$ip -d link show flannel.1 13: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN mode DEFAULT group default link/ether da:42:52:a6:68:99 brd ff:ff:ff:ff:ff:ff promiscuity 0 vxlan id 1 local 192.168.1.110 dev eno1 srcport 0 0 dstport 8472 nolearning ageing 300 addrgenmode none$ ip -d addr show flannel.1 13: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default link/ether da:42:52:a6:68:99 brd ff:ff:ff:ff:ff:ff promiscuity 0 vxlan id 1 local 192.168.1.110 dev eno1 srcport 0 0 dstport 8472 nolearning ageing 300 inet 10.244.1.0/32 scope global flannel.1 valid_lft forever preferred_lft forever
可以看到,本机的 VTEP 分配了 10.244.1.0 这个 IP 地址。而 MTU 被设置成了 1450 字节,这是因为 VxLAN 需要额外的 MAC + IP + UDP + VxLAN Header = 14 + 20 + 8 + 8 = 50 字节的封装。
而 cni0 网桥则相当于一个本机交换机,带有一个 VLAN:
1 2 3 4 5 6 7 8 9 10 11
$ip -d link show cni0 14: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether 1a:9b:9d:6d:4f:f2 brd ff:ff:ff:ff:ff:ff promiscuity 0 bridge forward_delay 1500 hello_time 200 max_age 2000 ageing_time 30000 stp_state 0 priority 32768 vlan_filtering 0 vlan_protocol 802.1Q addrgenmode eui64$ ip -d addr show cni0 14: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default qlen 1000 link/ether 1a:9b:9d:6d:4f:f2 brd ff:ff:ff:ff:ff:ff promiscuity 0 bridge forward_delay 1500 hello_time 200 max_age 2000 ageing_time 30000 stp_state 0 priority 32768 vlan_filtering 0 vlan_protocol 802.1Q inet 10.244.1.1/24 scope global cni0 valid_lft forever preferred_lft forever inet6 fe80::189b:9dff:fe6d:4ff2/64 scope link valid_lft forever preferred_lft forever
查看路由表可以发现,同一个主机上的 Pod 直接使用 cni0 网桥通信,而如果要跨机通信,则需要通过 Flannel 网卡进行隧道转发到对应主机上的 Flannel VxLAN 网卡:
1 2 3 4 5 6 7 8
$ip route show ... 10.244.0.0/24 via 10.244.0.0 dev flannel.1 onlink 10.244.1.0/24 dev cni0 proto kernel scope link src 10.244.1.1 10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink 10.244.3.0/24 via 10.244.3.0 dev flannel.1 onlink 10.244.4.0/24 via 10.244.4.0 dev flannel.1 onlink ...
那么问题来了,例如本机需要发送一个到 10.244.2.233 的数据包,经过路由表发现需要发送给网关 10.244.2.0。毫无疑问,这时候主机需要知道 10.244.2.0 的 MAC 地址,此时相当于发生了一次 l3miss,主机会尝试发送 ARP 来获取 10.244.2.0 的 MAC 地址。当然,为了避免广播风暴,Flannel 会提前在 ARP 表中写好对端 VTEP 的 MAC 地址:
ip neigh
1 2 3 4 5 6 7 8 9
... 10.244.1.57 dev cni0 lladdr 1e:fd:14:d0:08:51 REACHABLE 10.244.3.0 dev flannel.1 lladdr 56:34:8f:23:99:30 PERMANENT 10.244.7.0 dev flannel.1 lladdr ea:60:1e:c4:3d:6f PERMANENT 10.244.5.0 dev flannel.1 lladdr d6:ea:dd:2b:cc:86 PERMANENT 10.244.1.47 dev cni0 lladdr b6:02:9a:fd:b9:a9 REACHABLE 10.244.1.60 dev cni0 lladdr 4a:25:01:b7:a0:b2 REACHABLE 10.244.2.0 dev flannel.1 lladdr aa:63:8e:fa:63:4e PERMANENT ...
知道了 MAC 地址之后,还有一个问题:这个 MAC 地址应该发送到哪个主机上呢,我要从哪个端口发送数据包,用哪个 IP 地址封装?此时,相当于发生了一次 l2miss,如果是交换机,就会尝试泛洪(Flooding),同样为了避免广播,Flannel 会提前在 FDB (相当于交换机的 MAC 地址表)写好对应的主机 IP: