Macvlan 允许你在主机的一个网络接口上配置多个虚拟的网络接口,这些网络 interface 有自己独立的 MAC 地址,也可以配置上 IP 地址进行通信。Macvlan 下的虚拟机或者容器网络和主机在同一个网段中,共享同一个广播域。Macvlan 和 Bridge 比较相似,但因为它省去了 Bridge 的存在,所以配置和调试起来比较简单,而且效率也相对高。除此之外,Macvlan 自身也完美支持 VLAN

macvlan 本身是 linxu kernel 模块,其功能是允许在同一个物理网卡上配置多个 MAC 地址,即多个 interface,每个 interface 可以配置自己的 IP。macvlan 本质上是一种网卡虚拟化技术(最大优点是性能极好)

可以在 linux 命令行执行 lsmod | grep macvlan 查看当前内核是否加载了该 driver;如果没有查看到,可以通过 modprobe macvlan来载入,然后重新查看。内核代码路径 /drivers/net/macvlan.c

Bridge VS MACVlan

Bridge Mode

  • Bridge 是二层设备,仅用来处理二层的通讯。
  • Bridge 使用 MAC 地址表来决定怎么转发帧(Frame)。
  • Bridge 会从 host 之间的通讯数据包中学习 MAC 地址。
  • 可以是硬件设备,也可以是纯软件实现(例如:Linux Bridge)。

提示:

**Bridge 有可能会遇到二层环路,如有需要,可以开启 STP 来防止出现环路。**

MACVlan Mode

  • 可让使用者在同一张实体网卡上设定多个 MAC 地址。
  • 上述设定的 MAC 地址的网卡称为子接口(sub interface);而实体网卡则称为父接口(parent interface)。
  • parent interface 可以是一个物理接口(eth0),可以是一个 802.1q 的子接口(eth0.10),也可以是 bonding 接口。
  • 可在 parent/sub interface 上设定的不只是 MAC 地址,IP 地址同样也可以被设定。
  • sub interface 无法直接与 parent interface 通讯 (带有 sub interface 的 VM 或容器无法与 host 直接通讯)。
  • 若 VM 或容器需要与 host 通讯,那就必须额外建立一个 sub interface 给 host 用。
  • sub interface 通常以 mac0@eth0 的形式来命名以方便区別。

工作模式

Bridge Mode

属于同一个 parent 接口的 macvlan 接口之间挂到同一个 bridge 上,可以二层互通(macvlan 接口都无法与 parent 接口互通)

VPEA Mode

Virtual Ethernet Port Aggregator,所有接口的流量都需要到外部 switch 才能够到达其他接口

Private Mode

接口只接受发送给自己 MAC 地址的报文。

Passthru Mode

父接口和相应的 MacVLAN 接口捆绑在一起,这种模式每个父接口只能和一个 Macvlan 虚拟网卡接口进行捆绑,并且 Macvlan 虚拟网卡接口继承父接口的 MAC 地址。

实战体验

下面的实验创建了两个 macvlan 接口,分别放到两个 netns 中;然后验证这两个 macvlan 口之间客户互通。

先使用 bridge mode 创建两个 macvlan 接口,其 parent 接口都是 eth0。

1
2
$ sudo ip link add link eth0 name macv1 type macvlan mode bridge
$ sudo ip link add link eth0 name macv2 type macvlan mode bridge

查看创建的结果,注意每个接口都有自己的 mac 地址

1
2
3
4
5
6
7
$ sudo ip link
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:f4:3e:1d brd ff:ff:ff:ff:ff:ff
3763: macv1@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 52:76:5f:92:85:8d brd ff:ff:ff:ff:ff:ff
3764: macv2@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 66:90:ba:08:bd:81 brd ff:ff:ff:ff:ff:ff

创建 namespace

1
2
$ sudo ip netns add net1
$ sudo ip netns add net2

将 macvlan 接口插入到 namespace

1
2
$ sudo ip link set macv1 netns net1
$ sudo ip link set macv2 netns net2

设置网卡 IP,设置网卡 UP 状态

1
2
3
4
5
$ sudo ip netns exec net1 ip addr add 52.1.1.151/24 dev macv1
$ sudo ip netns exec net2 ip addr add 52.1.1.152/24 dev macv2

$ sudo ip netns exec net1 ip link set macv1 up
$ sudo ip netns exec net2 ip link set macv2 up

查看网卡状态

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ sudo ip netns exec net1 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3763: macv1@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 52:76:5f:92:85:8d brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 52.1.1.151/24 scope global macv1
       valid_lft forever preferred_lft forever
$ sudo ip netns exec net2 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3764: macv2@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 66:90:ba:08:bd:81 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 52.1.1.152/24 scope global macv2
       valid_lft forever preferred_lft forever

net1 和 net2 无法 ping 通宿主机,ping 自己也不通.2 个容器互相 ping 没有问题

发现 macv1 ping 不通宿主机接口 eth0 的地址:

1
2
3
4
5
$ sudo ip net exec net1 ping 10.0.1.3
PING 10.0.1.3 (10.0.1.3) 56(84) bytes of data.
^C
--- 10.0.1.3 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3008ms

但是可以 ping 通 macv2 的地址:

1
2
3
4
5
$ sudo ip net exec net1 ping 52.1.1.152
PING 52.1.1.152 (52.1.1.152) 56(84) bytes of data.
64 bytes from 52.1.1.152: icmp_seq=1 ttl=64 time=0.044 ms
64 bytes from 52.1.1.152: icmp_seq=2 ttl=64 time=0.041 ms
64 bytes from 52.1.1.152: icmp_seq=3 ttl=64 time=0.047 ms