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 |
|
在bridge
test_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中ping
ns5,通:
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 |
|