[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/
- 应用层
- HTTP
- Cookie
- Session
- HTTP报文格式
- HTTP的Header字段
- HTTPS
- 简介
- 原理
- RSA加密与解密
- 证书签名与验证
- TLS双向认证
- openssl命令汇总
- DNS
- DNS的记录类型
- DNS的报文格式
- FAQ
- 传输层
- TCP
- CloseWait
- 网络层
- IPv6
- 链路层
- 链接层基础知识
- VLAN
- FAQ
- Linux网络收发包
- 网卡收包
- 网卡发包
- 收发包FAQ
- LVS
- 安装-DR模式
- 基本原理
- Ipvsadm命令
- Netfilter
- Netfilter简介
- 注册钩子函数
- Netfilter中数据包流向
- Iptables的数据结构
- 连接跟踪
- 初识连接跟踪
- 连接跟踪详解
- 连接跟踪数据结构
- 数据包与连接的状态
- NAT
- IPVS
- KubeProxy的IPVS模式
- Linux虚拟网络设备
- 虚拟网络设备简介
- Tap
- VethPair
- Vlan
- Vxlan
- Flannel的VXLAN原理
- Openstack的VXLAN原理
- VXLAN总结
- Bridge
- 给容器设置主机网段IP
- Macvlan
- Ipvlan
- IPIP
- IPIP使用介绍
- IPIP源码分析
- Limdiag网络
- 详细设计
- kubeovn
- IP命令
- Calico
- Calico常见问题
- ARP无响应
- 其他