linux 虚拟网卡之 macvlan
原理说明
通过Macvlan可以在一个网络接口上创建多个虚拟接口,这些虚拟接口有自己的MAC地址,可以配置 IP 进行通信。虚拟接口和父接口共享同一个广播域。
Macvlan和Bridge相似,但省去了Bridge的存在,所以配置和调试起来比较简单,效率也相对高。此外,Macvlan完美支持VLAN。
Before MACVLAN, if you wanted to connect to physical network from a VM or namespace, you would have needed to create TAP/VETH devices and attach one side to a bridge and attach a physical interface to the bridge on the host at the same time…
物理网卡相当于一个交换机,记录着对应的虚拟网卡的MAC 地址,当收到数据包时,它会根据目的 MAC 判断这个包属于哪一个虚拟网卡。这就意味着,只要是从 Macvlan 子接口发来的数据包(或者是发往 Macvlan 子接口的数据包),物理网卡只转发数据包,而不处理数据包;这导致:本机 Macvlan 网卡上的 IP 无法和物理网卡上面的 IP 直接通信!这和ipvlan一样。
Mavlan sub-interfaces are not able to directly communicate with the parent interface , i.e. VMs cannot directly communicate with the host. If you require VM-host communication, you should add another macvlan sub-interface and assign it to the host.
模式
macvlan有四种模式:private、VEPA(default mode)、Bridge和Passthru。具体每种模式的说明请参考这里。
Macvlan sub-interfaces use a mac0@eth0 notation, to clearly identify the sub-interface and it’s parent interface. Sub-interface state is bound to its parent’s state – if eth0 is down, so is the mac0@eth0.
vepa
vepa模式的测试拓扑如下:
在这种拓扑下
bridge上的veth接口其实就相当于物理交换机的trunk类型接口!
环境配置
首先创建bridge:test_br,两个veth设备对,并将veth设备对的一端加入 test_br,打开bridge上两个接口的hairpin配置。
1 | |
在两个veth设备对的另一端各自创建一个vlan子接口,并打开其混杂模式;注意,vlan子接口和父接口的MAC地址一样:
1 | |
配置防火墙规则允许bridge test_br转发数据:
1 | |
创建4个网络命名空间,并分别基于veth1.11和veth2.12各创建两个macvlan接口,放入对应命名空间:
1 | |
ns1的配置如下:
1 | |
ns2配置如下:
1 | |
ns3的配置如下:
1 | |
ns4配置如下:
1 | |
验证同一父接口下macvlan子接口的连通性
在ns1中执行:ping 192.168.9.3,可以看到在bridge的作用下同一父接口的macvlan接口之间是通的。可以看到192.168.9.3的mac地址正是是ns2中macvl2接口的mac地址,而不是ns4中macvl4的。
1 | |
验证一下,在网桥中的veth1_br接口上抓包,可以看到数据帧都带有vlan tag,并且又都发回veth1_br接口,所以数据包是双份的:
注意:
bridge等桥接设备在转发数据包时源MAC和目的MAC不会改变!
1 | |
在veth2.12和ns4中的macvl4接口上都没有抓到数据包:
说明,对于
vlan子接口来说,非此vlan的数据包已经在父接口被丢弃!
1 | |
验证跨父接口macvlan接口的连通性
在veth2接口上再创建一个vlan id为11的vlan子接口:veth2.11,在其上创建macvlan子接口,并将其移动到ns5命名空间:
1 | |
ns5配置如下:
1 | |
在ns1中执行ping 192.168.9.5,通:
1 | |
在veth2.11上抓包,可以看到vlan子接口上的vlan tag信息已经被去掉了!
当父接口接收报文时,如果是802.1Q报文,则会根据VLAN ID将报文发到对应的子接口。
当子接口发送报文时,内核会在报文中添加802.1Q头,然后交由父接口完成发送。接收报文时,Linux内核在将帧从父接口转发到VLAN子接口时,会自动移除VLAN标签。
1 | |
private
private模式的测试拓扑如下:
环境配置
首先清理vepa模式下创建的环境:
1 | |
按上面拓扑创建环境,基于veth1和veth2创建3个macvlan接口放入三个命名空间,并打开两个父接口的混杂模式:
1 | |
ns1的配置如下:
1 | |
ns2配置如下:
1 | |
ns3配置如下:
1 | |
测试同一父接口下macvlan接口连通性
在ns1中执行ping 192.168.9.3,不通!
1 | |
在ns2中没有抓到任何报文:
1 | |
在ns3上抓包,可以看到对应的arp报文:
1 | |
在接口veth1_br上抓包,结合ns3中抓到的报文可以得出对应的报文已经发回父接口,但是被父接口丢弃!
1 | |
手动在ns1和ns2中添加对方的mac地址信息后测试:
在ns1中:
1 | |
在ns2中:
1 | |
再次在ns1中测试,通了(ping了两次)!
这说明
macvlan的private模式只是屏蔽了同一父接口下macvlan子接口之间的arp广播报文,要能相互通信须手动更新arp表!
1 | |
在ns2中抓包,可以看到两次ping的报文交互:
1 | |
在veth2上抓包,可以看到了一条icmp请求报文,这是bridge泛洪的报文,在bridge的转发表相应条目过期前只会收到这一次!
1 | |
注意此时在ns3中并未抓到任何报文,因为虽然第一次bridge会泛洪,但此时是因为父接口并没有转发icmp请求报文到macvl3接口,报文并不是macvl3接口丢弃的!
正常情况下当网卡接收到一个数据帧时,它会检查该数据帧的目的MAC地址是否与其自身的MAC地址匹配。如果目的MAC地址不是网卡自身的MAC地址,并且网卡没有处于混杂模式(Promiscuous Mode),那么网卡会丢弃这个数据帧,不会将其传递给上层协议栈或任何网络分析工具(如tcpdump)。
1 | |
验证和外部网络的连通性
在bridge test_br上配置ip:192.168.9.1,bridge配置ip后就具备了三层路由功能,但这并不影响其二层转发功能:
如果要和公网的交互,则还需要配置
iptables的nat转发规则,可以参考linux 虚拟网卡之 ipvlan
1 | |
在ns1中添加到test_br的默认路由 ,然后ping宿主机ip(36.58)和宿主机所在物理网络host(36.66),通!
1 | |
在bridgetest_br上抓包:
1 | |
在eno2(36.58)上抓包,可以看到36.66相关的报文已经从eno2(36.58)接口转发出去!注意并没有和36.58相关的交互报文!
1 | |
36.66上到网络192.168.9.0/24路由配置如下:
1 | |
bridge
换种方式,直接在物理网卡eno2上创建两个macvlan子接口,子接口配置和父接口同一网络下的ip。
环境搭建
创建命名空间ns4和ns5,并将创建的两个macvlan接口分别放入两个命名空间:
1 | |
ns4的配置如下:
1 | |
ns5中配置:
1 | |
测试macvlan接口间的连通性
在ns4中pingns5,通:
1 | |
在宿主机的父接口抓包如下,父接口相当于一个bridge转发其上macvlan接口之间的单播报文:
1 | |
在和宿主机同一物理网络的其它主机(36.66)抓包,抓到了arp广播报文,也说明macvlan接口和父接口共享同一广播域!
1 | |
测试和外部网络的连通性
在ns4中ping和父接口同一物理网络的其它主机36.66以及其它网络的主机10.138.10.161,通:
1 | |
在父接口上抓包如下,可以看到ping不同子网ip时,流量是经过网关36.1的:
1 | |
测试与公网的连通性
当然ping 110.242.68.66公网也是通的,因为报文也是通过网关36.1转发出去了(默认路由)。这种情况,因为创建的macvlan接口和父接口是同一网络,所以省去了额外在防火墙iptables中配置 NAT规则的麻烦。
1 | |
父接口上抓包:
1 | |