本来想将macvlan和ipvlan放一起写,但是在测试过程中发现,ipvlan使用起来还是挺复杂的,于是单独作为一章来写。
ipvlan 和 macvlan 类似,都是从一个主机接口虚拟出多个虚拟网络接口。一个重要的区别就是所有的虚拟接口都有相同的 macv 地址,而拥有不同的 ip 地址。
ipvlan 有两种不同的模式:L2 和 L3。一个父接口只能选择一种模式,依附于它的所有虚拟接口都运行在这个模式下,不能混用模式。
L2 模式和 macvlan bridge 模式工作原理很相似,父接口作为交换机来转发子接口的数据。同一个网络的子接口可以通过父接口来转发数据,而如果想发送到其他网络,报文则会通过父接口的路由转发出去。
L3 模式下,ipvlan 有点像路由器的功能,它在各个虚拟网络和主机网络之间进行不同网络报文的路由转发工作。
为了更好的理解代码,在做代码分析之前,先按照场景看一下ipvlan的使用。
如下图:
两个主机: host1,host2
host1上:
Ns0~Ns3 是三个network namespace;
ipv0_0, ipv0_1 是在eth0上创建的两个ipvlan接口;
ipv1_0, ipv1_1, ipv1_2 是在eth1上创建的三个ipvlan接口;
ipv2_0, ipv2_1, 是在eth1上创建的两个ipvlan接口。
ipv0_0, ipv1_0, ipv2_0 在宿主机的namespace,其它的在相应的namespace中。
注意修改一下宿主接口的rp_filter配置为0或者2(场景二、三)
echo 0 > /proc/sys/net/ipv4/conf/eth0/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/eth1/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/eth2/rp_filter
####场景一、ipvlan mode l2,ipv1_1, ipv1_2 互通
即同一宿主接口的两个ipvlan接口之间互通,2.1.1.1 ping 2.1.1.2,两个接口是同一网段,arp获取到对方的mac地址后,ipv1_1的驱动发送函数通过查找ip地址(2.1.1.2)所在的ipvlan接口为ipv1_2,直接走接口的接收流程。反向一样。
####场景二、ipvlan mode l2,ipv1_1, Host1互通
这种场景,即如何使用ipvlan 和宿主机互通,很常用的一个场景。
如图,我们从 Ns2 ping 宿主机,即2.1.1.1 ping 170.171.0.1,流量分红色的出方向和蓝色的入方向,走的是不同的路。
先贴配置,Ns2中的路由配置:
# ip route
default via 2.1.1.254 dev ipv2_1
宿主机的配置:
# ip addr
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:89:49:80 brd ff:ff:ff:ff:ff:ff
inet 1.1.1.254/24 scope global ens9
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fe89:4980/64 scope link
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:4e:0a:de brd ff:ff:ff:ff:ff:ff
inet 2.1.1.254/24 scope global ens10
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fe4e:ade/64 scope link
valid_lft forever preferred_lft forever
33: ipv0_0@ens9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 52:54:00:89:49:80 brd ff:ff:ff:ff:ff:ff
inet 192.168.114.1/32 scope host ipv1_0
valid_lft forever preferred_lft forever
inet6 fe80::5254:0:189:4980/64 scope link
valid_lft forever preferred_lft forever
39: ipv1_0@ens10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
link/ether 52:54:00:4e:0a:de brd ff:ff:ff:ff:ff:ff
inet 192.168.114.1/32 scope host ipv2_0
valid_lft forever preferred_lft forever
inet6 fe80::5254:0:24e:ade/64 scope link
valid_lft forever preferred_lft forever
40: ipv2_0@ens15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
link/ether 52:54:00:8f:77:cd brd ff:ff:ff:ff:ff:ff
inet 192.168.114.1/32 scope host ipv3_0
valid_lft forever preferred_lft forever
inet6 fe80::5254:0:28f:77cd/64 scope link
# ip route
1.1.1.1 dev ipv0_0 scope link
2.1.1.1 dev ipv1_0 scope link
2.1.1.2 dev ipv1_0 scope link
3.1.1.1 dev ipv2_0 scope link
# ip neigh
2.1.1.1 dev ipv1_0 lladdr 52:54:00:4e:0a:de
可以看到,Ns2中,路由的配置我们指定了nexthop为宿主接口的ip地址,而不是直接指向ipv1_1,两者的区别是前者arp请求网关ip所以会有数据报文dst macsrc mac的结果;而后者请求ping包的dst ip。
因为宿主机和Ns2不是一个广播域,出方向数据报文,目的ip不是eth1任何一个ipvlan接口的ip,且dst macsrc mac,数据报文需要通过宿主接口协议栈,查找路由表,找到170.171.0.1 为宿主机loopback口ip地址;而回来的包,是无法通过eth1进入的(进eth1就直接发到设备外),这需要通过宿主机中和ipv1_1同宿主的ipv1_0进入ipv1_1,我们配置了“2.1.1.1 dev ipv1_0 scope link”,在宿主机上通过三层将流量转发至ipv1_0,后面流程就入场景一一样,