
搞网络的人应该都遇到过这种场景服务器上要同时跑好几个业务网段或者一台物理机要充当虚拟化宿主、网关而物理网口就一两个。这时候最干净的做法就是把交换机上的Access口和Trunk口语义搬到Linux网卡上让服务器直接参与VLAN隔离。我自己在做多租户隔离、机房网络规划、甚至调试家用IPTV组播的时候都反复用这两套工具iproute2和Open vSwitch。这俩东西能覆盖绝大多数网卡级VLAN配置需求一个轻量原生一个功能全面今天把它们的用法和踩过的坑一次说清楚。1. 先搞清楚Access与Trunk在Linux里到底对应什么1.1 802.1Q标签的本质与端口角色VLAN隔离靠的是给以太网帧打上一个4字节的802.1Q标签里面有12位的VLAN ID和3位优先级。交换机端口一看这个标签就知道这个帧属于哪个虚拟网络。Access口和Trunk口的区别说白了就一句话Access口发出去的帧不带标签进来的帧打上配置好的PVID标签Trunk口转发时保留标签让多个VLAN共用一条物理链路。这个语义用到Linux服务器上就很有意思。服务器网卡本身不理解VLAN它只认识普通的以太网帧。Linux内核的网络栈用VLAN子接口的方式模拟出多个逻辑网卡每个子接口绑定一个VLAN ID子接口收到的数据帧会自动剥离标签发给上层协议栈发出的帧会自动打上对应ID的标签。1.2 在Linux里模拟Access口和Trunk口Linux模拟Access口的方式很简单创建一个VLAN子接口并配好IP这个子接口对外表现就像一个独立的网卡走的流量天然带对应VLAN标签。这里有个关键认知——Linux里的VLAN子接口本质上更像交换机的Trunk语义因为它不剥离标记就交给协议栈。但实际使用中我们把它当作Access口的客户端来用对接交换机的Trunk口让某个特定VLAN的流量进入服务器。换句话说服务器侧的口是Access角色交换机的口是Trunk角色两边配合才能打通。Trunk口在Linux里通常出现在两种场景一是网卡上创建多个VLAN子接口每个接一个业务网段二是拿Linux bridge做二层交换把多个物理口或虚拟口放进同一个桥里再配置vlan_filtering做真正的Trunk转发。第二种场景更接近硬交换机的行为也是Open vSwitch最擅长的地方。1.3 iproute2和Open vSwitch怎么选我的选择标准很直接只做几个IP层访问场景比如服务器要上联到两个VLAN分别走业务和管理网段直接用iproute2系统自带零依赖性能也最好。要模拟复杂的二层交换、做虚拟机的虚拟网络、需要ACL和QoS控制或者要在同一物理口上同时做Access和Trunk混合配置直接上Open vSwitch。OVS的数据路径在内核里性能不会差太多但配置灵活度完全是另一个级别。提示不管选哪种方案都先确认网卡驱动支持VLAN硬件卸载。现代网卡基本都支持但有些老旧驱动开了卸载反而出问题遇到诡异不通的可以先关掉测试。2. 用iproute2快速配置Access口最常见也最容易被坑2.1 一条命令创建VLAN子接口iproute2配置VLAN的核心命令是ip link add我日常使用的基本模板长这样# 加载8021q内核模块 modprobe 8021q # 在物理网卡eth0上创建VLAN 10子接口 ip link add link eth0 name eth0.10 type vlan id 10 # 启用子接口 ip link set eth0.10 up # 分配IP ip addr add 192.168.10.2/24 dev eth0.10 # 确认配置 ip -d link show eth0.10 ip addr show eth0.10这里的eth0.10只是命名习惯内核看的是type vlan id 10这个属性名字叫vlan10、eth0-vlan10都无所谓。我见过有人用ip link set改子接口的mac地址结果和物理口mac不一致导致交换机上MAC表项漂移这种自找麻烦的事儿不建议干。2.2 用子接口对接交换机Trunk口的完整例子假设一台服务器有两个VLAN要跑VLAN 10是业务网段VLAN 20是管理网段。物理口eth0接交换机Trunk口管理VLAN的PVID是20业务VLAN的PVID是10。服务器侧的做法是modprobe 8021q ip link add link eth0 name eth0.10 type vlan id 10 ip link add link eth0 name eth0.20 type vlan id 20 ip link set eth0.10 up ip link set eth0.20 up ip addr add 192.168.10.100/24 dev eth0.10 ip addr add 192.168.20.100/24 dev eth0.20这时候服务器和交换机之间的链路是Trunk但服务器逻辑上就是两个独立网卡各走各的VLAN。要注意的是物理口eth0本身不要配IP如果配了IP默认路由可能会从物理口出去VLAN流量反而走不对。正确做法是让默认路由指向其中一个子接口的网关。2.3 一个典型坑rp_filter反向路径过滤导致VLAN不通我刚用VLAN子接口的时候踩过一个很隐蔽的坑子接口都能起来IP也配好了但是ping不通网关。排查半天发现是麒麟和CentOS默认开了rp_filter反向路径过滤它要求入站报文的源地址能从收到报文的接口返回去多网卡多路由环境下判断会出错直接丢包。解决方式要么关掉要么改成松散模式sysctl -w net.ipv4.conf.all.rp_filter0 sysctl -w net.ipv4.conf.default.rp_filter0 sysctl -w net.ipv4.conf.eth0.rp_filter0如果想永久生效写到 /etc/sysctl.conf 里。这个坑尤其在一台物理机同时接入多个VLAN且有默认路由的场景高发遇到接口全起来但就是不通的问题第一反应就查rp_filter。2.4 配置持久化从命令行到重启不丢命令行配好只是临时状态重启就没了。我在Ubuntu上用netplan在CentOS上用ifcfg在纯systemd环境用networkd三种都放出来参考。netplan的写法/etc/netplan/01-netcfg.yamlnetwork: version: 2 ethernets: eth0: dhcp4: no vlans: eth0.10: id: 10 link: eth0 addresses: [192.168.10.100/24] routes: - to: default via: 192.168.10.1CentOS的ifcfg写法/etc/sysconfig/network-scripts/ifcfg-eth0.10DEVICEeth0.10 BOOTPROTOnone ONBOOTyes VLANyes IPADDR192.168.10.100 PREFIX24 GATEWAY192.168.10.1改完分别执行netplan apply、systemctl restart network或nmcli con reload。我的建议是尽量少用NetworkManager管VLAN子接口容易和手工配置打架服务器上直接关掉NM用纯networkd或脚本管理更省心。3. iproute2的进阶玩法在Linux Bridge上做真正的Trunk3.1 配置Linux Bridge的VLAN过滤只有VLAN子接口还不够当服务器要充当一个小型二层交换机比如给KVM虚拟机提供VLAN网络就需要把物理口、虚拟机的虚拟网卡都塞进同一个Linux Bridge然后打开vlan_filtering。这个模式下bridge端口就像交换机端口一样可以分别设置AccessPVID和Trunk允许哪些VLAN通过。先创建桥并开启VLAN过滤ip link add name br0 type bridge ip link set br0 type bridge vlan_filtering 1 ip link set br0 up # 把物理口和虚拟口加进桥 ip link set eth0 master br0 ip link set tap0 master br0 ip link set eth0 up ip link set tap0 up默认情况下所有端口都会视为Trunk且允许所有VLAN。要模拟真实交换机就需要用bridge vlan命令去收敛端口行为。3.2 用bridge vlan命令模拟Access口和Trunk口经典的场景是这样的物理口eth0作为上联口只允许VLAN 10和VLAN 20的标签帧通过连接虚拟机的tap0口作为Access口只属于VLAN 10。# eth0口设置TrunkPVID为10允许VLAN 10、20 bridge vlan add dev eth0 vid 10 pvid untagged bridge vlan add dev eth0 vid 20 # tap0口设置AccessPVID为10只允许VLAN 10 bridge vlan add dev tap0 vid 10 pvid untagged # 查看端口VLAN表 bridge vlan show注意untrunk这个关键字容易写错正确的是untagged它表示这个VLAN的帧从该端口出去时不带标签。Access口的本质就是PVID untagged 只允许单个VLANTrunk口的本质就是允许多个VLAN 除PVID外都打标签。理解这个映射关系配置就不会懵。3.3 桥接模式下虚拟机怎么接VLAN给虚拟机用这种方案有个大好处虚拟机里的网卡不需要理解VLAN直接配IP就能通因为tap0口是Access口虚拟机的网卡发的普通帧进入桥后自动被关联到VLAN 10。如果想让虚拟机直接带Trunk出去那就不要给tap0口配PVID而是把虚拟机里的网卡做成VLAN子接口让tagged帧直接走tap0端口。一个特别值得留意的点Linux Bridge的vlan_filtering在转发逻辑上和硬件交换机有细微差别有些场景下IGMP snooping行为也跟预期不一致。如果做组播业务比如IPTV类场景最好实测一下组播流量能不能正常转发我遇到过MLD snooping默认开启导致的组播不通问题关掉才恢复。4. Open vSwitch把物理口玩成真正的交换机端口4.1 OVS的基本组网模型Open vSwitch的灵魂在于它把端口配置从内核数据结构里解放出来全部通过ovsdb数据库管理也就是说你可以随时修改端口类型、VLAN标签、Trunk列表不用重新加载内核模块也不用重启网络服务。在物理机上用OVS通常是把物理网卡加进OVS桥再把虚拟机网卡或容器虚拟网卡也加进去通过OVS端口配置实现隔离。先装好OVS并创建一个桥systemctl enable --now openvswitch-switch ovs-vsctl add-br ovs0 ovs-vsctl add-port ovs0 eth0 ovs-vsctl add-port ovs0 tap0 ovs-vsctl show创建完桥以后ovs0就是一个虚拟交换机物理口eth0和虚拟口tap0都是它的端口。4.2 OVS里配置Access口tag命令一学就会OVS配置Access口的思路比Linux Bridge直白得多所谓Access口就是给端口指定一个tag该端口收到的无标签帧自动归入这个VLAN发出的帧剥掉VLAN标签。# 让tap0成为Access口属于VLAN 10 ovs-vsctl set port tap0 tag10 # 让tap1属于VLAN 20 ovs-vsctl set port tap1 tag20这里注意如果端口被设置了tag默认就只允许这一个VLAN通行其他VLAN的帧不会从该端口出去。这正好对应交换机Access口的单VLAN语义。同样物理口eth0如果不设tag它就是一个Trunk口跑所有VLAN的标签帧。4.3 OVS里配置Trunk口trunks参数控制放行列表用OVS配置Trunk口就更灵活了因为可以精确控制放行哪些VLAN# eth0作为Trunk口只放行VLAN 10、20、30 ovs-vsctl set port eth0 trunks[10,20,30] # 查看端口配置 ovs-vsctl list port eth0 ovs-vsctl get port eth0 trunks如果希望某个Trunk口的PVID是10同时放行10、20、30三个VLAN就把tag和trunks组合起来ovs-vsctl set port eth0 tag10 trunks[10,20,30]这个配置的含义是从eth0进入的无标签帧归入VLAN 10三个VLAN的标签帧都允许通过只有VLAN 10的帧从eth0出去时不带标签其余带标签。这正好是交换机上native VLAN Trunk的典型模型。4.4 OVS和虚拟化平台联动Docker/QEMU接入VLAN我自己用得最多的场景是把OVS桥接给Docker容器和QEMU虚拟机。容器侧可以创建一个直接的虚拟网卡接进OVS然后在OVS里设置tag容器无需感知VLAN也可以把OVS端口做成Trunk让容器内部自己创建VLAN子接口。前者简单后者适合跑一些需要自己管理VLAN的网络设备模拟器。Docker接入OVS的简略流程是先用ip命令创建veth对一头放进容器网络命名空间另一头加进ovs0然后ovs-vsctl set port veth0 tag10。QEMU虚拟机则用tap设备接进OVStap0配tag10。配完以后虚拟机、容器、物理网络就在同一个VLAN平面里了彼此能通和外面的接入交换机也能正常对接。4.5 OVS的独门优势ACL与流量镜像如果只是配VLANLinux Bridge也能做我为什么还要用OVS因为OVS自带ACL通过流表实现能精细控制端口之间能不能互通。比如同一个VLAN 10里只允许虚拟机A访问虚拟机B禁止C访问BOVS流表几行就能搞定Linux Bridge做这个几乎不可能。另外OVS可以把某个端口的流量镜像到另一个端口调试抓包极其方便这个我们在后面的排查环节还会提到。5. 常见问题与排查VLAN配置不生效时我一般这么查5.1 从物理层到协议层的五步排查法VLAN配置完ping不通我有一套固定的排查顺序照着做基本能找到问题。第一步先确认链路层的协商状态ethtool eth0看一下有没有连上、速率对不对。 第二步确认VLAN子接口或OVS端口有没有正确upip link show和ovs-vsctl show都能看到。 第三步抓包看有没有VLAN标签这个最关键。在服务器上抓包tcpdump -i eth0 -e vlan 10 tcpdump -i eth0.10 -e在子接口上抓包时看到的是剥离标签后的原始帧在物理口上抓包时能看到带802.1Q标签的帧。如果物理口上能看到带标签的帧说明服务器发出去了如果对端没回应就把抓包放到交换机侧确认交换机是否真的放行了对应VLAN。 第四步检查本机路由表ip route看回包路由是否正确。 第五步检查防火墙和安全策略。5.2 常见问题速查表现象可能原因处理方式子接口起来了但ping不通网关rp_filter反向路径过滤sysctl关闭rp_filter物理口和子接口都能通但VLAN不通交换机口配置了Access收到带标签的帧交换机端口改成Trunk并放行对应VLAN重启后VLAN配置丢失配置没持久化用netplan/ifcfg/networkd写入持久化配置OVS端口配置了tag但虚拟机不通虚拟机网关配置错误或OVS流表冲突ovs-ofctl dump-flows检查流表双网卡服务器VLAN流量从错误网卡出去路由表策略路由缺失用ip rule或独立路由表分流硬件卸载导致乱序丢包网卡驱动VLAN卸载bugethtool -K eth0 rxvlan off txvlan off测试这些坑我基本都踩过一遍尤其是rp_filter和交换机口模式不匹配这两个占了日常VLAN问题的一半以上。5.3 OVS的流表排错手段OVS出问题光看端口配置还不够因为OVS真正转发依据是流表。有时候端口配置明明对着但流表里有更优先级的规则把流量丢了或改了动作表现就是VLAN流量不通。排查时我用两个命令# 查看完整流表 ovs-ofctl dump-flows ovs0 # 跟踪某个数据包的转发行为 ovs-appctl ofproto/trace ovs0 in_porttap0,dl_vlan10,dl_srcaa:bb:cc:dd:ee:ff,dl_dst00:11:22:33:44:55ovs-appctl ofproto/trace会把数据包从进端口开始逐条匹配流表并告诉你最终动作是什么是下发到控制器、丢弃、还是转发到某个端口。这个命令是OVS排错的定海神针比看日志高效太多。5.4 硬件卸载和高性能场景的注意事项跑高流量业务时VLAN的CPU消耗不能忽视。每一个带标签的帧都要经过内核的协议栈处理开启网卡的VLAN硬件卸载能把封装解封装下沉到网卡显著降低CPU占用。现代Intel i219、Mellanox CX系列都支持默认也开着。但要注意一旦给网卡配了VLAN子接口或者把网卡加进OVS驱动对VLAN卸载的支持可能出现兼容性问题。我遇到过一次魔改网卡开VLAN卸载后小包转发延迟暴增的案例关掉rxtx VLAN卸载立即恢复正常。主要是看业务类型来权衡。6. 从单一配置到网络域隔离VLAN和ACL怎么配合6.1 为什么VLAN划分和ACL策略要一起规划VLAN隔离解决的是二层广播域隔离问题不同VLAN之间默认不通这个天然隔离是网络安全的基石。但VLAN内部依旧是全通的如果同一个VLAN里有办公网、测试机、打印机混在一起不少安全风险依然存在。所以生产环境做网络域隔离标准套路是先用VLAN把业务切成独立广播域再在VLAN的边界或内部用ACL做精细化访问控制。我做的多租户隔离项目里每个租户一个VLAN租户内部再拆几个子VLAN区分Web、DB、管理最后在核心交换机上配ACL只放行Web网段访问DB的特定端口禁止租户管理网段访问外部。这套VLAN打底 ACL增强的组合无论用硬交换机还是OVS思路完全一致。6.2 OVS里的ACL配置把防火墙规则下沉到流表OVS的ACL本质就是流表规则。举个例子禁止VLAN 10里的主机访问VLAN 20里的数据库端口3306# 禁止VLAN 10到VLAN 20的3306端口 ovs-ofctl add-flow ovs0 priority100,dl_vlan10,dl_type0x0800,nw_proto6,tp_dst3306,actionsdrop规则生效的优先级是priority越大越优先普通转发规则优先级默认是0所以高优先级的drop规则会盖过转发规则。这种需求放在Linux Bridge里得靠iptableseBPF实现复杂度和性能损耗都大得多。6.3 华为交换机里Smart VLAN和Mux VLAN的坑既然热词里提到了Smart VLAN和Mux VLAN顺带说一句有些运营商接入网络喜欢把Smart VLAN一个业务VLAN叠加在一个承载VLAN里用在IPTV场景Mux VLAN则用来做隔离它的原理是一个主VLAN绑定多个从VLAN端口分Principal和Secondary角色。这类高级VLAN特性在Linux和OVS里没有直接对等的配置如果要在服务器侧模拟只能是老老实实打标签或者用OVS流表手动实现隔离逻辑不要硬套命令行。调试运营商IPTV组播时我习惯把那一路单独划一个VLAN子接口不要让它跟业务VLAN混在一起否则组播表项和PVID配置搅在一起极难排查。7. 我的几点体会和踩坑总结做服务器VLAN配置这些年我最大的体会是大部分问题不是命令不会敲而是对交换机端口的PVID、untagged语义理解不透。很多人分不清tag和untagged、Access和Trunk的边界导致交换机侧和服务器侧各配一半怎么都不通。只要把Access单个VLAN出去不带标签、Trunk多个VLAN看情况带标签这个核心逻辑刻在脑子里在Linux Bridge、OVS、硬件交换机上来回切换都不虚。踩过的坑里最值得提醒的是不要在物理口上配IP和VLAN子接口混用又加默认路由路由策略会乱成一团另外优先级队列和VLAN的CoS位是两回事做QoS时别搞混。最后分享一个小技巧新环境配置VLAN前先拿ip -d link、ovs-vsctl show、bridge vlan show三个命令把现网拓扑摸清楚再动手。VLAN配置这事儿看着简单但真出问题的时候最朴素的抓包和一步一步梳理端口角色比什么高级技巧都管用。