ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

VXLAN报文抓包解析与ECMP四路径负载均衡实战

VXLAN报文抓包解析与ECMP四路径负载均衡实战

在数据中心里待过几年的人,基本都有过这种经历:虚拟机之间的ARP通了,可业务就是时好时坏;明明underlay链路都活着,VXLAN隧道却像得了癫痫;配置了四路ECMP,流量偏偏全都挤在同一条链路上。遇到这种情况,光靠“逻辑推理”真能把人绕晕。我的习惯很简单,直接在VTEP的物理口上抓一份VXLAN报文,一层一层拆开看:外层MAC、外层IP、UDP 4789、VXLAN头、内层原始帧,全都清清楚楚摆在那里。抓明白了封装,再去看ECMP怎么给这些封装报文分流,很多东西不用猜,一眼就能定论。

这篇文章我就用实际抓包作为线索,把VXLAN报文封装的完整流程过一遍,再用一组四路径ECMP实验,看看underlay到底是怎么根据VXLAN外表层的UDP源端口,把不同业务流又分散又不乱序地送到对端VTEP的。内容偏实操,命令和抓包解读都有,适合刚接触overlay网络的运维同学,也适合被ECMP负载不均折磨过的老手对一下思路。

1. VXLAN到底在解决什么问题,为什么非抓包不可

1.1 传统VLAN的墙和overlay的思路

传统VLAN用的是12比特的VID,满打满算4096个,这在云化数据中心里根本不够用。更麻烦的是VLAN是二层概念,想要跨三层组网,就必须依靠VLAN Trunk、VPLS这些技术,配置复杂度直线上升。而虚拟机热迁移要求源端和目标端在同一个二层域里,旧方案往往把二层网络拉得千疮百孔,各种环路和广播域问题接踵而至。

VXLAN的思路完全不同。它在原始二层报文外面再套一层UDP/IP头,把“带VLAN语义”的二层报文变成一个普通的三层UDP包,在underlay网络里走IP路由转发。这样一来,底层网络只需要提供IP连通性,不需要理解虚拟机里的MAC地址,也不需要为一个租户维护跨设备的VLAN状态。用大白话说,这就是给二层帧套了一个可以跨三层寄送的快递信封,信封上的地址是VTEP的IP,信封里面是原封不动的二层报文。

这个“信封”概念,是理解所有VXLAN问题的起点。很多排障翻车,都是因为脑子里没有把“隧道里层的业务报文”和“隧道外层underlay报文”分开。抓包的时候如果抓错位置,看到的完全是两份不同的东西。

1.2 VTEP、VNI、隧道:三个必须记清的概念

VTEP是VXLAN Tunnel Endpoint,隧道端点。封装和解封装都发生在VTEP上。服务器上的VXLAN接口、虚拟交换机上配置的VXLAN网关、物理交换机上的VXLAN业务口,这些角色都可以叫VTEP。它是“信封”的投递点,负责把二层帧塞进UDP包,或者从UDP包里取出二层帧。

VNI是VXLAN Network Identifier,24位,最多1600多万个。它才是真正区分租户二层域的那个ID。VLAN用的是12位,VXLAN换成24位,等于从一个小区的门牌号扩展成了全球邮政编码。同一个VNI下的VTEP属于同一个大二层广播域,不同VNI之间天然隔离。

隧道则是VTEP之间的一条逻辑路径。理解隧道要抓住一点:隧道本身不加密、不保证可靠传输,它只是把内层帧“寄放”在underlay的三层报文中。所以Underlay抖动、丢包、乱序,都会直接影响overlay业务质量。这也是为什么排查VXLAN问题时,先看underlay再看overlay是基本顺序。

1.3 抓包看VXLAN的天然优势

VXLAN报文在网络上传输是明文形式,没有加密,所以只要能抓到包,就能一层层拆开检查。这是它排障友好的地方。从抓包视角看,一份完整的VXLAN报文从外到内依次是:外层以太网头、外层IP头、UDP头、VXLAN头、内层以太网头、内层IP头、内层传输层头。这个顺序非常重要,抓包时所有解读都围绕这层洋葱结构展开。

我强烈建议每个刚学VXLAN的人都亲手抓一次包。因为只有亲眼看到外层UDP源端口在变、VNI出现在8字节固定头部、内层报文原封不动地藏在里面,才能真正理解“overlay是封装出来的”这件事。很多人学了三个月VXLAN原理,不如自己抓一次包十分钟。

2. 一步步拆解VXLAN报文封装全流程

2.1 封装的起点:原始二层帧

所有VXLAN封装的起点,都是虚拟机网卡发出的一个标准以太网帧。这个帧有目的MAC、源MAC、EtherType,然后是IP头、TCP/UDP头、Payload。比如虚拟机A访问虚拟机B的某个服务,原始报文就是一个普通TCP连接的数据包。

这个原始帧会被完整地放进VXLAN的“信封”里,不做任何改写。目的MAC就是你业务真正的目的MAC,源MAC是真正的源MAC。这里的“完整保留”是VXLAN能作为大二层承载技术的关键——VTEP对租户虚拟机完全透明,虚拟机感知不到隧道存在。

有一点需要注意:抓包工具看到的原始二层帧通常没有FCS校验字段,因为网卡在收包时已经剥掉了。VXLAN封装封装的是以太网帧主体,不包含FCS。Underlay链路自己会对整个外层报文做CRC校验,所以内层数据是靠外层链路误码检测来兜底的。

2.2 加VXLAN头:VNI从这里进入报文

第一步,在原始帧前面加8字节VXLAN头。它的结构非常规整:

字段长度说明
Flags1字节第4个bit为I标志,置1表示VNI有效,抓包常见值0x08
Reserved3字节保留,必须为0
VNI3字节VXLAN网络标识符,24位
Reserved1字节保留,必须为0

Wireshark里有些版本会把Flags显示成0x08000000,有些显示成0x08,其实只是解析粒度不同,本质都是同一个标志位。看到第一个字节等于0x08,就表示这个包带了有效的VNI。

这个VNI是整个VXLAN头里唯一“有业务含义”的字段。两个虚拟交换机要通信,VNI必须一致。VNI不一致时,报文要么被对端VTEP丢弃,要么在VTEP上根本找不到对应的逻辑接口,表现就是二层不通。

2.3 UDP头:源端口不是随便写的

VXLAN选择UDP作为承载协议,目的端口是4789,这个端口已经由IANA分配。源端口却不是某个固定数值,而是由VTEP根据内层报文的关键字段算出来的一个哈希值,通常是内层五元组(源IP、目的IP、协议、源端口、目的端口)通过哈希函数生成的16位结果。

这一步是整个ECMP智能分流链条的起点。后面会展开讲,这里先记住一句话:外层UDP源端口是VXLAN流量的“熵”,它把不同业务流的差异,向上传递给了underlay的负载均衡设备。

在抓包时,如果你看到同一对VTEP之间有很多不同源端口的外层UDP报文,说明有多个内层业务流正在走这条隧道。如果源端口非常单一,多半是VTEP实现有问题,或者抓包位置不对。

外层IPv4的UDP校验和通常是可选的。很多服务器VTEP为了性能会关闭外层UDP校验和,抓包会看到Checksum为0,这不是报文损坏,也不需要惊慌。Wireshark在计算时可能会标成incorrect,原因是硬件offload没有参与,忽略即可。

2.4 外层IP和MAC:把“内层帧”送上underlay网络

VXLAN头前面继续加上外层IP头。源IP是本端VTEP的隧道源地址,目的IP是对端VTEP的隧道目的地址。这两个IP一定要从VTEP的underlay路由角度可达,否则隧道起不来。抓包时如果发现外层目的IP到了某个设备后包消失了,多半是该设备没有到达目的VTEP的路由。

外层IP头的协议字段是17,也就是UDP,这决定了underlay交换机看到它就是一个普通的三层包。特别注意,VXLAN封装后外层IP一般不设置分片标志或者会设置DF位。如果内层报文太大,外层又不分片,就会直接丢弃,这就是VXLAN网络里MTU问题导致丢包的底层原因。

最外层加14字节以太网头。目的MAC是underlay路径上下一跳设备的MAC地址,不是对端VTEP的MAC。比如VTEP上级路由器的MAC、spine节点的MAC。源MAC是本端VTEP物理出接口的MAC。EtherType是0x0800,表示外层走IPv4。

抓包时通过“外层目的MAC”可以快速判断报文从VTEP出来后交给谁了。这也是排查ECMP分流时很重要的一个点:不同路径的下一跳MAC不同,抓包看外层目的MAC就知道你抓到的是哪条路径的流量。

2.5 封装后的报文到底有多长

VXLAN封装增加的开销是:外层以太头14字节 + 外层IP头20字节 + UDP头8字节 + VXLAN头8字节,一共50字节。如果外层还带了VLAN标签,再加4字节。

一个常见场景:业务报文内层IP MTU是1500,内层以太网帧1514字节,封装后整包变成1564字节。如果underlay的物理接口MTU还停留在1500,这个包要么被分片,要么被丢弃。很多VXLAN网络故障排查到最后,发现都是从物理接口MTU到虚拟机网卡MTU中间某个环节没放开。常用解法有两种:把underlay接口MTU统一调成9000,走jumbo frame;或者把overlay业务VLAN的MTU调成1450,给50字节预留空间。我个人在测试环境喜欢前者,生产环境则要仔细评估链路每跳的MTU能力。

3. 抓包实操:从VTEP物理口完整抓取一封VXLAN报文

3.1 最小实验环境怎么搭

不想动物理设备的话,用两台Linux主机就能搭一个最小VXLAN实验环境。假设两个主机IP分别是192.168.1.1和192.168.2.1,在主机A上执行:

# 主机A:创建VXLAN接口,VNI 100,远端指向主机B ip link add vxlan100 type vxlan id 100 remote 192.168.2.1 dstport 4789 dev eth0 ip link set vxlan100 up ip addr add 10.0.0.1/24 dev vxlan100

主机B上做对称配置:

# 主机B:VNI必须一致,远端指向主机A ip link add vxlan100 type vxlan id 100 remote 192.168.1.1 dstport 4789 dev eth0 ip link set vxlan100 up ip addr add 10.0.0.2/24 dev vxlan100

配置完用10.0.0.1去ping 10.0.0.2,通了说明隧道已经起来。然后到主机A的物理网卡eth0上抓包:

tcpdump -i eth0 udp port 4789 -nn -s 0 -w vxlan_cap.pcap

这个命令只抓UDP 4789端口,也就是只抓VXLAN报文,-s 0表示抓完整包,不截断。很多新手只抓前96字节,结果内层报文一截为二,什么都看不到,这是第一个容易踩的坑。

3.2 一次抓包中的字段逐行解读

用Wireshark打开抓到的pcap,展开一个完整的数据包,你会看到典型的外层结构。下面是一个1500字节业务包封装后的抓包字段示例,我按Wireshark的展示习惯整理了一下:

Frame 12: 1564 bytes on wire Ethernet II, Src: 00:0c:29:xx:xx:xx, Dst: c8:3a:35:xx:xx:xx Type: IPv4 (0x0800) Internet Protocol Version 4, Src: 192.168.1.1, Dst: 192.168.2.1 Protocol: UDP (17) Total Length: 1550 User Datagram Protocol, Src Port: 53012, Dst Port: 4789 Length: 1530 VXLAN Flags: 0x08 VNI: 100 Ethernet II, Src: 02:00:00:00:00:01, Dst: 02:00:00:00:00:02 Type: IPv4 (0x0800) Internet Protocol Version 4, Src: 10.0.0.1, Dst: 10.0.0.2 Protocol: TCP (6) TCP: src port 12345, dst port 443

注意几个细节。外层IP Total Length是1550字节,那正好是“内层完整帧1514字节 + 外层IP的20字节 + UDP的8字节 + VXLAN的8字节”。整个线缆上看到的Frame Length是1564字节,就是再加14字节外层以太头。

外层UDP源端口53012不是随机数,是VTEP对10.0.0.1到10.0.0.2这条内层流的五元组做哈希得到的。如果实验里有第二条内层流,比如换成TCP源端口23456,你会看到外层UDP源端口变成另一个值。这个“端口跟着流走”的现象,正是后面的ECMP能分流的命根子。

VXLAN层的VNI显示为100,对应我们创建隧道时的id 100。内层以太网帧的两个MAC是虚拟机的虚拟MAC,外层以太网帧的两个MAC是宿主机物理网卡和网关/交换机的物理MAC。外层和内层两套MAC可以完全不同,这正是网络虚拟化的体现。

3.3 两份视角抓包对比:隧道内vs隧道外

再做一个对比实验。在主机A的vxlan100接口上抓包:

tcpdump -i vxlan100 -nn -s 0 icmp

这里看到的是解封装后的原始报文,只有内层IP和ICMP头,完全没有外层UDP和VXLAN头。而在物理eth0上抓到的则是完整封装报文。两份抓包对比着看,你就能直观理解“封装”到底发生在哪一层:VTEP虚拟接口里是原始帧,VTEP物理出接口上变成了带外层的封装帧,中间隔着的就是VXLAN/UDP/IP这层壳。

排障时这份对比很有用。业务抓包抓隧道内,underlay抓包抓隧道外。如果隧道内两层通、物理上抓不到对端回包,问题就定位在underlay路由或ECMP上;如果物理口有封装包但虚拟接口没有解出来的包,问题多半出在VNI不匹配或目的端口不对。

4. ECMP四路径负载均衡:封装好的报文如何智能分流

4.1 ECMP的基本原则:等代价多路径

ECMP的全称是Equal-Cost Multi-Path,等代价多路径。Underlay网络里,一个VTEP的隧道目的地址往往通过多条链路、多个中间节点同时可达,而且这几条路径的OSPF/BGP路由开销完全一样。在这种情况下,设备会在路由表里同时安装多个下一跳,形成多路径路由。

可以这么理解:你要去一个地址,打开地图发现有四条路路况一样、距离一样,系统就让你把不同车流分散到四条路上,避免所有车挤一条路。这就是ECMP的朴素原理。传统路由只有最优下一跳,ECMP则是“多条等价路径同时有效”。

在VXLAN场景里,ECMP通常发生在leaf VTEP到spine的这一段。Leaf把封装好的VXLAN报文从underlay转发出去时,如果到远端VTEP有多个等价下一跳,它就根据报文内容计算哈希值,再根据哈希值落到某个下一跳。

4.2 熵和哈希:VXLAN给ECMP送上的“分散因子”

问题来了:leaf设备怎么知道该把哪个包分到哪条路?它只能看到外层报文。如果所有VXLAN报文的外层五元组完全一样,那哈希结果就永远一样,所有流量都会固定走一条路径,四条ECMP链路只有一条在干活。

VXLAN的设计者早就想到了这一点。RFC 7348建议VTEP在设置外层UDP源端口时,对内层报文的关键字段做哈希,把这个哈希值当作源端口。于是不同内层流,外层UDP源端口不同;同一内层流,外层UDP源端口保持不变。Underlay设备做ECMP哈希时,用外层五元组里的源端口参与计算,天然就把不同内层流分散到了不同路径上。

这个链条可以概括为:内层五元组变化 → 外层UDP源端口变化 → underlay哈希结果变化 → 分流到不同链路。可以说,VXLAN用一个小小的UDP源端口,把原本对underlay“透明不可见”的内层流信息,重新注入到了外层报文里。

设备端的ECMP哈希原理用伪代码表示大约是这样:

hash_value = hash(out_src_ip, out_dst_ip, out_proto, out_src_port, out_dst_port) path_index = hash_value % path_count

当然,真实设备使用的哈希函数比这复杂,往往是CRC、XOR等混合计算,还可能加入随机扰动量。但核心思想一致:参与哈希的字段差异越大,分流越均匀。VXLAN外层源端口恰好提供了这种差异。

4.3 实验:四路径下多流vs单流的走向

我在模拟环境里搭过一组四路径实验。一台leaf VTEP上联四条等价链路,到远端VTEP的underlay路由同时挂了四个下一跳,路由表里能看到这样的多路径记录:

$ ip route show 192.168.2.0/24 nexthop via 10.0.0.1 dev veth0 weight 1 nexthop via 10.0.0.2 dev veth1 weight 1 nexthop via 10.0.0.3 dev veth2 weight 1 nexthop via 10.0.0.4 dev veth3 weight 1

然后我用iperf3并发发起多路TCP流去压测对端VTEP,同时在veth0到veth3四个接口上分别统计VXLAN报文数量。一次比较典型的结果如下:

路径VXLAN包数占比
veth01268425.2%
veth11253024.9%
veth21272025.3%
veth31240624.6%

四条路径的流量基本在25%附近,非常接近四等分。这就是ECMP“智能”的一面:不需要有人手工配置调度,纯粹靠哈希统计规律,就把几十条流大致均匀地撒到了四条链路上。

再看单条流的走向。我单独抓一条TCP流的所有包,分析它们经过的路径,结论很明确:同一时刻、同一业务流的所有VXLAN包,全部都出现在同一条物理链路上。因为同一条流的五元组不变,外层UDP源端口不变,哈希结果稳定,自然始终落在同一个nexthop。这个特性非常重要,它保证了同一条TCP流不会被分散到不同路径导致乱序,TCP性能不会因为ECMP而崩掉。

用tshark也能验证外层源端口的分布情况:

tshark -r vxlan_multi.pcap -Y "udp.port == 4789" -T fields -e udp.srcport | sort | uniq -c | sort -rn

统计结果里会有很多不同的UDP源端口值,端口数约等于内层流的数量。如果看到源端口长期只有一个或几个,就要怀疑VTEP是不是没有做sport哈希,或者哈希被offload卸载掉了。

4.4 对称哈希和哈希极化:容易被忽略的坑

ECMP四路径也不是万能药,至少有两个坑非常典型。

第一个是对称哈希问题。普通哈希只管把一个方向的包分到路径上,双向独立计算。对同一条业务流来说,正向从VM A到VM B走veth0,反向从VM B到VM A可能走veth2,这就导致往返路径不一致。对TCP这种本身能容忍乱序的协议来说问题不大,但很多安全设备、负载均衡设备是按会话跟踪状态的,双向路径不一致会直接造成连接异常。所以现在很多网络设备提供“对称哈希”能力,把哈希字段先按大小排序再做运算,让来回两个方向尽量选择同一条路径。VXLAN组网如果中间串了状态化设备,必须确认underlay设备开启了对称哈希。

第二个是哈希极化。多条不同流的哈希值可能映射到同一个出口bin,导致某条链路流量高得离谱,其他链路闲着。常见诱因是参与哈希的字段太少、流数太少、或者所有VTEP采用的哈希算法和seed完全一致。缓解手段通常是调整哈希seed、更换哈希算法、或者在万不得已时把大流量业务拆成更多小流再测试。

还有一个经常让人误解的概念:四路径ECMP不是说“四个流分别走四条路”,而是“哈希结果被分成四个桶,每个桶对应一条路”。一条流落进哪个桶是随机但确定的,所以即使你开了四条ECMP,某个时刻完全可能所有流量都在一条链路上,这不算故障。评估负载均衡效果要看统计分布,不能看瞬间值。

5. 常见问题与排查技巧实录

5.1 VXLAN抓包典型问题速查

我在实操中总结了一些高频问题,整理成表格供对照:

现象可能原因解决办法
Wireshark只显示UDP不显示VXLAN未识别4789端口为VXLANPreferences → Protocols → VXLAN,添加UDP端口4789;或tshark -d udp.port==4789,vxlan
物理口抓不到外层头网卡硬件offload把VXLAN封装卸载了ethtool -K eth0 gro off gso off tso off后重抓
抓到外层UDP源端口总是一个固定值VTEP未实现sport哈希,或offload接管检查VTEP实现版本,关offload验证
内层报文显示不完整tcpdump截断了抓包加-s 0,抓完整包
外层目的MAC和自己网关不一样隧道报文没走预期路径清理邻居表,检查underlay路由
vxlan接口通了但业务不通VNI不一致或UDP目的端口不一致两端对比ip -d link show vxlan100和dstport

特别提醒,网卡offload是抓包排障里最大的暗坑。支持VXLAN offload的网卡在驱动层就把外层头剥离或者直接由硬件添加,软件接口上看不到完整VXLAN报文。遇到这种情况,优先在underlay交换机镜像口上抓,或者在宿主机上用ethtool关闭相关offload后再抓。

5.2 ECMP分流不均怎么排查

分流不均时,第一步先确认路由是不是真的等价。命令看多路径路由:

ip route get 192.168.2.1

如果只显示一个nexthop,说明只有一条路径被安装,ECMP根本没生效。再看所有路径的weight,必须完全一致才叫等价,任何一个weight不同都会改变哈希分布。

第二步看外层UDP源端口分布。抓一段VXLAN报文,数一下源端口种类。如果源端口种类很少,问题出在VTEP侧。比如所有业务都是同一对IP主机之间的少量长连接,五元组差异本身就不大,那么哈希熵不足是“天生”的。这种情况不能怪ECMP,要么增加业务流数量,要么在VTEP和underlay支持的前提下考虑按内层字段做深层哈希。

第三步看是否存在哈希极化。可以把设备哈希算法的seed调一下,或者给不同设备配置不同的hash seed。很多网络设备都有类似“load-balance hash seed”的命令,调整后流量分布会立刻变化。调整一次不彻底正常,多试几次,同时观察四条路径的长期统计。

还有一种常见场景是所谓的“大象流”导致视觉上的不均。假设有一条业务流占整体带宽60%,它被哈希到某条路径后,那条路径显示占比远超25%。这不是ECMP失效,而是流粒度负载均衡和大流量竞争之间的天然矛盾。要处理大象流,常规ECMP解决不了,需要另上Multipath TCP或业务层拆分。

5.3 MTU和offload两个细节别忽视

VXLAN多出来的50字节,在抓包时也会露出马脚。如果你在物理口看到外层IP头里有分片标志,甚至看到多片IP分片包,多半是underlay MTU不足。排查时可以主动用大包测试:

ping -M do -s 1400 192.168.2.1

一次成功后再逐步加大size,直到出现失败,就能确认MTU瓶颈在哪一步。这种方式比翻配置直观得多。

offload除了影响抓包,还会影响真实转发。有些网卡开启VXLAN offload后,发送路径上由硬件计算校验和、添加外层头,接收路径上直接解封装,这本身没问题,甚至会大幅提升转发性能。但如果你在调试隧道本身,或者想确认某个字段的取值,offload会让抓包结果失真。测试环境里我的习惯是宁可关掉offload,拿到真实报文,再考虑性能优化。

最后分享一个排障小习惯

很长一段时间里,我遇到VXLAN相关的疑难杂症,第一步永远是抓一份完整的VXLAN报文,先从外层看到内层,确认封装链路里每个字段都符合预期。然后再去看ECMP,用tshark统计外层源端口分布,判断是不是哈希熵不足,而不是直接去怀疑Hash算法本身。这样一步步验证下来,大多数“玄学”问题最后都能落到某个具体参数上。

另外一个很实用的技巧是,做ECMP验证时用iperf3并发多流,比如iperf3 -c 10.0.0.2 -P 8 -t 30,一次就能产生8条不同端口的流,足够让VXLAN外层源端口产生明显差异。然后用tshark统计路径分布,比单纯ping大包有效得多。VXLAN和ECMP这两个东西,看着抽象,只要抓包看一次,心里就有底了。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进