基于Linux的点对点VXLAN通信

一卷旌收千骑虏,万全身出百重围。这篇文章主要讲述基于Linux的点对点VXLAN通信相关的知识,希望能为你提供帮助。
一、VXLAN基本概念VXLAN是NVOS3中的一种网络虚拟化技术,通过将虚拟机发出的数据包封装在UDP报文中,并使用物理网络中宿主机的IP地址以及MAC地址作为outer-header进行封装,然后在传统的IP网络中进行传输,到达目的地后由隧道接点解封装并将数据发送给目标虚拟机。
通过VXLAN,虚拟网络可接入大量租户,且租户可以规划自己的虚拟网络,不需要考虑物理网络IP地址和广播域的限制,降低了网络管理的难度。
1.1 Underlay网络和Overlay网络
VXLAN技术将已有的宿主机所在的物理网络作为Underlay网络,在其上构建出虚拟的二层或三层网络,即Overlay网络。Overlay网络通过封装技术、利用Underlay网络提供的三层转发路径,实现租户报文在不同站点间传递。对于租户来说,Underlay网络是透明的,只能感知到Overlay网络。
1.2 NVE(Network Virtualization Edge)
网络虚拟边缘节点NVE,实现网络虚拟化功能的网络实体。报文经过NVE封装转发后,NVE间就可基于三层基础网络建立二层虚拟化网络。
?说明?:设备和服务器上的虚拟交换机VSwitch都可以作为NVE。
按照NVE部署位置的不同,可以分为以下三种模式:

  • 硬件模式:所有的NVE都部署在支持NVE的设备上,所有的VXLAN报文封装与解封装都在设备上进行。
  • 软件模式:所有的NVE都部署在VSwitch上,所有的VXLAN报文封装与解封装都在VSwitch上进行。
  • 混合模式:部分NVE部署在VSwitch上,部分NVE部署在支持NVE的设备上,在VSwitch和设备上都有可能会进行VXLAN报文的封装与解封装。
1.3 VTEP(VXLAN Tunnel Endpoints)
VTEP是VXLAN隧道端点,封装在NVE中,用于VXLAN报文的封装和解封装。
VTEP与物理网络相连,分配有物理网络的IP地址,该地址与虚拟网络无关。
VXLAN报文中源IP地址为本节点的VTEP地址,VXLAN报文中目的IP地址为对端节点的VTEP地址,一对VTEP地址就对应着一个VXLAN隧道。
1.4 VNI(VXLAN Network Identifier)
VXLAN网络标识VNI类似VLAN ID,用于区分VXLAN段,不同VXLAN段的虚拟机不能直接二层相互通信。
一个VNI表示一个租户,即使多个终端用户属于同一个VNI,也表示一个租户。VNI由24比特组成,支持多达16M的租户。
在分布式网关部署场景下,VNI分为二层VNI和三层VNI。
  • 二层VNI是普通的VNI,以1:1方式映射到广播BD,实现VXLAN报文同子网的转发。
  • 三层VNI和VPN实例进行关联,用于VXLAN报文跨子网的转发。
二、VXLAN报文格式2.1 报文格式
VXLAN是MAC in UDP的网络虚拟化技术,所以其报文封装是在原始以太网报文之前添加了一个UDP封装及VXLAN头封装。具体报文格式如图所示:

2.2 报文格式说明
字段
描述
VXLAN header
  • VXLAN Flags:8比特,取值为000010000。
  • VNI:VXLAN网络标识,24比特,用于区分VXLAN段。
  • Reserved:24比特和8比特,必须设置为0。
Outer UDP header
  • DestPort:目的UDP端口号是4789。
  • Source Port:源端口号是内层报文通过哈希算法计算后的值。
Outer IP header
  • IP SA:源IP地址是VXLAN隧道本端VTEP的IP地址。
  • IP DA:目标IP地址是VXLAN隧道远端VTEP的IP地址。
如果Underlay网络为IPv4网络,VTEP IP为IPv4类型;如果Underlay网络为IPv6网络,VTEP IP为IPv6类型
Outer Ethernet header
  • MAC DA:在发送报文的虚拟机所属VTEP上根据目的VTEP地址查找路由表,路由表中下一跳IP地址对应的MAC地址。
  • MAC SA:发送报文的虚拟机所属的VTEP的MAC地址。
  • 802.1Q Tag:可选字段,该字段为报文中携带的VLAN Tag。
  • Ethernet Type:以太网报文类型。
三、基于Linux的点对点VXLAN通信实验3.1 实验逻辑拓扑

3.2 实验目的
两台主机之间的ns1 namespace和ns2 namespace之间通过VXLAN相互通讯。
描述网络架构图(包的构成和转发依据)
3.3 实验步骤
3.3.1 关闭防火墙
vxlan-server1:
[root@vxlan-server1 ~]#systemctl disable --now firewalld.service
vxlan-server2:
[root@vxlan-server2 ~]#systemctl disable --now firewalld.service

3.3.2 创建VXLAN设备,并配置IP
vxlan-server1:
[root@vxlan-server1 ~]#ip link add vxlan1 type vxlan id 100 \\
dstport 4789 remote 172.31.0.17 local 172.31.0.7 dev eth0
vxlan-server2:
[root@vxlan-server2 ~]#ip link add vxlan2 type vxlan id 100 \\
dstport 4789 remote 172.31.0.7 local 172.31.0.17 dev eth0

3.3.2.1 参数解释
  • id 100:指定VNI的值,有效值在1到2^24之间。
  • dstport 4789:VTEP通信的端口,IANA分配的端口是4789。如果不指定,Linux默认使用8472。ovs创建的VXLAN port也是默认使用端口4789。
  • remote:对端VTEP的地址。
  • local:当前节点VTEP要是用的IP地址,即当前节点隧道口的IP地址。
  • dev eth0:当前节点用于VTEP通信的设备,用来获取VTEP IP地址。这个参数与local参数目的相同,二选一即可。
3.3.2.2 查看VXLAN的详细信息
vxlan-server1:
[root@vxlan-server1 ~]#ip -d link show vxlan1
3: vxlan1: < BROADCAST,MULTICAST> mtu 1450 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 8a:cf:54:54:26:9e brd ff:ff:ff:ff:ff:ff promiscuity 0
vxlan id 100 remote 172.31.0.17 local 172.31.0.7 dev eth0 srcport 0 0 dstport 4789 ageing 300 noudpcsum noudp6zerocsumtx noudp6zerocsumrx addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
vxlan-server2:
[root@vxlan-server2 ~]#ip -d link show vxlan2
3: vxlan2: < BROADCAST,MULTICAST> mtu 1450 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether c6:93:97:8a:58:cf brd ff:ff:ff:ff:ff:ff promiscuity 0
vxlan id 100 remote 172.31.0.7 local 172.31.0.17 dev eth0 srcport 0 0 dstport 4789 ageing 300 noudpcsum noudp6zerocsumtx noudp6zerocsumrx addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535

3.3.2.3 同时会增加一条fdb转发表
vxlan-server1:
[root@vxlan-server1 ~]#bridge fdb
01:00:5e:00:00:01 dev eth0 self permanent
00:00:00:00:00:00 dev vxlan1 dst 172.31.0.17 via eth0 self permanent
vxlan-server2:
[root@vxlan-server2 ~]#bridge fdb
01:00:5e:00:00:01 dev eth0 self permanent
33:33:00:00:00:01 dev eth0 self permanent
00:00:00:00:00:00 dev vxlan2 dst 172.31.0.7 via eth0 self permanent

?注?:全零表项表示没有匹配的MAC地址时,就发送到该表项中的VTEP。这条表项的意思是,默认的VTEP对端地址为172.31.0.17,原始报文经过VXLAN1后会添加VXLAN头部,而外部UDP头的目的IP地址会被加上172.31.0.17。
3.3.2.4 为VXLAN1配置IP地址并启用
vxlan-server1:
[root@vxlan-server1 ~]#ip link set dev vxlan1 up
[root@vxlan-server1 ~]#ip addr add 192.168.1.254/32 dev vxlan1
vxlan-server2:
[root@vxlan-server2 ~]#ip link set dev vxlan2 up
[root@vxlan-server2 ~]#ip addr add 192.168.2.254/32 dev vxlan2

3.3.2.5 创建bridge,并设置IP
vxlan-server1:
[root@vxlan-server1 ~]#brctl addbr br1
[root@vxlan-server1 ~]#ip link set dev br1 up
[root@vxlan-server1 ~]#ip addr add 192.168.1.1/24 dev br1
vxlan-server2:
[root@vxlan-server2 ~]#brctl addbr br1
[root@vxlan-server2 ~]#ip link set dev br1 up
[root@vxlan-server2 ~]#ip addr add 192.168.2.1/24 dev br1

3.3.2.6 创建namespace,VTEP peer,各自加入ns1和br1,并配置IP
vxlan-server1:
[root@vxlan-server1 ~]#ip netns add ns1
[root@vxlan-server1 ~]#ip link add tap1 type veth peer name tap2
[root@vxlan-server1 ~]#ip link set dev tap2 up
[root@vxlan-server1 ~]#ip link set tap1 netns ns1
[root@vxlan-server1 ~]#ip netns exec ns1 ip link set dev tap1 up
[root@vxlan-server1 ~]#ip netns exec ns1 ip addr add \\
192.168.1.100/24 dev tap1
[root@vxlan-server1 ~]#brctl addif br1 tap2
vxlan-server2:
[root@vxlan-server2 ~]#ip netns add ns2
[root@vxlan-server2 ~]#ip link add tap1 type veth peer name tap2
[root@vxlan-server2 ~]#ip link set dev tap2 up
[root@vxlan-server2 ~]#ip link set tap1 netns ns2
[root@vxlan-server2 ~]#ip netns exec ns2 ip link set dev tap1 up
[root@vxlan-server2 ~]#ip netns exec ns2 ip addr add \\
192.168.2.100/24 dev tap1
[root@vxlan-server2 ~]#brctl addif br1 tap2

3.3.2.7 系统网络内核参数修改
vxlan-server1:
[root@vxlan-server1 ~]#echo 0 > \\
/proc/sys/net/ipv4/conf/all/rp_filter
[root@vxlan-server1 ~]#echo 0 > \\
/proc/sys/net/ipv4/conf/br1/rp_filter
[root@vxlan-server1 ~]#echo 1 > /proc/sys/net/ipv4/ip_forward
vxlan-server2:
[root@vxlan-server2 ~]#echo 0 > \\
/proc/sys/net/ipv4/conf/all/rp_filter
[root@vxlan-server2 ~]#echo 0 > \\
/proc/sys/net/ipv4/conf/br1/rp_filter
[root@vxlan-server2 ~]#echo 1 > /proc/sys/net/ipv4/ip_forward

3.3.2.8 配置路由
vxlan-server1:
[root@vxlan-server1 ~]#ip netns exec ns1 ip route add default via 192.168.1.1

问题:
将ns1的网关指向VXLAN1的IP地址(192.168.1.254),此时ns1和ns2的通信也是正常的,但在ns上查看192.168.1.254学到的MAC地址为br1的MAC地址?


本接口收到的arp请求,要把自己的mac回给请求者。
否则后续报文的目的mac是别人的,本接口收到后会丢弃。
[root@vxlan-server1 ~]#ip route add 192.168.2.0/24 via \\
192.168.2.254 dev vxlan1 onlink
vxlan-server2:
[root@vxlan-server2 ~]#ip netns exec ns2 ip route add default via 192.168.2.1
[root@vxlan-server2 ~]#ip route add 192.168.1.0/24 via \\
192.168.1.254 dev vxlan2 onlink
注:若不设置onlink,会提示network is unreachable。onlink的意义在于协议栈虽然找不到链路层直连路由,但是还是会发布针对via网关的ARP请求的。

3.3.2.9 状态截图vxlan-server1:


vxlan-server2:


3.3.3 点对点VXLAN通信过程主机1的ns1向主机2的ns2发送ICMP数据包,通信结果如图所示:

3.3.3.1 ns1发送ARP报文当ns1中的tap1网卡去ping另一台主机的ns2中的网卡192.168.2.100时,夸网段访问会将请求发送给网关,先发送ARP请求获取网关192.168.1.1的MAC地址。
ARP请求报文:
Sender IP:192.168.1.100
Sender MAC:a6:15:75:51:38:cc
Target IP:192.168.1.1
Target MAC:全0
以太二层封装:
Source MAC:a6:15:75:51:38:cc
Destination MAC:全F
报文如图所示:

ARP广播请求报文会通过tap1--> tap2到达宿主机,本机MAC地址表会学习并记录该报文的源MAC和接收接口的对应关系。

3.3.3.2 br1单播响应ns1收到该ARP广播请求,解封装之后查看ARP请求的IP地址是本地的,那么构建ARP单播响应,根据先学习记录的对应MAC表项出接口是br1设备上的tap2口到达ns1。
ARP响应报文:
Sender IP:192.168.1.1
Sender MAC:7a:06:cd:1d:69:e5
Target IP:192.168.1.100
Target MAC:a6:15:75:51:38:cc
以太二层封装:
Source MAC:7a:06:cd:1d:69:e5(192.168.1.1网关的MAC地址)
Destination MAC:a6:15:75:51:38:cc(192.168.1.100的MAC地址)
报文如图所示:

3.3.3.3 ns1缓存网关ARPns1收到网关的ARP响应之后,缓存到本地

3.3.3.4 ns1构建ICMP的请求报文Source IP:192.168.1.100
Destination IP:192.168.2.100
Source MAC:a6:15:75:51:38:cc
Destination MAC:7a:06:cd:1d:69:e5
报文如图所示:

ICMP请求报文通过tap1--> tap2设备从ns1到达宿主机1时也就是到达默认的namespace时
1) 查看报文目的MAC是本机的br1设备的MAC,解封装拆掉二层帧头,露出IP报文。
2) (br设备的MAC地址是它所有从设备中最小的MAC地址),在这里br1设备只有一个从设备tap2,所以br1的MAC和tap2的MAC一致。

3.3.3.5 br1查询宿主机路由表主机1的br1发现报文访问的是192.168.2.100,与本地不是同一网段,查看宿主机(default namespace)路由表,匹配路由,发现去往192.168.2.0/24的下一跳为192.168.2.254,出接口为VXLAN1

为什么没有抓到br1到VXLAN1的ARP报文,以及ICMP报文从br1到VXLAN1的转发过程?
因为这个过程是在Linux内部协议栈进行处理完成的。
3.3.3.6 VXLAN1发送ARP报文不是发往本机的,需要判断本机是否开启了路由转发功能,如果开启则发送ARP请求192.168.2.254的MAC地址,出接口是VXLAN1,需要进行VXLAN封装,会使用出接口的IP,MAC作为报文的源地址。
宿主机1的VXLAN1的抓包截图,VXLAN接口抓到的包是为封装之前或解封装之后的报文:

宿主机1的eth0网卡抓包截图,此时的报文是VXLAN封装之后的报文:

原始ARP请求报文:
  Send MAC:be:cf:4d:87:f1:f8
  Send IP:192.168.1.254
  Target MAC:全0
  Target IP:192.168.2.254
内层以太层帧:
  Source MAC:be:cf:4d:87:f1:f8
  Source MAC:全F
VXLAN封装:
  VNI:100
UDP封装:
  Source port:39795(随机端口号)
Destination port:4789
外层VTEP IP封装:
  Source IP:172.31.0.7
  Destination IP:172.31.0.17
外层以太二层帧:
  Source MAC:本端VTEP(宿主机1的eth0)接口的MAC
  Destination MAC:对端VTEP(宿主机2的eth0)接口的MAC
原始ARP请求报文VXLAN封装前:

原始ARP请求报文VXLAN封装后:

主机2有一条fdb表项:
00:00:00:00:00:00 dev vxlan2 dst 172.31.0.7 via eth0 self permanent是否会直接从host2的vxlan2接口发出,再进入隧道,形成环路
抓包来看是没有环路的,为什么不根据这条fdb表项转发
VETP解封装后根据UDP 4789端口号,发给vxlan进程,进程对报文做解析,知道vxlan2接口,vxlan2接口会收到数据包
水平分割防环,不会再从vxlan2接口发出
报文到达主机2,进行解封装,在主机2的VXLAN2抓取报文。VXLAN2接口这里的报文是已经解封装之后的报文。

根据原始ARP广播报文发现(主机本地fdb mac地址表会记录该广播包的源MAC和接入口绑定)请求的是本机的192.168.2.254的MAC,构建ARP单播响应,目的MAC是be:cf:4d:87:f1:f8,源MAC是f6:8e:cd:3c:8b:1a。根据fdb转发表查看发给be:cf:4d:87:f1:f8这MAC表项出接口是VXLAN2。三层路由出接口和二层的出接口必须一致,三层路由表项和二层转发项都得有,不然会不通(两个表都会查)。

3.3.3.7 VXLAN2响应VXLAN1的ARP报文ARP单播响应也会进行VXLAN封装:

主机1的VXLAN1接口收到主机2的VXLAN2发过来的ARP单播响应报文之后,将其VXLAN2的MAC地址记录到fdb表,如图所示:

3.3.3.8 主机1发送并进行封装ICMP报文主机1收到主机2的VXLAN2的ARP响应之后,开始构建发送ICMP请求报文。
根据三层路由表和fdb转发表得知发往f6:8e:cd:3c:8b:1a这个MAC的数据包需要走VXLAN1通道,进行VXLAN封装:


ICMP报文:
内层IP封装:
  Source IP:192.168.1.100
  Destination IP:192.168.2.100
内层MAC封装:
  Source MAC:be:cf:4d:87:f1:f8(宿主机1的VXLAN1的MAC)
  Destination MAC:f6:8e:cd:3c:8b:1a(宿主机2的VXLAN2的MAC)
VXLAN封装:
  VNI:100
UDP封装:
  Source Port:53918(随机端口号)
  Destination Port:4789
外层VTEP IP地址封装:
  Source IP:172.31.0.7
  Destination IP:172.31.0.17
外层VTEP MAC地址封装:
  Source MAC:00:0c:29:cb:6a:88(宿主机1的eth0接口MAC)
  Destination MAC:00:0c:29:57:d0:06(宿主机2的eth接口MAC)

3.3.3.9 主机2接收并解封装主机1的ICMP报文 VXLAN封装的ICMP请求报文到达主机2的VTEP设备,解封之后二层目的MAC是VXLAN2设备的MAC(192.168.2.254/32)。

ICMP报文:
IP封装:
  Source IP:192.168.1.100
  Destination IP:192.168.2.100
MAC封装:
  Source MAC:be:cf:4d:87:f1:f8(宿主机1的VXLAN1的MAC)
  Destination MAC:f6:8e:cd:3c:8b:1a(宿主机2的VXLAN2的MAC)
3.3.3.10 主机2的VXLAN2查询路由发现原始报文访问的是192.168.2.100,与本地不是同一网段(VXLAN设备32位主机路由),查找路由表发现去往192.168.2.0/24网段的出接口是br1,于是将ICMP请求报文转发给br1。

这里抓不到VXLAN2到主机2br1的报文,因为这个过程是在Linux内部协议栈进行处理完成的。
3.3.3.11 主机2的br1发送ARP报文当主机2的br1接口收到VXLAN2发过来的ICMP报文,发现报文中目标IP地址是192.168.2.100(ns2的IP地址),此时主机2的fdb表中并没有ns2的MAC地址,因此使用192.168.2.1作为广播源,ARP广播请求192.168.2.100的MAC。

3.3.3.12 主机2的ns2单播报文响应br1ns2的tap1网卡收到ARP请求会返回ARP响应。
8a:e2:90:0b:08:54--> br1 192.168.2.1网关的MAC

3.3.3.13 主机2的ns2接收ICMP报文主机2得到ns2的MAC地址之后,构建ICMP报文,目的MAC是192.168.2.100的MAC地址,根据fdb转发表将数据从br1网桥的tap2接口转发出去,最终ns2中的tap1网卡会受到请求包。

报文封装如下:
ICMP报文:
IP封装:
  Source IP:192.168.1.100
  Destination IP:192.168.2.100
内层以太二层封装:
  Source MAC:56:ab:6c:f2:c1:78(主机2 br1设备的MAC地址)
  Destination MAC:8a:e2:90:0b:08:54(ns2的tap1的MAC地址)

回包的流程逻辑与以上过程基本一致。
【基于Linux的点对点VXLAN通信】至此VXLAN的相关知识就先介绍这么多,文章写得有不恰当之处,恳请斧正。

    推荐阅读