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

文章详细探讨了Linux系统中网卡混杂模式、包类型(PACKET_BROADCAST,PACKET_MULTICAST,PACKET_OTHERHOST,PACKET_HOST)在网络转发中的作用,以及它们如何影响网桥、ip_forward和虚拟机环境。混杂模式主要在嗅探和特殊网络配置中发挥作用,而包类型决定了数据包在二、三层的处理方式。在虚拟机场景中,如VirtualBox更改MAC地址可能导致网络不通,开启混杂模式或利用网桥特性可解决这个问题。文章还提到了不同虚拟化平台如KVM、VirtualBox、Hyper-v在网络层的差异和限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

shixudong@163.com

Linux网络功能强大,可用作网桥和路由器,网桥用于转发目标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层直接丢弃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,还有补救办法,即将网桥(不是物理网卡,网桥物理网卡总是处于混杂模式)开启混杂模式,网桥驱动会将DNAT后的数据包移交本机三层处理而不是丢弃包,后续能被ip_rcv接收并在三层进行转发。
深入理解了网卡混杂模式和包类型的概念,有助于判断和解决一些网卡层面的疑难杂症。
在四大虚拟机环境中,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不符,直接在网卡硬件层面DROP(ARP查询为广播包,能被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_mac=1,也是为了避免出现网卡失效触发网卡切换导致虚拟机网卡硬件和内核层面MAC不一致的情形。当fail_over_mac=1时只涉及bond更换MAC,不涉及物理网卡更换MAC,故不受影响。针对fail_over_mac=0或2的情形,就需要在虚拟机里将网卡开启混杂模式,才能体验网卡切换效果。虽然除VirtualBox外,Kvm、Vmware和hyper-v已不存在网卡硬件和内核层面MAC不一致的问题,但Vmware不支持虚拟机网卡改为其他虚拟网卡在用的MAC,导致Vmware虚拟机bond效果和VirtualBox一致;而hyper-v则由于虚拟网卡不支持热更改MAC(即网卡UP状态时更改MAC)的特性,fail_over_mac=2时无法切换并且无法通过开启混杂模式解决;只有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桥和修改网卡MAC);Hyper-v与Vmware的二层nat转换则无此问题(Hyper-v实质上不参与二层nat转换,由Windows主机的无线网桥完成);KVM桥接外部网络时,直接采用linux网桥技术,将虚拟机网卡加入主机网桥,因此KVM桥接无线网卡时,只要主机无线网卡能设法加入主机网桥,压根没有二层nat转换的概念,如主机无线网卡不能加入主机网桥,就无法桥接主机无线网卡。
3、KVM、Vmware和Virtualbox的虚拟机网卡支持热更改MAC;Hyper-v则不支持,需要down后更改,然后再up。
4、WSL2采用了Hyper-v技术但不支持开启MAC地址欺骗,所以尽管WSL2已支持桥接外部网络,但虚拟机中更改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_HOST(iptables的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规则了,通过桥接级联的数据包最终的流向则是二层出去、三层回来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值