1、同节点,同POD,不同容器之间通信

  1. 采用container 模式 (跟udp一样)
  2. 这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。# [两个容器的进程可以通过 lo 网卡设备通信。]


2、同节点,不同pod之间通信

# 同节点不同Pod之间的通信: (跟udp一样)
/#/ 有一个前提,我们在iconfig中看到的网卡都是在内核级别的,或是说在内核这个层面。
Pod - Pod[Same Node]:通常情况下,在Flannel上解决同节点Pod之间的通信依赖的是Linux Bridge,和我们在Docker中不同的是,在Kubernetes Flannel的环境中使用的Linux Bridge为cni0,而不是原来的docker0。
可通过:brctl  show查看对应的Linux Bridge的bridge name和interfaces。
[root@k8s-1 ~]# brctl show 
bridge name     bridge id               STP enabled     interfaces
cni0            8000.1edb12e1c079       no              veth54a9e98a  # cni0 为Linux下的一个虚拟Bridge。
docker0         8000.0242da0ca579       no
[root@k8s-1 ~]# 
此时我们看到一端在ROOT NS中的一个接口,而Pod中的eth0中的接口在Pod所在的namespace中。此时两者之间有通信的需求,何种方案比较合适呢?--- #[veth pair]
其中veth device(pair)的定义为:
# The veth devices are virtual Ethernet devices.  They can act as tunnels between network namespaces。topo like below:
     APP                            APP
      |                              |
      |                              |
kernel ------------------------------ kernel 
      |                              |
network stack                  network stack 
      |                              |
        |______________________________|
     veth-m                       veth-n
#
对于此种模式我们普通Linux中是怎么实现呢?
#5.2.1:创建 namespace
ip netns a ns1
ip netns a ns2

#5.2.2:创建一对 veth-pair veth0 veth1
ip l a veth0 type veth peer name veth1

#5.2.3:将 veth0 veth1 分别加入两个 ns
ip l s veth0 netns ns1
ip l s veth1 netns ns2

#5.2.4:给两个 veth0 veth1 配上 IP 并启用
ip netns exec ns1 ip a a 10.1.1.2/24 dev veth0
ip netns exec ns1 ip l s veth0 up

ip netns exec ns2 ip a a 10.1.1.3/24 dev veth1
ip netns exec ns2 ip l s veth1 up

# veth0 ping veth1
[root@k8s-1 ~]# ip netns exec ns1 ping 10.1.1.3
PING 10.1.1.3 (10.1.1.3) 56(84) bytes of data.
64 bytes from 10.1.1.3: icmp_seq=1 ttl=64 time=0.060 ms


/

此时需要弄清楚两个问题:
1.此时如何知道Pod中的eth0的pair是谁?
2.此时由Pod-1进入内核,如果想要把数据包转发给另外一个Pod-2?
#1.使用ethtool -S eth0
[root@k8s-1 ~]# kubectl exec -it cni-59h6g  bash 
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
bash-5.1# ethtool -S eth0
NIC statistics:
     peer_ifindex: 6   ##此时在Pod中查看peer的index为6.我们可以在ROOT NS中查看,ifindex为6的网卡。
     rx_queue_0_xdp_packets: 0
     rx_queue_0_xdp_bytes: 0
     rx_queue_0_drops: 0
     rx_queue_0_xdp_redirect: 0
     rx_queue_0_xdp_drops: 0
     rx_queue_0_xdp_tx: 0
     rx_queue_0_xdp_tx_errors: 0
     tx_queue_0_xdp_xmit: 0
     tx_queue_0_xdp_xmit_errors: 0
bash-5.1# exit
exit
[root@k8s-1 ~]# ip a 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:bd:fb:4a brd ff:ff:ff:ff:ff:ff
    inet 172.12.1.11/24 brd 172.12.1.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::e222:32bb:f400:f0c3/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:da:0c:a5:79 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
4: flannel0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1472 qdisc pfifo_fast state UNKNOWN group default qlen 500
    link/none 
    inet 10.244.0.0/32 brd 10.244.0.0 scope global flannel0
       valid_lft forever preferred_lft forever
    inet6 fe80::9af7:c926:3592:e41f/64 scope link flags 800 
       valid_lft forever preferred_lft forever
5: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1472 qdisc noqueue state UP group default qlen 1000
    link/ether 1e:db:12:e1:c0:79 brd ff:ff:ff:ff:ff:ff
    inet 10.244.0.1/24 brd 10.244.0.255 scope global cni0
       valid_lft forever preferred_lft forever
    inet6 fe80::1cdb:12ff:fee1:c079/64 scope link 
       valid_lft forever preferred_lft forever
6: veth54a9e98a@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1472 qdisc noqueue master cni0 state UP group default   # 这里的ifindex为6.
    link/ether 66:c5:ab:c8:03:4e brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::64c5:abff:fec8:34e/64 scope link 
       valid_lft forever preferred_lft forever
[root@k8s-1 ~]# 
[root@k8s-1 ~]# brctl show 
bridge name     bridge id               STP enabled     interfaces
cni0            8000.1edb12e1c079       no              veth54a9e98a # 此时该接口是在cni0这个bridge上。
docker0         8000.0242da0ca579       no
[root@k8s-1 ~]# 

下边以两个在同一个节点上的两个Pod的情况分析:
# network topo:
10.244.1.10  10.244.1.7
    [ns1]      [ns2]
      |          |
      -- [cni0] --
#
[root@k8s-1 ~]# kubectl get pods -o wide | grep k8s-2
cc          1/1     Running   0          32h    10.244.1.10   k8s-2   <none>           <none>
cni-svtwf   1/1     Running   1          109d   10.244.1.7    k8s-2   <none>           <none>
[root@k8s-1 ~]# 
在pod cni-svtwf中去ping cc这个pod。抓包显示为:
[root@k8s-1 ~]#  kubectl exec -it cni-svtwf  bash 
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
bash-5.1# tcpdump -n -e  -i  eth0      
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
14:31:06.751041 9a:16:45:30:3a:c6 > ee:6f:75:01:ed:bb, ethertype IPv4 (0x0800), length 98: 10.244.1.7 > 10.244.1.10: ICMP echo request, id 17920, seq 0, length 64
14:31:06.751096 ee:6f:75:01:ed:bb > 9a:16:45:30:3a:c6, ethertype IPv4 (0x0800), length 98: 10.244.1.10 > 10.244.1.7: ICMP echo reply, id 17920, seq 0, length 64
^C
#从抓包可以看出,cni-svtwf 的eth0的网卡的MAC地址为:9a:16:45:30:3a:c6
                cc 的eth0的网卡的MAC地址为:ee:6f:75:01:ed:bb
此时我们在cni0 bridge中查看MAC地址表:
[root@k8s-2 ~]# brctl showmacs cni0
port no mac addr                is local?       ageing timer
  1     1e:89:b9:2c:44:b1       yes                0.00
  1     1e:89:b9:2c:44:b1       yes                0.00
  3     32:2e:01:1d:a1:53       yes                0.00
  3     32:2e:01:1d:a1:53       yes                0.00
  2     4a:bc:c1:08:30:04       no                 1.70
  2     5e:14:4c:e2:2b:22       yes                0.00
  2     5e:14:4c:e2:2b:22       yes                0.00
  3     9a:16:45:30:3a:c6       no                32.42   # 此地址对应 cni-svtwf的eht0 MAC地址,对应bridge上的端口3.
  4     b2:8e:21:90:45:39       yes                0.00
  4     b2:8e:21:90:45:39       yes                0.00
  1     ce:22:d7:ee:59:7d       no                 1.70
  4     ee:6f:75:01:ed:bb       no                32.42   # 此地址对应cc 的eth0 的MAC地址,对应bridge上的端口4.
[root@k8s-2 ~]#

#此种Bridge模式把相应的peer建立在pod和bridge之间。此时Linux中又是如何实现呢:
# network topo:
10.1.1.2  10.1.1.3
 [ns1]      [ns2]
   |          |
   -- [br0] --
#
#创建ns
ip netns a ns1
ip netns a ns2
#首先创建 bridge br0
ip l a br0 type bridge
ip l s br0 up 

#然后创建两对 veth-pair
ip l a veth0 type veth peer name br-veth0
ip l a veth1 type veth peer name br-veth1

#分别将两对 veth-pair 加入两个 ns 和 br0
ip l s veth0 netns ns1
ip l s br-veth0 master br0
ip l s br-veth0 up

ip l s veth1 netns ns2
ip l s br-veth1 master br0
ip l s br-veth1 up

#给两个 ns 中的 veth 配置 IP 并启用
ip netns exec ns1 ip a a 10.1.1.2/24 dev veth0
ip netns exec ns1 ip l s veth0 up
ip netns exec ns2 ip a a 10.1.1.3/24 dev veth1
ip netns exec ns2 ip l s veth1 up
# ping 测:
[root@k8s-2 ~]# ip netns exec ns1 ping 10.1.1.3
PING 10.1.1.3 (10.1.1.3) 56(84) bytes of data.
64 bytes from 10.1.1.3: icmp_seq=1 ttl=64 time=0.173 ms
64 bytes from 10.1.1.3: icmp_seq=2 ttl=64 time=0.068 ms
^C
--- 10.1.1.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1020ms
rtt min/avg/max/mdev = 0.068/0.120/0.173/0.053 ms

# 查看bridge br0上的端口:
[root@k8s-2 ~]# brctl show 
bridge name     bridge id               STP enabled     interfaces
br0             8000.8e495ef498dd       no              br-veth0
                                                        br-veth1
# 查看对应的MAC地址和不同ns中的MAC。
[root@k8s-2 ~]# brctl showmacs br0
port no mac addr                is local?       ageing timer
  2     06:b5:78:d9:7b:75       no                16.28      # ns2
  1     1a:7e:30:46:72:11       no                12.18      # ns1
  1     8e:49:5e:f4:98:dd       yes                0.00
  1     8e:49:5e:f4:98:dd       yes                0.00
  2     ca:b6:7e:6:c2:bf       yes                0.00
  2     ca:b6:7e:06:c2:bf       yes                0.00
[root@k8s-2 ~]#

3、Vxlan

# 3.1:VxLAN基础:
RFC定义了VLAN扩展方案VXLAN(Virtual eXtensible Local Area Network,虚拟扩展局域网)。VXLAN采用MAC in UDP(User Datagram Protocol)封装方式,是NVO3(Network Virtualization over Layer 3)中的一种网络虚拟化技术。

服务器虚拟化技术的广泛部署,极大地增加了数据中心的计算密度;同时,为了实现业务的灵活变更,虚拟机VM需要能够在网络中不受限迁移,这给传统的“二层+三层”数据中心网络带来了新的挑战。

虚拟机规模受网络设备表项规格的限制
在传统二层网络环境下,数据报文是通过查询MAC地址表进行二层转发。服务器虚拟化后,VM的数量比原有的物理机发生了数量级的增长,伴随而来的便是VM网卡MAC地址数量的空前增加。而接入侧二层设备的MAC地址表规格较小,无法满足快速增长的VM数量。

网络隔离能力有限
VLAN作为当前主流的网络隔离技术,在标准定义中只有12比特,因此可用的VLAN数量仅4096个。对于公有云或其它大型虚拟化云计算服务这种动辄上万甚至更多租户的场景而言,VLAN的隔离能力无法满足。

虚拟机迁移范围受限
由于服务器资源等问题(如CPU过高,内存不够等),虚拟机迁移已经成为了一个常态性业务。
虚拟机迁移是指将虚拟机从一个物理机迁移到另一个物理机。为了保证虚拟机迁移过程中业务不中断,则需要保证虚拟机的IP地址、MAC地址等参数保持不变,这就要求虚拟机迁移必须发生在一个二层网络中。而传统的二层网络,将虚拟机迁移限制在了一个较小的局部范围内。


为了应对传统数据中心网络对服务器虚拟化技术的限制,VXLAN技术应运而生,其能够很好的解决上述问题。
针对虚拟机规模受设备表项规格限制
VXLAN将管理员规划的同一区域内的VM发出的原始报文封装成新的UDP报文,并使用物理网络的IP和MAC地址作为外层头,这样报文对网络中的其他设备只表现为封装后的参数。因此,极大降低了大二层网络对MAC地址规格的需求。
针对网络隔离能力限制
VXLAN引入了类似VLAN ID的用户标识,称为VXLAN网络标识VNI(VXLAN Network Identifier),由24比特组成,支持多达16M的VXLAN段,有效得解决了云计算中海量租户隔离的问题。
针对虚拟机迁移范围受限
VXLAN将VM发出的原始报文进行封装后通过VXLAN隧道进行传输,隧道两端的VM不需感知传输网络的物理架构。这样,对于具有同一网段IP地址的VM而言,即使其物理位置不在同一个二层网络中,但从逻辑上看,相当于处于同一个二层域。即VXLAN技术在三层网络之上,构建出了一个虚拟的大二层网络,只要虚拟机路由可达,就可以将其规划到同一个大二层网络中。这就解决了虚拟机迁移范围受限问题。

为了解决数据中心网络服务器虚拟化以及虚拟机不受限迁移问题,VXLAN特性应运而生。由于VXLAN特性在本质上属于一种VPN技术,因此,其同样能够应用在园区网络中,以实现分散物理站点之间的二层互联以及站点间的三层互联。

在当前的园区网中,租户站点与站点之间为了实现二、三层互联,需要部署相关设备以及多种二、三层网络技术。而基于Overlay的VXLAN技术,不感知当前的物理网络,能够在任意路由可达的网络上叠加二层虚拟网络,实现站点与站点之间的二层互联。同时,基于VXLAN三层网关,也能够实现站点与站点之间的三层互联。因此,通过VXLAN技术实现租户不同站点之间的互联更加快速、灵活。

4、VxLAN 数据报文结构

02-Kubernetes Flannel VxLAN Mode - 图1

# 一个完整的 vxlan 报文需要哪些信息:

1.内层报文:通信的虚拟机双方要么直接使用 IP 地址,要么通过 DNS 等方式已经获取了对方的 IP 地址,因此网络层地址已经知道。同一个网络的虚拟机需要通信,还需要知道对方虚拟机的 MAC 地址,vxlan 需要一个机制来实现传统网络 ARP 的功能
2.vxlan 头部:只需要知道 VNI,这一般是直接配置在 vtep 上的,要么是提前规划写死的,要么是根据内部报文自动生成的,也不需要担心
3.UDP 头部:最重要的是源地址和目的地址的端口,源地址端口是系统生成并管理的,目的端口也是写死的,比如 IANA 规定的 4789 端口,这部分也不需要担心
4.IP 头部:IP 头部关心的是 vtep 双方的 IP 地址,源地址可以很简单确定,目的地址是虚拟机所在地址宿主机 vtep 的 IP 地址,这个也需要由某种方式来确定
5.MAC 头部:如果 vtep 的 IP 地址确定了,MAC 地址可以通过经典的 ARP 方式来获取,毕竟 vtep 网络在同一个三层,经典网络架构那一套就能直接用了

5、点对点Vxlan模型

02-Kubernetes Flannel VxLAN Mode - 图2

# 点对点VxLAN实现过程:
# node k8s-1:
ip link add vxlan0 type vxlan id 5 dstport 4789 remote 172.12.1.12 local 172.12.1.11 dev ens33
ip addr add 10.20.1.2/24 dev vxlan0
ip link set vxlan0 up
# node k8s-2:
ip link add vxlan0 type vxlan id 5 dstport 4789 remote 172.12.1.11 local 172.12.1.12 dev ens33
ip addr add 10.20.1.3/24 dev vxlan0
ip link set vxlan0 up

# 语句解释:
ip link add vxlan0 type vxlan id 5 dstport 4789 remote 172.12.1.11 local 172.12.1.12 dev ens33 
ip l a xx type xx 。这里我们看到的是:添加一个接口vxlan0,它的类型为vxlan。
ip addr add 10.20.1.3/24 dev vxlan0   # 为vxlan0接口配置ip地址。
ip link set vxlan0 up  # 设置其端口启动。

# Packet Flow:
network topo:

env:使用k8s-1节点上vxlan0接口:10.20.1.2去pingk8s-2节点上的vxlan0接口:10.20.1.3
# 1.首先数据包会由k8s-1-vxlan0网卡构建,此时S_IP,S_MAC,D_IP均有,但是D_MAC暂时没有。所以需要查询10.20.1.3对应的MAC地址。
  10.20.1.2    10.20.1.3
   [vxlan0]    [vxlan0]
      |           |
       -- [SW] --
此时需要发送ARP来查询D_IP对应的MAC地址:
所以需要发送ARP查询:
在k8s-1上的vxlan0接口抓包:
No.     Time                          Source                Destination           Protocol Length Info
1       2021-07-26 16:06:37.586009    6a:c4:14:76:29:f7     Broadcast             ARP      42     Who has 10.20.1.3? Tell 10.20.1.2       # ARP Request

Frame 1: 42 bytes on wire (336 bits), 42 bytes captured (336 bits)
Ethernet II, Src: 6a:c4:14:76:29:f7 (6a:c4:14:76:29:f7), Dst: Broadcast (ff:ff:ff:ff:ff:ff)
Address Resolution Protocol (request)

No.     Time                          Source                Destination           Protocol Length Info
2       2021-07-26 16:06:37.586523    a2:7e:68:70:57:a3     6a:c4:14:76:29:f7     ARP      42     10.20.1.3 is at a2:7e:68:70:57:a3       # ARP Replay

Frame 2: 42 bytes on wire (336 bits), 42 bytes captured (336 bits)
Ethernet II, Src: a2:7e:68:70:57:a3 (a2:7e:68:70:57:a3), Dst: 6a:c4:14:76:29:f7 (6a:c4:14:76:29:f7)
Address Resolution Protocol (reply)
# capture on vxlan0 ICMP Request and Replay
No.     Time                          Source                Destination           Protocol Length Info
3       2021-07-26 16:06:37.586595    10.20.1.2             10.20.1.3             ICMP     98     Echo (ping) request  id=0x6da4, seq=1/256, ttl=64 (reply in 4)

Frame 3: 98 bytes on wire (784 bits), 98 bytes captured (784 bits)
Ethernet II, Src: 6a:c4:14:76:29:f7 (6a:c4:14:76:29:f7), Dst: a2:7e:68:70:57:a3 (a2:7e:68:70:57:a3)
Internet Protocol Version 4, Src: 10.20.1.2, Dst: 10.20.1.3
Internet Control Message Protocol

No.     Time                          Source                Destination           Protocol Length Info
4       2021-07-26 16:06:37.587002    10.20.1.3             10.20.1.2             ICMP     98     Echo (ping) reply    id=0x6da4, seq=1/256, ttl=64 (request in 3)

Frame 4: 98 bytes on wire (784 bits), 98 bytes captured (784 bits)
Ethernet II, Src: a2:7e:68:70:57:a3 (a2:7e:68:70:57:a3), Dst: 6a:c4:14:76:29:f7 (6a:c4:14:76:29:f7)
Internet Protocol Version 4, Src: 10.20.1.3, Dst: 10.20.1.2
Internet Control Message Protocol

此时在k8s-1的vxlan0接口上抓包,我们可以看到,由于10.20.1.2和10.10.1.3的属于同一个网段,所以直接发出ARP的查询:
No.     Time                          Source                Destination           Protocol Length Info
1       2021-07-26 16:06:37.586009    6a:c4:14:76:29:f7     Broadcast             ARP      42     Who has 10.20.1.3? Tell 10.20.1.2       # ARP Request
2       2021-07-26 16:06:37.586523    a2:7e:68:70:57:a3     6a:c4:14:76:29:f7     ARP      42     10.20.1.3 is at a2:7e:68:70:57:a3       # ARP Replay

# 此时这里需要注意的是:由于vxlan0这个接口是一个type我vxlan的设备,所以此时数据包会按照我们的配置为这个数据包打上VxLAN的信息:
ip link add vxlan0 type vxlan id 5 dstport 4789 remote 172.12.1.12 local 172.12.1.11 dev ens33   # VxlAN使用端口4789,点对点的remote是172.12.1.12,而local是172.12.1.11
所以此时封装应该是
Inner_S_IP://///////   Inner_S_MAC: 6a:c4:14:76:29:f7  Outer_S_IP:172.12.1.11 Outer_S_MAC:00:0c:29:bd:fb:4a
Inner_D_IP://///////   Inner_D_MAC: ff:ff:ff:ff:ff:ff  Outer_D_IP:172.12.1.12 Outer_D_MAC:00:0c:29:e2:bf:86
# 抓包显示为:
No.     Time                          Source                Destination           Protocol Length Info
11      2021-07-26 13:21:55.782996    6a:c4:14:76:29:f7     Broadcast             ARP      92     Who has 10.20.1.3? Tell 10.20.1.2

Frame 11: 92 bytes on wire (736 bits), 92 bytes captured (736 bits)
Ethernet II, Src: Vmware_bd:fb:4a (00:0c:29:bd:fb:4a), Dst: Vmware_e2:bf:86 (00:0c:29:e2:bf:86)           # Outer_S_MAC:00:0c:29:bd:fb:4a Outer_D_MAC:00:0c:29:e2:bf:86
Internet Protocol Version 4, Src: 172.12.1.11, Dst: 172.12.1.12                                           # Outer_S_IP: 172.12.1.11       Outer_D_IP: 172.12.1.12
User Datagram Protocol, Src Port: 60935, Dst Port: 4789                                                   # VxLAN Port
Virtual eXtensible Local Area Network                                                                     # VxLAN Info
Ethernet II, Src: 6a:c4:14:76:29:f7 (6a:c4:14:76:29:f7), Dst: Broadcast (ff:ff:ff:ff:ff:ff)               # Inner_S_MAC: 6a:c4:14:76:29:f7 Inner_D_MAC: ff:ff:ff:ff:ff:ff
Address Resolution Protocol (request)

No.     Time                          Source                Destination           Protocol Length Info
14      2021-07-26 13:21:55.783336    a2:7e:68:70:57:a3     6a:c4:14:76:29:f7     ARP      92     10.20.1.3 is at a2:7e:68:70:57:a3

Frame 14: 92 bytes on wire (736 bits), 92 bytes captured (736 bits)
Ethernet II, Src: Vmware_e2:bf:86 (00:0c:29:e2:bf:86), Dst: Vmware_bd:fb:4a (00:0c:29:bd:fb:4a)
Internet Protocol Version 4, Src: 172.12.1.12, Dst: 172.12.1.11
User Datagram Protocol, Src Port: 55876, Dst Port: 4789
Virtual eXtensible Local Area Network
Ethernet II, Src: a2:7e:68:70:57:a3 (a2:7e:68:70:57:a3), Dst: 6a:c4:14:76:29:f7 (6a:c4:14:76:29:f7)       # Inner_S_MAC: a2:7e:68:70:57:a3 Inner_D_MAC: 6a:c4:14:76:29:f7 {ARP Response}
Address Resolution Protocol (reply)
# capture on ens33 ICMP Request and Replay
No.     Time                          Source                Destination           Protocol Length Info
15      2021-07-26 13:21:55.783387    10.20.1.2             10.20.1.3             ICMP     148    Echo (ping) request  id=0x62cd, seq=1/256, ttl=64 (reply in 16)  # ICMP Reauest

Frame 15: 148 bytes on wire (1184 bits), 148 bytes captured (1184 bits)
Ethernet II, Src: Vmware_bd:fb:4a (00:0c:29:bd:fb:4a), Dst: Vmware_e2:bf:86 (00:0c:29:e2:bf:86)
Internet Protocol Version 4, Src: 172.12.1.11, Dst: 172.12.1.12
User Datagram Protocol, Src Port: 55473, Dst Port: 4789
Virtual eXtensible Local Area Network
Ethernet II, Src: 6a:c4:14:76:29:f7 (6a:c4:14:76:29:f7), Dst: a2:7e:68:70:57:a3 (a2:7e:68:70:57:a3)
Internet Protocol Version 4, Src: 10.20.1.2, Dst: 10.20.1.3
Internet Control Message Protocol

No.     Time                          Source                Destination           Protocol Length Info
16      2021-07-26 13:21:55.783655    10.20.1.3             10.20.1.2             ICMP     148    Echo (ping) reply    id=0x62cd, seq=1/256, ttl=64 (request in 15)  # ICMP Response

Frame 16: 148 bytes on wire (1184 bits), 148 bytes captured (1184 bits)
Ethernet II, Src: Vmware_e2:bf:86 (00:0c:29:e2:bf:86), Dst: Vmware_bd:fb:4a (00:0c:29:bd:fb:4a)
Internet Protocol Version 4, Src: 172.12.1.12, Dst: 172.12.1.11
User Datagram Protocol, Src Port: 48531, Dst Port: 4789
Virtual eXtensible Local Area Network
Ethernet II, Src: a2:7e:68:70:57:a3 (a2:7e:68:70:57:a3), Dst: 6a:c4:14:76:29:f7 (6a:c4:14:76:29:f7)
Internet Protocol Version 4, Src: 10.20.1.3, Dst: 10.20.1.2
Internet Control Message Protocol

6、Muticase VxLAN模型

image.png

# muticast vxlan配置:
# k8s-1
ip link add vxlan0 type vxlan id 6 dstport 4789 group 239.1.1.1 dev ens33
ip addr add 10.20.1.2/24 dev vxlan0
ip link set vxlan0 up

# k8s-2
ip link add vxlan0 type vxlan id 6 dstport 4789 group 239.1.1.1 dev ens33
ip addr add 10.20.1.3/24 dev vxlan0
ip link set vxlan0 up

ip link add vxlan0 type vxlan id 6 dstport 4789 group 239.1.1.1 dev ens33
这里最重要的参数是 group 239.1.1.1 表示把 vtep 加入到这个多播组。关于多播的原理和使用不是这篇文章的重点,这里选择的多播 IP 地址也没有特殊的含义,关于多播的内容可以自行了解。
分析这个模式下 vxlan 通信的过程:

在配置完成之后,vtep 通过 IGMP 加入同一个多播网络 239.1.1.1。

1.发送 ping 报文到 10.20.1.3,查看路由表,报文会从 vxlan0 发出去
2.内核发现 vxlan0 的 IP 是 10.20.1.2/24,和目的 IP 在同一个网段,所以在同一个局域网,需要知道对方的 MAC 地址,因此会发送 ARP 报文查询
3.ARP 报文源 MAC 地址为 vxlan0 的 MAC 地址,目的 MAC 地址为全 1 的广播地址
4.vxlan 根据配置(VNI 6)添加上头部
5.因为不知道对方 vtep 在哪台主机上,根据配置,vtep 会往多播地址 239.1.1.1 发送多播报文
6.多播组中所有的主机都会受到这个报文,内核发现是 vxlan 报文,会根据 VNI 发送给对应的 vtep
7.vtep 去掉 vxlan 头部,取出真正的 ARP 请求报文。同时 vtep 会记录 <源 MAC 地址 - vtep 所在主机 IP 地址> 信息到 fdb 表中
8.如果发现 ARP 不是发送给自己的,直接丢弃;如果是发送给自己的,则生成 ARP 应答报文
9.应答报文目的 MAC 地址是发送方 vtep 的 MAC 地址,而且 vtep 已经通过源报文学习到了 vtep 所在的主机,因此会直接单播发送给目的 vtep。因此 vtep 不需要多播,就能填充所有的头部信息
10.应答报文通过 underlay 网络直接返回给发送方主机,发送方主机根据 VNI 把报文转发给 vtep,vtep 解包取出 ARP 应答报文,添加 arp 缓存到内核。并根据报文学习到目的 vtep 所在的主机地址,添加到 fdb 表中
11.vtep 已经知道了通信需要的所有信息,后续 ICMP 的 ping 报文都是单播进行的