IPVLAN 和 MACVLAN 类似,都是从一个主机接口虚拟出多个虚拟网络接口。一个重要的区别就是所有的虚拟接口都有相同的 mac 地址,而拥有不同的 ip 地址。

因为所有的虚拟接口要共享 mac 地址,所以有些需要注意的地方:

  • DHCP 协议分配 ip 的时候一般会用 mac 地址作为机器的标识。这个情况下,客户端动态获取 ip 的时候需要配置唯一的 ClientID 字段,并且 DHCP server 也要正确配置使用该字段作为机器标识,而不是使用 mac 地址

Ipvlan 是 linux kernel 比较新的特性,linux kernel 3.19 开始支持 ipvlan,但是比较稳定推荐的版本是 >=4.2(因为 docker 对之前版本的支持有 bug),具体代码见内核目录:/drivers/net/ipvlan/

工作模式

创建 ipvlan 的简单方法为

1
$ ip link add link <master-dev> <slave-dev> type ipvlan mode { l2 | L3 }

L2 模式

ipvlan L2 模式和 macvlan bridge 模式工作原理很相似,父接口作为交换机来转发子接口的数据。同一个网络的子接口可以通过父接口来转发数据,而如果想发送到其他网络,报文则会通过父接口的路由转发出去。

L3 模式

ipvlan 有点像路由器的功能,它在各个虚拟网络和主机网络之间进行不同网络报文的路由转发工作。只要父接口相同,即使虚拟机/容器不在同一个网络,也可以互相 ping 通对方,因为 ipvlan 会在中间做报文的转发工作。

注意 L3 模式下的虚拟接口 不会接收到多播或者广播的报文(这个模式下,所有的网络都会发送给父接口,所有的 ARP 过程或者其他多播报文都是在底层的父接口完成的)。另外外部网络默认情况下是不知道 ipvlan 虚拟出来的网络的,如果不在外部路由器上配置好对应的路由规则,ipvlan 的网络是不能被外部直接访问的。

实战体验

创建 IPVlan L3 模式

1
2
[root@localhost ~]#ip link add link ens224 ipvlan1 type ipvlan mode l3
[root@localhost ~]#ip link add link ens224 ipvlan2 type ipvlan mode l3

注意看 ipvlan1 和 ipvlan2 的 MAC 地址跟 ens224 的一样

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[root@localhost ~]# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
   link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
   link/ether 00:0c:29:05:18:ac brd ff:ff:ff:ff:ff:ff
3: ens224: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
   link/ether **00:0c:29:05:18:b6** brd ff:ff:ff:ff:ff:ff
4: ipvlan1@enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
   link/ether **00:0c:29:05:18:b6** brd ff:ff:ff:ff:ff:ff
5: ipvlan2@enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
   link/ether **00:0c:29:05:18:b6** brd ff:ff:ff:ff:ff:ff

创建 ns 绑定接口

1
2
3
4
[root@localhost ~]#ip netns add net1
[root@localhost ~]#ip netns add net2
[root@localhost ~]#ip link set ipvlan1 netns net1
[root@localhost ~]#ip link set ipvlan2 netns net2

配置 IP

1
2
3
4
[root@localhost ~]#ip netns exec net1 ip addr add 10.0.2.18/24 dev ipvlan1
[root@localhost ~]#ip netns exec net2 ip addr add 10.0.3.19/24 dev ipvlan2
[root@localhost ~]#ip netns exec net1 ip link set ipvlan1 up
[root@localhost ~]#ip netns exec net2 ip link set ipvlan2 up

增加路由

1
2
[root@localhost ~]#ip netns exec net1 route add default dev ipvlan1
[root@localhost ~]#ip netns exec net2 route add default dev ipvlan2

ping 测试,2 个 ns 可以正常互相 ping 通,无法 ping 通宿主机 IP

抓取 ARP 报文,结果无法在 L3 模式中抓到 ARP,说明二层广播和组播都不处理,工作在 L3。(这就是和 L2 模式的区别)

1
[root@localhost ~]#ip netns exec net1 tcpdump -ni ipvlan1 -p arp

创建 L2 模式,其余操作跟 L3 一样

1
2
# ip link add link enp0s3 ipvlan1 type ipvlan mode l2
# ip link add link enp0s3 ipvlan2 type ipvlan mode l2

区别在于 L2 可以在 2 个 ns 中抓取到 ARP 报文

总结

ipvlan L3 模式中外部网络默认情况下是不知道 ipvlan 虚拟出来的网络的,如果不在外部路由器上配置好对应的路由规则,ipvlan 的网络是不能被外部直接访问的。

CNI 配置

cni 配置格式为

1
2
3
4
5
6
7
8
9
{
    "name": "mynet",
    "type": "ipvlan",
    "master": "eth0",
    "ipam": {
        "type": "host-local",
        "subnet": "10.1.2.0/24"
    }
}

需要注意的是

  • ipvlan 插件下,容器不能跟 Host 网络通信
  • 主机接口(也就是 master interface)不能同时作为 ipvlan 和 macvlan 的 master 接口