VXLAN的全称为Virtual eXtensible LAN,从名称看,它的目标就是扩展VLAN协议。802.1Q的VLAN TAG只占12位,只能提供4096个网络标识符。而在VXLAN中,标识符扩展到24位,能提供16777216个逻辑网络标识符,VXLAN的标识符称为VNI(VXLAN Network Identifier)。另外,VLAN只能应用在一个二层网络中,而VXLAN通过将原始二层以太网帧封装在IP协议包中,在IP基础网络之上构建overlay的逻辑大二层网络。

我们来看具体协议包结构。VXLAN将二层数据帧封装在UDP数据包中,构建隧道在不同节点间通信。包结构如图:

从包结构上可以看到,VXLAN会额外消耗50字节的空间。为了防止因数据包大小超过网络设备的MTU值而被丢弃,需要将VM的MTU减少50甚至更多,或者调整中间网络设备的MTU。

VXLAN协议中将对原始数据包进行封装和解封装的设备称为VTEP(VXLAN Tunnel End Point),它可以由硬件设备实现,也可以由软件实现。

VXLAN的整体应用示意拓朴结构如图:

我们来看VXLAN的通信过程。在上图的虚拟机VM1和VM2处于逻辑二层网络中。VM1发出的二层以太网帧由VTEP封装进IP数据包,之后发送到VM2所在主机。VM2所在主机接收到IP报文后,解封装出原始的以太网帧再转发给VM2。然而,VM1所在主机的VTEP做完数据封装后,如何知道要将封装后的数据包发到哪个VTEP呢?实际上,VTEP通过查询转发表来确定目标VTEP地址,而转发表通过泛洪和学习机制来构建。目标MAC地址在转发表中不存在的流量称为未知单播(Unknown unicast)。广播(broadcast)、未知单播(unknown unicast)和组播(multicast)一般统称为BUM流量。 VXLAN规范要求BUM流量使用IP组播进行洪泛,将数据包发送到除源VTEP外的所有VTEP。目标VTEP发送回响应数据包时,源VTEP从中学习MAC地址、VNI和VTEP的映射关系,并添加到转发表中。后续VTEP再次发送数据包给该MAC地址时,VTEP会从转发表中直接确定目标VTEP,从而只发送单播数据到目标VTEP。

OpenvSwitch没有实现IP组播,而是使用多个单播来实现洪泛。洪泛流量本身对性能有一定影响,可以通过由controller收集相应信息来填充转发表而避免洪泛。

Linux环境中常用的VXLAN实现有两种:

  • Linux内核实现
  • OpenvSwitch实现

接下来分别以实例来说明。

首先看Linux内核实现实例。我们的测试环境有三台主机,物理网卡IP分别为192.168.33.12/24, 192.168.33.13/24和192.168.33.14/24。我们在每台机器上创建一个Linux Bridge, 三台主机上的Linux Bridge默认接口的IP分别设置为10.1.1.2/24, 10.1.1.3/24和10.1.1.4/24。此时三台主机的Linux网桥处于同一虚拟二层网络,但由于没有相互连接,所以无法互相访问。我们通过建立VXLAN隧道使其可互相访问实现虚拟二层网络10.1.1.0/24。网络结构如图:

首先在主机1上创建Linux网桥:

brctl addbr br0

给网桥接口设置IP并启动:

ip addr add 10.1.1.2/24 dev br0
ip link set up br0

我们从主机1访问主机2上的虚拟二层网络IP, 访问失败:

[root@localhost vagrant]# ping 10.1.1.3
PING 10.1.1.3 (10.1.1.3): 56 data bytes
^C
--- 10.1.1.3 ping statistics ---
1 packets transmitted, 0 packets received, 100.0% packet loss

接下来,我们添加VTEP虚拟接口vxlan0, 并加入组播IP:239.1.1.1, 后续发送到该组播IP的数据包,该VTEP都可以接收到:

ip link add vxlan0 type vxlan id 1 group 239.1.1.1 dev eth1 dstport 4789

将虚拟接口vxlan0连接到网桥:

brctl addif br0 vxlan0

在另外两台主机上也完成相似配置后,我们开始测试。

首先在主机1查看VTEP的转发表,可以看到此时只有一条组播条目,所有发出流量都将发送给该组播IP:

[root@localhost vagrant]# bridge fdb show dev vxlan0
00:00:00:00:00:00 dst 239.1.1.1 via eth1 self permanent

我们再次从主机1上访问主机2上的网桥IP, 此时访问成功:

[root@localhost vagrant]# 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=1.58 ms
64 bytes from 10.1.1.3: icmp_seq=2 ttl=64 time=0.610 ms
^C
--- 10.1.1.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.610/1.096/1.582/0.486 ms

此时再次在主机1上查看VTEP转发表,可以看到转发表中已经学习到10.1.1.3所在主机的VTEP地址:192.168.33.13,下次再发送数据给10.1.13所对应的MAC该直接发送到192.168.33.13:

[root@localhost vagrant]# bridge fdb show dev vxlan0
00:00:00:00:00:00 dst 239.1.1.1 via eth1 self permanent
2e:7a:a2:53:7b:31 dst 192.168.33.13 self

我们根据主机2上tcpdump的抓包结果来分析具体过程:

14:57:54.330846 IP 192.168.33.12.38538 > 239.1.1.1.4789: VXLAN, flags [I] (0x08), vni 1
ARP, Request who-has 10.1.1.3 tell 10.1.1.2, length 28

10.1.1.2所在主机不知道10.1.1.3对应的MAC地址,因而发送ARP广播,ARP数据包发送至VTEP,VTEP进行封装并洪泛给组播IP:239.1.1.1。

14:57:54.330975 IP 192.168.33.13.58823 > 192.168.33.12.4789: VXLAN, flags [I] (0x08), vni 1
ARP, Reply 10.1.1.3 is-at 2e:7a:a2:53:7b:31, length 28

主机2收到数据包之后解封装,VTEP会学习数据包的MAC及VTEP地址,将其添加到转发表,并将解封后的数据帧发送到网桥接口10.1.1.3。10.1.1.3的接口发送ARP响应。

14:57:54.332055 IP 192.168.33.12.48980 > 192.168.33.13.4789: VXLAN, flags [I] (0x08), vni 1
IP 10.1.1.2 > 10.1.1.3: ICMP echo request, id 4478, seq 1, length 64

主机1之后开始发送ICMP数据包,从这里可以看出外层IP地址不再为组播IP,而是学习到的192.168.33.13。

14:57:54.332225 IP 192.168.33.13.55921 > 192.168.33.12.4789: VXLAN, flags [I] (0x08), vni 1
IP 10.1.1.3 > 10.1.1.2: ICMP echo reply, id 4478, seq 1, length 64

接着,10.1.1.3发送回ICMP响应包。

下面再来说明OpenvSwitch实现实例。

OVS不支持组播,需要为任意两个主机之间建立VXLAN单播隧道。与上边示例的拓朴结构相比,我们使用了两个OVS网桥,将虚拟逻辑网络的接口接入网桥br-int,将所有VXLAN接口接入br-tun。两个网桥使用PATCH类型接口进行连接。由于网桥br-tun上有多个VTEP,当BUM数据包从其中某个VTEP流入时,数据包会从其他VTEP接口再流出,这会导致数据包在主机之间无限循环。因而我们需要添加流表使VTEP流入的数据包不再转发至其他VTEP。若逻辑网络接口与VTEP连接同一网桥,配置流表将比较繁琐。单独将逻辑网络接口放到独立的网桥上,可以使流表配置非常简单,只需要设置VTEP流入的数据包从PATCH接口流出。

拓朴结构如图:

首先在主机1上创建网桥br-int和br-tun:

ovs-vsctl add-br br-int
ovs-vsctl add-br br-tun

创建PATCH接口连接br-int和br-tun:

ovs-vsctl add-port br-int patch-int -- set interface patch-int type=patch options:peer=patch-tun
ovs-vsctl add-port br-tun patch-tun -- set interface patch-tun type=patch options:peer=patch-int

创建单播VTEP连接主机2:

ovs-vsctl add-port br-tun vxlan0 -- set interface vxlan0 type=vxlan options:remote_ip=192.168.33.13

创建单播VTEP连接主机3:

ovs-vsctl add-port br-tun vxlan1 -- set interface vxlan1 type=vxlan options:remote_ip=192.168.33.14

接下来,我们给br-tun添加流表来处理流量。

首先查看br-tun上各接口的PORT ID,从结果看到Patch Port为1,VTEP分别为5和6:

[root@localhost vagrant]# ovs-ofctl show br-tun
OFPT_FEATURES_REPLY (xid=0x2): dpid:00006e12f4fd6949
n_tables:254, n_buffers:256
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
1(patch-tun): addr:92:fa:08:fb:3c:bfconfig:     0state:      0speed: 0 Mbps now, 0 Mbps max
5(vxlan0): addr:e6:65:c2:85:79:eaconfig:     0state:      0speed: 0 Mbps now, 0 Mbps max
6(vxlan1): addr:2a:38:b0:fa:b2:98config:     0state:      0speed: 0 Mbps now, 0 Mbps max
LOCAL(br-tun): addr:6e:12:f4:fd:69:49config:     PORT_DOWNstate:      LINK_DOWNspeed: 0 Mbps now, 0 Mbps max
OFPT_GET_CONFIG_REPLY (xid=0x4): frags=normal miss_send_len=0

清空br-tun流表:

ovs-ofctl del-flows br-tun

数据包进入br-tun后开始匹配table 0的流。我们使用table 0区分流量来源。来源于br-int的数据包由table 1处理,VTEP流入的数据交由table 2处理, 并丢弃其他PORT进入的数据包:

ovs-ofctl add-flow br-tun "table=0,priority=1,in_port=1 actions=resubmit(,1)”
ovs-ofctl add-flow br-tun "table=0,priority=1,in_port=5 actions=resubmit(,2)"
ovs-ofctl add-flow br-tun "table=0,priority=1,in_port=6 actions=resubmit(,2)”
ovs-ofctl add-flow br-tun "table=0,priority=0,actions=drop”

接着添加table 1的流, table 1用于处理来自br-int的流量,单播数据包交由table 20处理,多播或广播数据包交由table 21处理:

ovs-ofctl add-flow br-tun "table=1,priority=0,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00,actions=resubmit(,20)”
ovs-ofctl add-flow br-tun "table=1,priority=0,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00,actions=resubmit(,21)”

table 21处理广播流量,将数据包从所有VTEP的PORT口发出:

ovs-ofctl add-flow br-tun "table=21,priority=0,actions=output:5,output:6”

table 2处理VTEP流入的数据包,在这里我们实现学习机制。来自VTEP的数据包到达后,table 2从中学习MAC地址,VNI、PORT信息,并将学习到的流写入table 20中,并将流量由PATCH口发送到br-int上, 并将学习到的流优先级设为1:

ovs-ofctl add-flow br-tun "table=2,priority=0,actions=learn(table=20,hard_timeout=300,priority=1,NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],output:NXM_OF_IN_PORT[]), output:1”

table 20处理单播流量,我们将默认流优先级设置为0。因为学习到的流优先级设置为1,因而只有匹配不到目标MAC的未知单播交由table 21处理,table 21将流量广播到所有VTEP:

ovs-ofctl add-flow br-tun "table=20,priority=0,actions=resubmit(,21)"

整体处理逻辑如图:

我们查看流表, 发现table 20中只有一条默认添加的流:

[root@localhost vagrant]# ovs-ofctl dump-flows br-tun table=20
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=1.832s, table=20, n_packets=0, n_bytes=0, idle_age=1, priority=0 actions=resubmit(,21)

我们从主机1访问主机3上的虚拟网络IP,访问成功:

[root@localhost vagrant]# ping 10.1.1.4 -c 2
PING 10.1.1.4 (10.1.1.4) 56(84) bytes of data.
64 bytes from 10.1.1.4: icmp_seq=1 ttl=64 time=1.45 ms
64 bytes from 10.1.1.4: icmp_seq=2 ttl=64 time=0.538 ms--- 10.1.1.4 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.538/0.994/1.451/0.457 ms

我们再次查看流表, 发现table 20中已经多了一条学习到的流,下次再向该MAC发送数据包,数据将直接从PORT 6中发出:

[root@localhost vagrant]# ovs-ofctl dump-flows br-tun table=20
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=164.902s, table=20, n_packets=36, n_bytes=3360, hard_timeout=300, idle_age=19, hard_age=19, priority=1,dl_dst=ee:2c:09:42:0e:46 actions=load:0->NXM_NX_TUN_ID[],output:6
cookie=0x0, duration=223.811s, table=20, n_packets=1, n_bytes=98, idle_age=164, priority=0 actions=resubmit(,21)

原文链接:http://just4coding.com/2017/05/21/vxlan/

OVS对VXLAN报文解封包相关推荐

  1. OpenStack OVS GRE/VXLAN

    https://www.jianshu.com/p/0b52de73a4b3 OpenStack OVS GRE/VXLAN网络 学习或者使用OpenStack普遍有这样的现象:50%的时间花费在了网 ...

  2. 【Linux4.1.12源码分析】VXLAN报文内核协议栈处理

    4.1.12内核已经支持vxlan报文的gro功能,意味着vxlan报文交给协议栈之前,已经被聚合过了,而在早期的内核中聚合逻辑是在encap_rcv函数之后实现的. 之前分析的UDP报文处理中,可以 ...

  3. vxlan报文 wireshark_Linux VXLAN

    VXLAN协议 VXLAN是Virtual eXtensible Local Area Network的缩写,RFC 7348的标题"A Framework for Overlaying V ...

  4. VXLAN报文形式和如果通讯的

    VXLAN隧道是如何建立的 本节将为您介绍VXLAN隧道的建立过程,并在这个过程中更好地理解VXLAN的工作原理. 什么是VXLAN中的VTEP和VNI 下面让我们来进一步了解VXLAN的网络模型以及 ...

  5. 海蜘蛛OEM和修改后门帐号解封包

    公布海蜘蛛BIN解包封包命令 2009-04-30 09:54 解包命令:cat hsrouter_isp_v6.1.0.bin| openssl des-cbc -k 'letusd01twell' ...

  6. Java解析银联报文_中国银联8583报文(JAVA)封包/解包/位图 相关操作源代码

    一:IS08583包介绍: ISO8583包(简称8583包)是一个国际标准的包格式,最多由128个字段域组成,每个域都有统一的规定,并有定长与变长之分. 8583包前面一段为位图,用来确定包的字段域 ...

  7. OVS 非VXLAN的收发包调用栈(二十二)

    非VXLAN的收发包调用栈 netdev_frame_hook()netdev_port_receive()ovs_vport_receive()ovs_dp_process_packet()(在查表 ...

  8. OVS对VXLAN解封包(二)

    一.VxLAN 将二层数据帧封装为 UDP 包 含义: Outer MAC destination address (MAC address of the tunnel endpoint VTEP) ...

  9. OVS DPDK vhost-user详解(十三)

    vhost user协议的控制和数据通道 所有的控制信息通过UNIX套接口(控制通道)交互.包括为进行直接内存访问而交换的内存映射信息,以及当数据填入virtio队列后需要出发的kick事件和中断信息 ...

最新文章

  1. 对话Nullmax无人车CEO徐雷:造血营收L3,追梦宏图L4
  2. Linux 没有主清单属性,maven编译正常,运行报错:中没有主清单属性
  3. 收藏 | 来自微软大神的机器学习秘籍!
  4. 核电厂的“神经中枢”——核电厂数字化仪控系统
  5. R语言-主成分分析和聚类分析实操(包含源码)
  6. retinaface代码讲解_Pytorch-RetinaFace 详解
  7. https请求,报错Could not establish trust relationship for the SSL/TLS secure channel
  8. [滴水石穿]poj 1007-DNA Sorting 结题报告【1】
  9. stm32cubemx hal学习记录:JY901S串口
  10. Ubuntu中解压出现:bzip2: (stdin) is not a bzip2 file.
  11. 农村信用社计算机基础知识,农村信用社计算机基础知识题五
  12. bzoj3659 Which Dreamed It BEST定理(公式绝对没错doge)
  13. HTML5自动换行的间距设置,设置EXCEL自动换行的行与行之间的间距的办法
  14. 深度学习文献汇总|第四十二期
  15. 百度网盘满速下载工具利器SpeedPan
  16. mac 软件分享平台
  17. python画椭圆turtle_python之turtle画蚊香,python用turtle画圆弧,原理:利用turtl
  18. 飞旭体质健康测试云平台学生体质测试管理系统
  19. Windows 下 命令行 无法输入中文
  20. plt. bar添加数据标签

热门文章

  1. 如何自学python基础-零基础如何学习python
  2. python语法大全-python基本语法
  3. python编程培训多少钱-python培训一般多少钱?[python培训]
  4. python装饰器实例-python 装饰器的使用示例
  5. 下载了python在哪里写代码-通过python下载FTP上的文件夹的实现代码
  6. python银行系统-菲菲用python模拟银行系统
  7. python游戏脚本实例-基于Python实现的扫雷游戏实例代码
  8. python在线读-Python测试之道
  9. python的用途实例-Python实例方法、类方法、静态方法的区别与作用详解
  10. HackerRank Gift Boxes(hash)