单 VLAN 的 TAP 网桥:挂接子接口
物理上行链路上的 TAP 网桥会把无标记帧送进 trunk。改为把 VLAN 子接口桥接进去,并让地址随成员关系一起迁移。
在引入 VLAN 之前能访问局域网、之后却失联的 TAP 客户端,通常其网桥里仍然挂着错误的接口。帧转发不会添加 VLAN 标记,因此发往物理上联的无标记客户端帧到达 trunk 端口时仍无标记,要么被丢弃,要么落进本征 VLAN。子接口存在于主机的某个位置,并不会改变网桥的成员列表。首先要破除的误解正是这一点:标记由拥有它的接口施加,而不是主机上有这么一个接口就自动生效。
一次 VLAN 扩展意味着一个 2 层域,网桥要接入这个域,而不是承载所有 VLAN 的 trunk。
标记没出现,因为你把 trunk 桥接了
以一条承载 VLAN 120 的 Linux 上联 eno1 接到受管交换机为例。单 VLAN 可行的设计是把 tap_vpn 桥接到 br_vpn,让 br_vpn 包含 eno1.120,而不是 eno1。VLAN 子接口在出方向打标记、入方向剥标记,因此网桥只会看到该 VLAN 的无标记帧。反过来把物理接口放进网桥,同样的帧会以无标记状态从 trunk 端口发出,这并非你所计划的结果。
关掉 VLAN 过滤再桥接 trunk 并不是通向同一结果的捷径。它把那条链路上的所有 VLAN 都交给网桥,包括客户端根本不该看到的那些。
两种正当设计,一个标记所有者
VLAN 感知网桥是另一种合法做法:trunk 进入网桥端口,按端口的成员关系、PVID 和带标记出方向设置决定哪些 VLAN 通过。此时标记归网桥所有,再在它下面加一个 VLAN 子接口,等于为同一件事装上了第二个所有者。两种设计都能用;把两者拼在一起则不行。在改动任何成员列表之前,先确定由哪个对象施加标记。
交换机端口必须与你选定的设计一致。以无标记方式承载该 VLAN 的 access 端口对应物理接口作为接入点,而 trunk 端口对应带标记的子接口。把子接口加在并不匹配的 access 端口上,什么也修不好。
地址随成员关系一起迁移
在子接口方案里,被桥接子网的主机地址 应放在 br_vpn 上,而不是它原先可能待过的从属 VLAN 端口。把地址留在端口上,表面上可能能用,随后却会出现怪异行为,因为网桥在 2 层转发,而地址挂在某个成员上。要把它作为成员关系变更的一部分去迁移,而不是当成一次单独的试验。
迁移地址可能切断管理通道。先建立一条独立的恢复路径,通过发行版自带的网络管理器保存现有配置,并避免使用会在下次升级后与之冲突的竞争性启动脚本。
客户端地址规划同样需要谨慎。桥接 VPN 把客户端放进扩展子网,因此地址池不能与其他租约或静态分配重叠,由 DHCP 服务的方案必须是局域网真正预期的那一套。2 层通路能跑通,并不说明地址没有重复。
先核对成员关系,再怀疑路由
读当前状态,而不是设想中的状态:ip -d link show dev eno1.120 会打印 VLAN id 及其父接口,ip link show master br_vpn 列出网桥成员,bridge vlan show 报告按端口的成员关系与出方向处理方式。在子接口方案里,确认 TAP 设备和 VLAN 设备就是成员。在 VLAN 感知网桥里,检查端口策略本身,因为网桥存在并不能证明它允许什么。
然后拿一个被允许的客户端去访问该 VLAN 中的服务,同时记住 ARP、防火墙策略和回程路径是与成员关系彼此独立的问题。如果要抓包,注意硬件卸载可能改变 VLAN 标记在追踪中出现的位置。也要如实界定范围:被路由的 TUN 客户端不会因任何网桥改动而成为 VLAN 成员,客户端之间的流量也不能替代主机到 VLAN 的接入。