Docker Vxlan流量跨namespace浅析
实验目的:在Docker容器内,一般是通过veth-pair设备对实现了夸namespace流量传输,但是在Vxlan设备中,它如何实现从一个namespace封装数据包到宿主机的物理网卡呢?
实验环境
添加vxlan设备
另一台机器也按照这个流程添加一个10.70.2.200/24
# 添加一个vxlan设备,remote,local 在这里类似于选择vtep设备,用来封装、收发vxlan数据包
[root@boy ~]# ip link add vxlan0 type vxlan id 100 dstport 100 remote 192.168.0.12 local 192.168.0.11 dev ens33
# 添加一个vxlan命名空间,用来模拟容器的网络隔离环境
[root@boy ~]# ip netns add vxlan
# 将vxlan0设备加到这个vxlan命名空间
[root@boy ~]# ip link set vxlan0 netns vxlan
# 配置vxlan0的IP地址
[root@boy ~]# ip netns exec vxlan ip addr add 10.70.2.100/24 dev vxlan0
# 启动vxlan0设备
[root@boy ~]# ip netns exec vxlan ip link set vxlan0 up
# 进入vxlan命名空间,查看fdb表
[root@boy ~]# ip netns exec vxlan bridge fdb show
00:00:00:00:00:00 dev vxlan0 dst 192.168.0.12 link-netnsid 0 self permanent
# 查看此时ARP表,可见此时没有10.70.2.200的MAC地址
[root@boy ~]# ip netns exec vxlan arp -n
[root@boy ~]#
# 查看路由表,这条路由表明,在这个命名空间内,只有能去10.70.2.0/24的流量有路由通过vxlan0出去,其余的流量是不可达
[root@boy ~]# ip netns exec vxlan ip route
10.70.2.0/24 dev vxlan0 proto kernel scope link src 10.70.2.100
抓包分析
# vxlan0抓包
ip netns exec vxlan tcpdump -i any -w vxlan.cap
# vxlan0 ping
[root@boy ~]# ip netns exec vxlan ping 10.70.2.200
从上述抓包可以知道,10.70.2.100第一次ping 10.70.2.200时,会构建一个target MAC全为0的ARP数据包
# 这部分的MAC地址和上述截图的可能不一样,上图的实验环境当时做实验时未保存
# 查看此时ARP表、FDB表,可见vxlan0 通过ARP学习到了10.70.2.200的MAC地址
[root@boy ~]# ip netns exec vxlan bridge fdb
00:00:00:00:00:00 dev vxlan0 dst 192.168.0.12 via ifindex 2 link-netnsid 0 self permanent
06:ec:46:74:39:22 dev vxlan0 dst 192.168.0.12 link-netnsid 0 self
[root@boy ~]# ip netns exec vxlan arp -n
Address HWtype HWaddress Flags Mask Iface
10.70.2.200 ether 06:ec:46:74:39:22 C vxlan0
# ens33物理网卡抓包,不加-T指定 VXLAN格式,只显示UDP报文,原因未知
[root@docker1 ~]# tcpdump -i any host 192.168.0.12 -Nnv -T vxlan -X
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
23:28:40.595794 IP (tos 0x0, ttl 64, id 11743, offset 0, flags [none], proto UDP (17), length 134)
192.168.0.12.54943 > 192.168.0.11.100: VXLAN, flags [I] (0x08), vni 0
IP (tos 0x0, ttl 64, id 29630, offset 0, flags [DF], proto ICMP (1), length 84)
10.70.2.200 > 10.70.2.100: ICMP echo request, id 1360, seq 1299, length 64
0x0000: 4500 0086 2ddf 0000 4011 cb20 c0a8 000c E...-...@.......
0x0010: c0a8 000b d69f 0064 0072 90d7 0800 0000 .......d.r......
0x0020: 0000 0000 1eb0 2135 c271 ce5a 87a5 ad6f ......!5.q.Z...o
0x0030: 0800 4500 0054 73be 4000 4001 ad33 0a46 ..E..Ts.@.@..3.F
0x0040: 02c8 0a46 0264 0800 e1ac 0550 0513 e8db ...F.d.....P....
0x0050: 7962 0000 0000 e2de 0800 0000 0000 1011 yb..............
0x0060: 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 ...............!
0x0070: 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 "#$%&'()*+,-./01
0x0080: 3233 3435 3637 234567
23:28:40.595825 IP (tos 0x0, ttl 64, id 1332, offset 0, flags [none], proto UDP (17), length 134)
192.168.0.11.41086 > 192.168.0.12.100: VXLAN, flags [I] (0x08), vni 0
IP (tos 0x0, ttl 64, id 1300, offset 0, flags [none], proto ICMP (1), length 84)
10.70.2.100 > 10.70.2.200: ICMP echo reply, id 1360, seq 1299, length 64
0x0000: 4500 0086 0534 0000 4011 f3cb c0a8 000b E....4..@.......
0x0010: c0a8 000c a07e 0064 0072 81eb 0800 0000 .....~.d.r......
0x0020: 0000 0000 ce5a 87a5 ad6f 1eb0 2135 c271 .....Z...o..!5.q
0x0030: 0800 4500 0054 0514 0000 4001 5bde 0a46 ..E..T....@.[..F
0x0040: 0264 0a46 02c8 0000 e9ac 0550 0513 e8db .d.F.......P....
0x0050: 7962 0000 0000 e2de 0800 0000 0000 1011 yb..............
0x0060: 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 ...............!
0x0070: 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 "#$%&'()*+,-./01
0x0080: 3233 3435 3637 234567
结论
结论:即使vxlan被添加到另一命名空间后,只要存在00:00:00:00:00:00(第一次请求ARP时所需要,后续学习到对端IP后流量也会通过vxlan0) dev vxlan0 dst 192.168.0.15 link-netnsid 0 self permanent 这种FDB表,就会把流量自己封装好,然后发送到ens33(不需要借助像veth这种设备,然后ens33将在vxlan0发过来数据包的基础上使用UDP进行封装,然后封装IP报文,然后封装MAC等从而实现在一个三层网络上构建了一个二层网络)