ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Linux二层包类型对网络功能的影响分析

2026/8/9 17:06:29 拓冰建站 浏览量
Linux二层包类型对网络功能的影响分析 shixudong163.comLinux网络功能强大可用作网桥和路由器网桥用于转发目标MAC非本机的二层包路由用于转发目标MAC为本机、目标IP非本机的三层包。根据Linux网络相关源码分析二层包类型会对数据包的二、三层接收和转发产生一定影响特此记录以备今后随时查询。Linux网卡接收数据包时网卡驱动调用eth_type_trans对数据包进行预处理该函数通过比较目标MAC地址判断二层包类型并进行标记PACKET_BROADCAST二层广播地址、PACKET_MULTICAST二层多播地址、PACKET_OTHERHOST目标MAC非本网卡MAC、PACKET_HOST目标MAC为本网卡MAC。二层包类型后续可通过网桥驱动自动或者ebtables命令手动进行间接修改数据包到达三层ip_rcv此处以IP为例处理时首先丢弃所有PACKET_OTHERHOST包如数据包还需要进入三层转发环节在ip_forward处理时又丢弃所有非PACKET_HOST包。下面依据上述机制展开进一步分析一、包类型对网卡混杂模式的影响根据网卡工作机制如果网卡没有开启混杂模式网卡固件不允许收取目标MAC为非本网卡MAC的数据包直接将其DROP压根不会出现包类型为PACKET_OTHERHOST的数据包。只有当网卡开启混杂模式后内核才能接收目标MAC为非本网卡MAC的数据包并将其包类型标记为PACKET_OTHERHOST。网桥其实就是利用了这一原理将加入网桥的所有物理网卡开启混杂模式内核通过网桥驱动在二层转发PACKET_OTHERHOST包。关于网卡混杂模式容易引起误解的是网卡开启混杂模式后Linux是否能够接收并处理目标MAC非本机、但目标IP地址为本机的数据包如前所述由于IP层直接丢弃目标MAC非本机的PACKET_OTHERHOST包故此类数据包并不能被linux三层处理而在使用网桥的情况下目标MAC非本机的PACKET_OTHERHOST包早在二层就被网桥转发出去了。除非抓包时网桥开启了混杂模式否则PACKET_OTHERHOST包压根到不了三层所以如在网桥上用-p参数non-promiscuous mode执行tcpdump的话根本抓不到这些PACKET_OTHERHOST包。基于网桥这一特点在主机配置了bridge的情况下Vmware和VirtualBox虚拟机在桥接外部网络时应该选择桥接物理网卡而非网桥其目的就是为了避免网桥开启混杂模式不让网桥再往三层传递这些最终仍会被三层DROP的PACKET_OTHERHOST包。常规情况下混杂模式主要用于网桥物理网卡以及抓包工具然而凡事总有例外试举两例1、采用LPF的DHCP包不通过ip_rcv收包特定情形下开启混杂模式后的PACKET_OTHERHOST包能被DHCP处理详见《树莓派bond问题排查与分析》。2、在桥上启用了br_netfilter模块在二层调用iptables实现DNAT如果DNAT后数据包目的地与初始进入包都位于网桥同一物理端口该包在二层转发时被br_forward丢弃。但若该包DNAT前本来目标IP就指向桥IP的话因其包类型为PACKET_HOST就无需像《ebtables与iptables之间的交互技巧》一文那样既要启用桥对应物理网卡hairpin_mode参数还要额外考虑上联交换机的MAC漂移而只需要将网桥不是物理网卡网桥物理网卡总是处于混杂模式开启混杂模式即可当然网桥上还需要添加hairpin NAT必备的SNAT规则。网桥驱动将DNAT后的数据包移交本机三层ip_rcv不会丢弃该包而是通过ip_forward转发并进行SNAT处理后到达DNAT目标。此处由于是在三层进行SNAT网桥最终发往DNAT目标的数据包除了其源IP 被修改为桥IP外源MAC也被同步修改为桥MAC所以既无需担忧MAC漂移也不必启用hairpin_mode。更新内核6.9起对网桥混杂模式收包做了较大的调整针对网桥开启混杂模式后才能收到的数据包在移交三层前将清除其连接跟踪信息前述网桥在混杂模式下收到的PACKET_HOST包经过该调整后PREROUTING链DNAT规则nf_conntrack_in留下的连接跟踪痕迹被清除相当于中途跳出了连接跟踪机制。尽管该数据包已顺利执行DNAT规则目标IP也被更改为DNAT目标并且还能通过ip_forward转发但后续再也无法匹配POSTROUTING链SNAT规则。该数据包虽然最终还能到达DNAT目标但由于失去了SNAT的加持响应包再也无法回到网桥端到端全链路无法闭环导致hairpin NAT功能失效。深入理解了网卡混杂模式和包类型的概念有助于判断和解决一些网卡层面的疑难杂症。在四大虚拟机环境中KVM、Hyper-v和Vmware都支持在虚拟机运行时更改linux客户机网卡的MAC地址但目前VirtualBox环境中在Linux客户机更改网卡MAC后会导致网络不通此处暂不考虑桥接主机无线网卡导致二层NAT失效这一情形这是因为在guest里修改MAC时在内核层面虽然认定已修改成功但由于VirtualBox的某种限制或瑕疵guest网卡硬件层面的MAC并没有被真正修改仍保持为修改前的MAC即GUI界面的MACAddress设置值。在guest里修改MAC后正常情况下外部发往guest的数据包其目标MAC默认为修改后的MAC与guest网卡修改前MAC不符直接在网卡硬件层面DROPARP查询为广播包能被guest处理所以外部获取的是guest修改后的MAC如在外部机器设置guest的静态ARP指向修改前MAC以该MAC为目标MAC的数据包到达guest后虽然在guest网卡物理层面MAC相符不再被DROP但由于内核驱动层面网卡MAC已更改故内核认定两者不符导致二层包类型标记为PACKET_OTHERHOST从而在三层被DROP。解决方案有二核心思路都是开启网卡混杂模式一是guest里修改网卡MAC的同时将该网卡开启混杂模式guest网卡收到目标MAC为修改后的MAC时因网卡处于混杂模式能被网卡硬件接收并且由于目标MAC和修改后MAC一致二层包类型被标记为PACKET_HOST能被三层正常处理网络通讯即可恢复正常GUI界面网卡混杂模式还需设为全部允许。另一个方案则更为简洁一些即利用linux网桥的特性网卡加入网桥后总是开启混杂模式此时可以随意更改网桥MAC详见下文包类型对桥的影响分析或网卡MAC。由虚拟机动态更改MAC衍生出来的另一个情形即在虚拟机里测试bond功能active-backup模式一般都强调需设置fail_over_mac1也是为了避免出现网卡失效触发网卡切换导致虚拟机网卡硬件和内核层面MAC不一致的情形。当fail_over_mac1时只涉及bond更换MAC不涉及物理网卡更换MAC故不受影响。针对fail_over_mac0或2的情形就需要在虚拟机里将网卡开启混杂模式才能体验网卡切换效果。虽然除VirtualBox外Kvm、Vmware和hyper-v已不存在网卡硬件和内核层面MAC不一致的问题但Vmware不支持虚拟机网卡改为其他虚拟网卡在用的MAC导致Vmware虚拟机bond效果和VirtualBox一致而hyper-v则由于虚拟网卡不支持热更改MAC即网卡UP状态时更改MAC的特性fail_over_mac2时无法切换并且无法通过开启混杂模式解决只有Kvm虚拟机不会引发上述各种异常在active-backup模式下无需考虑fail_over_mac参数。经过前述分析、测试与验证对四大虚拟机网络层面的相关特性有了一定程度了解顺便记录于此与本文主题关系不大。1、Virtualbox不包括内置NAT与Vmware在同一网段采用Hub技术虚拟网卡只需开通混杂模式就能接收目标MAC非本网卡MAC的包而Hyper-v与KVM则采用了Switch技术网卡开启混杂模式无意义但由于不存在Virtualbox的瑕疵故能够支持虚拟机动态更改MAC其中Hyper-v需要额外开启MAC地址欺骗。2、Virtualbox桥接无线网卡时二层nat转换有缺陷即使开启混杂模式后改变MAC也会导致虚拟机和外部网络不通详见Virtualbox配置Linux guest桥和修改网卡MACHyper-v与Vmware的二层nat转换则无此问题Hyper-v实质上不参与二层nat转换由Windows主机的无线网桥完成KVM桥接外部网络时直接采用linux网桥技术将虚拟机网卡加入主机网桥因此KVM桥接无线网卡时只要主机无线网卡能设法加入主机网桥压根没有二层nat转换的概念如主机无线网卡不能加入主机网桥就无法桥接主机无线网卡。3、KVM、Vmware和Virtualbox的虚拟机网卡支持热更改MACHyper-v则不支持需要down后更改然后再up。4、WSL2采用了Hyper-v技术但不支持开启MAC地址欺骗所以尽管WSL2已支持桥接外部网络networkingModebridged但虚拟机中更改MAC后将导致网络不通也无法通过开启混杂模式思路解决如前所述Hyper-v采用Switch技术开启混杂模式无意义而且由于WSL2官方内核对ebtables支持力度不够从而也无法让其他虚拟机通过再桥接WSL2连通外部网络。二、包类型对桥的影响Linux网桥由多个物理网卡组成网桥和物理网卡都有各自MAC大多数情况下桥MAC和物理网卡MAC并不一致。当两者不一致时由于物理网卡不参与ARP响应导致该物理网卡收包的目标MAC要么是桥MAC要么是其他机器MAC。在该情形下物理网卡永远收不到目标MAC与自身MAC一致的包因此物理网卡驱动在调用eth_type_trans时总是将包类型标记为PACKET_OTHERHOST但因物理网卡处于混杂模式包可以被物理网卡接收。后续网桥驱动针对PACKET_OTHERHOST包分两种情形处理1、目标MAC和桥MAC不一致的包直接由网桥二层转发2、目标MAC和桥MAC一致的包修改其包类型为PACKET_HOST并提交三层处理。实际上后者主要指的就是目标IP为桥IP的数据包通过ARP保证了目标MAC和桥MAC总是一致。Linux的ebtables在下述情形下可将包类型修改为PACKET_HOST以便数据包后续能被三层接收和处理1、BROUTING实现dnat且dnat后目标MAC为物理网卡MAC。2、PREROUTING实现dnat且dnat后目标MAC为桥MAC。3、BROUTING和PREROUTING实现redirect。此处特别需要提醒的是如BROUTING直接将DROP作为-j的目标时其作用仅仅是强制数据包跳过二层桥直接提交三层处理并不会去修改包类型。如前所述大多数情形下数据包目标MAC与收包物理网卡MAC不一致包类型为PACKET_OTHERHOST导致实际上无法被三层处理。所以要实现BROUTING强制三层处理的作用有效用法应该是BROUTING -j redirect --redirect-target DROP先修改包类型为PACKET_HOST再强制移交三层处理。三、包类型对ip_forward的影响如前所述三层ip_forward在转发数据包时首先丢弃所有非PACKET_HOST包。鉴于PACKET_OTHERHOST包先前在ip_rcv时已被丢弃实际上ip_forward此处丢弃的主要是多播地址包、本地广播包和本地网段定向广播包跨网段定向广播包通过路由寻址对应的目标MAC就是Linux路由器本身所以包类型为PACKET_HOST不受ip_forward丢包机制影响。一般情形下路由器不用处理此类本地广播包仅当特定情形下需要使用iptables将广播IP转换为单播IP时才需要考虑ip_forward丢包机制影响此时可借助网桥和ebtables命令先将PACKET_BROADCAST修改为PACKET_HOSTiptables的DNAT不修改包类型然后便可交由iptables和ip_forward完成后续处理详见《iptables DNAT实现broadcast与unicast之间相互映射》。在考虑包类型对ip_forward的影响时存在如下情形即Vmware和VirtualBox虚拟机桥接无线网卡外部发往guest的数据包其目标MAC和主机无线网卡MAC一致因此包类型为PACKET_HOST该包除了被虚拟机处理外也能被主机三层再次处理通常是再次路由转发到虚拟机所以此种情形下一般建议不要开启主机的ip_forward功能以免产生大量重复包。此处尤其需要提醒的是VMware虚拟机产生的重复包更为严重这是由于主机与VMware虚拟机的交互也使用二层nat转换后的MAC即主机无线网卡MAC导致路由转发到虚拟机的数据包仍能再次被主机三层接收和处理形成了环路直到ttl为1。还有一种情形恰恰相反如前所述使用VirtualBox虚拟机桥接无线网卡时存在二层nat转换缺陷导致多个虚拟机之间无法通过级联桥接连通外部网络。此时可在直接桥接无线网卡的虚拟机上借助ebtables对其他级联虚拟机的MAC地址进行snat使之和虚拟机GUI界面的MACAddress保持一致以规避二层nat转换缺陷详见《ebtables与iptables之间的交互技巧》。然而由于ebtables缺乏连接跟踪机制对于外部方向进来的数据包还需针对每个内部IP添加一条相应的dnat规则稍有不便。考虑到数据包包括arp包通过snat出去后外部设备看到的其他虚拟机对应的MAC地址全部是桥接无线网卡虚拟机的桥MAC因此外部进来的数据包其包类型自然也由桥驱动更改为PACKET_HOST。基于此偷懒的做法就是在桥接无线网卡的虚拟机上开启ip_forward外部进来的数据包全部交由三层去处理或路由就无需再使用ebtables添加多条dnat规则了通过桥接级联的数据包最终的流向则是二层出去、三层回来。