在分析Win11主机和WSL2之间组播互通问题的过程中(详见《WSL2和multicast》),意外发现,Vmware虚拟机桥接到Windows无线网卡后,Windows主机也无法接收Vmware虚拟机发送的组播包,反之则没有问题。这是由于Vmware处理桥接模式下的包发送过于简单粗暴,直接将主机桥接网卡发送方向的数据包同步注入到该网卡的接收方向。在虚拟机桥接到主机无线网卡的情形下,接收方向注入的数据包也使用二层nat转换后的主机无线网卡MAC作为源MAC。Vmware虚拟机发出的组播包到达主机后分为两路,一路继续向外发送,另一路注入到无线网卡接收方向,Windows内核检测到以自身无线网卡MAC名义发出的组播包同时出现在发送和接收方向,误以为产生了二层环路,主动丢弃了接收方向的组播包,导致Windows无法接收Vmware虚拟机发来的组播包。Windows主机发出的组播包同样分为两路(实际上还有一路发往loopback),注入到无线网卡接收方向的组播包也因同样的原因被Windows丢弃,但并不影响Vmware虚拟机接收该组播包,也不影响Windows主机通过loopback自发自收该组播包。
Windows主机无法接收Vmware虚拟机发送的组播包与无法接收WSL2(mirrored)发送的组播包有着本质的区别,前者是组播包已到主机无线网卡接收方向,并能被主机抓包,但后续被Windows内核丢包;后者纯粹是路由问题,不涉及桥接或无线网卡,组播包无法发送到主机接收方向,主机上也就根本谈不上抓包一说。显然无法使用后者改变组播包路由的思路来解决前者面临的问题。
可通过引入Windows无线网桥来解决这一问题,让Vmware虚拟机桥接到Windows无线网桥,对于Vmware来说,无线桥接变成了有线桥接,由无线网桥负责二层nat转换。Vmware虚拟机发出的组播包被注入到无线网桥接收方向时,其源MAC仍是虚拟机网卡MAC而非主机无线网卡MAC,因而能被Windows主机顺利接收。
当Vmware虚拟机为Linux时,有一种更巧秒的办法可以解决前述问题,从而无需借助Windows无线网桥。在外部网络或Windows主机上跑一个IGMP查询器,同时在Linux虚拟机上执行如下四条命令后,就一切OK,Windows主机也能顺利接收Vmware虚拟机发来的组播包。
sudo ebtables -t nat -A PREROUTING -p ipv4 --ip-proto igmp --ip-dst 224.0.0.1 -j DROP
sudo ebtables -A OUTPUT -p ipv4 --ip-proto igmp --ip-dst 224.0.0.1 -j DROP
sudo bash -c "echo 1 > /sys/class/net/br0/bridge/multicast_querier"
sudo bash -c "echo 1 > /sys/class/net/ens192/brport/multicast_to_unicast"
该解决思路来自于本人疫情期间关于组播学习的一些心得,第一条命令不让外部网络或主机发来的查询报文被Linux网桥IGMP snooping处理,阻止虚拟机外出网卡成为router port。此处需注意不能使用filter/INPUT来DROP,因为其执行时点要晚于网桥IGMP snooping。第二条命令可防止虚拟机网桥自带IGMP查询器影响外部网络上的IGMP查询器。
后两条命令用于启用Linux虚拟机网桥br0外出网卡ens192的mcast_to_unicast功能(同样适用于有线网络,只要该端口不是router port),虚拟机网桥驱动将发给主机的组播包目标MAC转换成单播MAC(主机无线网卡MAC),就不会被Windows内核误以为二层组播环路而丢包,并顺利接收。
该思路的关键是外部网络上要有IGMP查询器,或在Windows主机跑一个IGMP查询器,在外发IGMP查询报文时也会发给自己一份。主机接收到查询报文后,持续向外发送IGMP report,Vmware桥接负责同步注入到Linux虚拟机,确保虚拟机网桥维护的主机网卡MAC长期有效,持续为mcast_to_unicast提供单播MAC。此处主机为何不能直接利用虚拟机上的IGMP查询器,原因仍在于虚拟机桥接无线网卡时发出的IGMP查询报文不能被Windows主机接收,因此VMware桥接也就无法主动向Linux虚拟机注入IGMP report。而外部网络或主机上的IGMP查询器,可触发VMware桥接顺便向Linux虚拟机定期注入IGMP report。
《WSL2和multicast》提到,WSL2桥接主机无线网卡,如果无线AP启用IGMP snooping功能或者外部网络上有IGMP查询器,由于Windows无线网桥不支持mcast_to_unicast逆转换,因此和无线AP的mcast_to_unicast功能发生冲突,导致WSL2(bridged)无法接收外来组播包。Vmware虚拟机(Linux)桥接主机无线网卡也不支持mcast_to_unicast逆转换,WSL2可以采用mirrored方式解决,Vmware虚拟机的类似问题又该如何解决呢?先透露一下答案,同时使用Windows无线网桥和Linux的bridge/ebtables命令。
既然Windows无线网桥不支持mcast_to_unicast逆转换,那Vmware虚拟机引入Windows无线网桥的意义又何在呢?虚拟机桥接无线网卡,无论是Vmware,或者Windows网桥,都需要提供二层nat转换功能,虚拟机数据包外出时,负责将数据包源MAC转换为主机无线网卡MAC,同时维护虚拟机源IP和主机无线网卡MAC之间多对一的映射关系。外来数据包到达主机无线网卡时,如数据包目标MAC为广播/组播,就直接传给虚拟机。如数据包目标MAC为主机无线网卡MAC,则根据目标IP去匹配前述映射关系,如匹配成功就将目标MAC转换为虚拟机MAC,然后传给虚拟机。当外来单播数据包目标IP为未知IP时,必然无法匹配映射关系(目标MAC为主机无线网卡MAC的unicast组播包显然也符合这一情形)。对于这些匹配失败的外来数据包,Vmware和Windows网桥各自的二层nat转换处理机制并不相同。
VMware虚拟机桥接主机无线网卡时,Vmware的二层nat转换提供了额外的安全防护,不会将前述匹配失败的外来数据包传给虚拟机。而改为桥接Windows无线网桥后,由无线网桥负责二层nat转换,但其功能相对简单,会把前述匹配失败的外来数据包原封不动传给Vmware。对于Vmware来说,无线桥接变成了有线桥接,不再需要二层nat转换,因此也是照单全收后如数传给虚拟机,完全由虚拟机去DROP不需要的数据包。
虚拟机桥接无线网桥后,来自无线AP的unicast组播包能够到达虚拟机,但因目标MAC为主机无线网卡MAC,和虚拟机MAC不一致,包类型被标记为PACKET_OTHERHOST,后续被虚拟机三层DROP,导致虚拟机仍然无法接收外来组播包。这时就轮到bridge/etables出场了,在虚拟机上执行如下两条命令后,也一切OK,不再受无线AP启用mcast_to_unicast影响,虚拟机能顺利接收外来组播包。
sudo ebtables -t nat -A PREROUTING -p ipv4 --ip-proto igmp --ip-dst 224.0.0.1 -j redirect
sudo ebtables -t nat -A PREROUTING -p ipv4 --ip-proto udp --ip-dst 224.0.0.0/4 -j redirect
这两条命令就是将外来的unicast组播包目标MAC从主机网卡MAC修改为Linux网桥MAC,同时修改包类型为PACKET_HOST,使之能被虚拟机三层进行常规处理(详见《Linux二层包类型对网络功能的影响分析》之二"包类型对桥的影响")。第一条命令允许虚拟机接收外部IGMP查询器发来的IGMP查询报文,后续虚拟机就能向外发送IGMP report,外来组播数据包就不会受到IGMP snooping影响,能够发往虚拟机。第二条命令允许虚拟机接收外来组播数据包,并将其交给上层组播接收程序。
在《WSL2和multicast》还提到,当Vmware虚拟机桥接的主机无线网卡固件具有multicast filter特性时,Vmware本身能使主机无线网卡multicast过滤功能失效,解除了主机无线网卡拦截外部组播包的隐患。改为桥接Windows无线网桥后,这一隐性福利消失了。但由于无线AP目前大都支持mcast_to_unicast,外来组播包到达主机无线网卡时,已变为unicast组播包,不会被主机无线网卡拦截。外部网络上的IGMP查询器能使Vmware虚拟机定期发出IGMP report,让mcast_to_unicast持续保持激活,便可对冲掉主机无线网卡的multicast filter特性,同样可以解除掉主机无线网卡拦截外部组播包的隐患。
最后顺便补充一下,对于Vmware虚拟机桥接无线网桥或无线网卡的情形,外来数据包到达主机无线网卡时,其目标MAC要么是广播/组播,要么就是主机无线网卡MAC。而且由于ARP协议在默默起作用,外来数据包目标IP要么也是广播/组播,要么就是主机IP或虚拟机IP,理论上不可能出现未知IP(不包括unicast组播包这种特殊情况)。要验证二层nat转换对未知IP的处理机制,可以手工修改虚拟机IP,并用iptables阻止外出的IGMP/UDP/TCP数据包,然后在外部设备上将该IP静态映射到主机无线网卡MAC,或者在主机上将该IP静态映射到虚拟机MAC。如虚拟机不发送Gratuitous ARP(Linux默认不发送),除非虚拟机先ping外部设备或主机,否则外部设备或主机永远无法ping通虚拟机修改后的IP。如虚拟机桥接无线网桥,虚拟机上能抓到目标MAC为主机无线网卡MAC的外来ping包,在组播接收程序初始发出的IGMP report超时前,还能抓到目标MAC为主机无线网卡MAC的外来unicast组播包。如虚拟机直接桥接无线网卡,由于Vmware二层nat转换额外提供的安全防护机制,虚拟机上根本抓不到上述包。这一区别,也正是Vmware虚拟机需要引入Windows无线网桥的意义所在。
然而本文解决方案却无法适用于WSL2(bridged)和桥接无线网卡的Hyper-v虚拟机,尽管这两者本来就必须使用Windows无线网桥。这是由于VMware采用的是Hub技术,而WSL2桥接所依赖的Hyper-v使用了Switch技术。目标MAC为主机无线网卡MAC的外来unicast组播包,直接被Hyper-v交换机转发到了主机vEthernet网卡,根本到不了WSL2(bridged)和Hyper-v虚拟机,自然也就无法像Vmware那样在虚拟机内部做进一步处理了。