🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ### **原理** 我们首先给出flannel-vxlan模式下,两个K8S节点容器之间通信的流程图,如下: ![](https://img.kancloud.cn/10/60/10607ffae770a98bda4099d478cbeff1_810x318.png) cni0是一个Linux虚拟网桥,flannel.1是一个Linux虚拟网络设备,类型为VXLAN,容器与cni0之间通过veth-pair连接。 假设节点Peng02上的容器`172.26.0.2`向节点Peng03上的容器`172.26.1.2`发送ping数据包(对应图上的Inner IP Header)。 首先数据包到达cni0网桥,cni0网桥接收到数据包后,最终会把包投递到主机的内核协议栈中(即会进入到`ip_rcv`函数)。根据下面的路由,数据包最终会从flannel.1网卡出去。 ``` [root@peng02 ~]# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface ... 172.26.0.0 0.0.0.0 255.255.255.0 U 0 0 0 cni0 172.26.1.0 172.26.1.0 255.255.255.0 UG 0 0 0 flannel.1 ``` 当数据包到达flannel.1时,需要对其进行二层封装。下一跳地址(上面那一条路由的网关)为`172.26.1.0/32`,于是就会查找flannel.1的ARP表(这个ARP表是由flanneld进行维护的),如下: ``` [root@peng02 ~]# ip neigh show dev flannel.1 172.26.1.0 lladdr 92:8d:c4:85:16:ad PERMANENT ``` 查到找对应的ARP条目后,于是对数据包进行二层封装,即对应前面图中的`Inner Ethernet Header`。 此时,`skb_buff`要从flannel.1发送出去。设备flannel.1的类型为VXLAN,于是会调用VXLAN模块的发送函数`vxlan_xmit`(不同类型的设备,发送函数不一样)。 VXLAN模块首先检查flannel.1的VNI(所有节点的flannel1的VNI都为1,这也是为什么flannel叫flannel.1的原因),然后将对数据帧封装一层VXLAN Header,这个头部中会包含VNI。 接着,VXLAN模块继续进行UDP封装,(要进行UDP封装,就要知道四元组信息:源IP、源端口、目的IP、目的端口)。首先是目的端口,Linux内核中默认为VXLAN分配的UDP监听端口为8472;然后是源端口,源端口是根据封装的内部数据帧做一个哈希值得到。 接下来是目的IP。Linux下的VXLAN设备都有一个转发表。通过下面的命令查看flannel.1的转发表,如下:(由flanneld进程维护): ``` [root@peng02 ~]# bridge fdb show dev flannel.1 | grep 92:8d:c4:85:16:ad 92:8d:c4:85:16:ad dev flannel.1 dst 192.168.2.103 self permanent ``` 它记录着,目的MAC地址为`92:8d:c4:85:16:ad`的数据帧封装后,应该发往哪个目的IP。根据上面的记录可以看出,UDP的目的IP应该为192.168.2.103。 最后是源IP,任何一个VXLAN设备创建时都会指定一个三层物理网络设备作为VTEP,这个物理网络设备的IP就是UDP的源IP。可以使用以下的命令查看flannel.1的VTEP,发现是ens33,所以源IP是192.168.2.102 ``` $ ip -d link show flannel.1 ... ``` UDP的四元组确定后,vxlan调用UDP协议的发包函数进行发包,后面的过程和本机的UDP程序发包没什么区别。 当数据包到达Peng03的8472端口后(实际上就是VXLAN模块),VXLAN模块就会比较这个VXLAN Header中的VNI和本机的VTEP(VXLAN Tunnel End Point,就是flannel.1)的VNI是否一致,然后比较Inner Ethernet Header中的目的MAC地址与本机的flannel.1是否一致,都一致后,则去掉数据包的VXLAN Header和Inner Ethernet Header,然后把数据包从flannel.1网卡进行发送。 然后,在Peng03节中上会有如下的路由(由flanneld维护),根据路由判断要把数据包发送到cni0网卡上。 ``` [root@peng03 ~]# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface ... 172.26.1.0 0.0.0.0 255.255.255.0 U 0 0 0 cni0 ``` ### **总结** * 经过封装,VXLAN隧道的两个端口是二层可通的;也就是说,VXLAN虚拟出来的是一个大二层网络。 ### **参考** * https://www.dazhuanlan.com/2019/11/08/5dc4570b3303a/ * https://cizixs.com/2017/09/28/linux-vxlan/