主题
VXLAN:二层 Overlay
GRE 是三层隧道:两个站点各自一个网段,靠路由互通。 VXLAN 是二层隧道:两个站点的主机变成同一个广播域里的邻居。
这个差别不只是"更底层",它带来的是完全不同的用途。
封装格式
text
┌────────────┬─────────┬──────────┬────────────────────────────┐
│ 外层 IP(20) │ UDP(8) │ VXLAN(8) │ 完整的以太网帧(含 MAC 头) │
│ │ dst4789 │ VNI 100 │ hA的MAC → hB的MAC + IP 包 │
└────────────┴─────────┴──────────┴────────────────────────────┘
↑ 连二层头都被封进去了开销 50 字节,是 GRE(24 字节)的两倍多 —— 因为它要多带一个以太网头 和 UDP/VXLAN 头。
VNI(VXLAN Network Identifier,24 位)标识这是哪个二层网段。 一对 VTEP 之间可以跑 1600 万个 VNI,互不干扰 —— 这是它在多租户 数据中心里的核心价值。
配置
应用配置
bash
./labctl up site
./labctl apply site 02
./labctl verify site 02bash
# 1. 两端各建一个隧道
vppctl create vxlan tunnel src 198.51.100.1 dst 198.51.100.2 vni 100
# 2. 建桥域
vppctl create bridge-domain 100 learn 1 forward 1 flood 1 uu-flood 1
# 3. 把 LAN 口和隧道口都放进桥域
vppctl set interface ip address del host-eth1 10.1.0.1/24 # 先摘掉三层地址
vppctl set interface l2 bridge host-eth1 100
vppctl set interface l2 bridge vxlan_tunnel0 100
vppctl set interface state vxlan_tunnel0 up一个接口不能同时是三层口和二层口
进桥域前必须先 set interface ip address del。忘了这步会报错, 或者更糟 —— 看起来配上了但转发行为不对。
反过来从桥域摘出来用 set interface l3 <接口>, 摘完记得把三层地址加回去,否则那个口就成了哑口。
配好之后,两台 NAT 的 LAN 口没有 IP 地址了。它们纯粹是二层桥的成员, 不参与路由 —— 跨站点通信完全靠桥转发。
决定性证据:学到了对端的 MAC
实验把 hB 挪到和 hA 同一个网段(10.1.0.11 和 10.1.0.12),然后:
text
── 2) 决定性证据:hA 学到了 hB 的 MAC ──
hA 的 ARP 表:10.1.0.12 dev eth1 lladdr aa:c1:ab:dc:2b:4f REACHABLE
hB 的真实 MAC:aa:c1:ab:dc:2b:4f
✓ 两者一致 —— 这是真正的二层邻居这一条就是 VXLAN 和 GRE 最本质的区别
text
GRE(三层) hA 的 ARP 表里只有网关的 MAC,
对端主机的 MAC 它永远看不到
VXLAN(二层) hA 直接学到 hB 的 MAC能学到对端 MAC,说明 ARP 广播被泛洪过去了、ARP 应答也原样 带着 MAC 头回来了 —— 整个以太网帧穿过了 WAN。
转发路径完全不同
text
→ af-packet-input
→ ethernet-input
→ l2-input ← 进的是二层处理,不是 ip4-input
→ l2-learn ← 学源 MAC
→ l2-flood ← 查不到目的 MAC 就泛洪(这里是 ARP 广播)
→ l2-output
→ vxlan4-encap ← 套上 VXLAN + UDP + 外层 IP
→ ip4-rewrite
→ host-eth2-output对比 GRE 的路径(ip4-input → ip4-lookup → ip4-midchain), 从第三跳就分岔了。
在 VPP 眼里,这个包从头到尾是个以太网帧,三层信息只是载荷的一部分。
L2FIB 记录了桥学到的 MAC:
bash
./labctl vppctl site show l2fib verbosetext
Mac-Address BD-Idx If-Idx Interface-Name
aa:c1:ab:20:30:5e 1 7 vxlan_tunnel0 ← 从隧道学到的远端 MAC
aa:c1:ab:04:32:d5 1 1 host-eth1 ← 本地 MAC为什么跑在 UDP 上
VXLAN 用 UDP 4789 封装,而不是像 GRE 那样自己占一个 IP 协议号。 这个选择有两个实际好处:
一、能穿 NAT。 UDP 有端口,NAT 设备处理得了。 GRE 是协议 47,大多数 NAT 穿不过去。
二、支持多路径负载分担。
text
中间设备做 ECMP 时按五元组哈希。
GRE 没有端口字段 → 两个 VTEP 之间的所有流量
在中间设备看来是同一条流 → 全挤在一条物理链路上
VXLAN 把**内层流**的哈希写进**外层源端口** →
不同的内层流有不同的外层源端口 →
中间设备把它们哈希到不同的物理路径第二点在数据中心里是刚需。没有它,两个机架之间买再多带宽也用不上 —— 所有流量都走同一条。
MTU 问题比 GRE 更紧张
text
┌──────────┬────────┬──────────────────────┐
│ 隧道类型 │ 开销 │ 1500 物理口的可用 MTU │
├──────────┼────────┼──────────────────────┤
│ GRE │ 24 │ 1476 │
│ VXLAN │ 50 │ 1450 │
└──────────┴────────┴──────────────────────┘GRE 那一篇讲的 MTU 分片问题在这里更严重。 数据中心的标准做法是把底层网络配成巨帧(9000 MTU), 这样封装 50 字节之后仍有 8950 可用,租户完全无感。
这也是为什么 VXLAN 主要用在数据中心内部而不是跨互联网 —— 你能控制底层 MTU 的时候它才好用。
一个坑:接口编号取决于链路声明顺序
netlab 按每个节点的链路顺序分配 ethN
这个坑我在写本章实验时踩了,而且症状极具迷惑性。
最初的拓扑链路顺序是:
yaml
links:
- nat1 + hA # 站点 A
- nat1 + nat2 # WAN
- nat2 + hB # 站点 B结果:
text
nat1: eth1 = 站点 A LAN, eth2 = WAN ← 符合直觉
nat2: eth1 = WAN, eth2 = 站点 B LAN ← 反过来了!因为 nat2 参与的第一条链路是 WAN。于是我在 nat2 上 把 WAN 口放进了桥域,而它的 LAN 口还留着三层地址。
症状是:配置命令都成功、桥域看起来正常、L2FIB 也在学 MAC, 但学到的全是错误的 MAC,跨站点就是不通。
解决办法是调整链路声明顺序,让每个节点的本地 LAN 都排在第一:
yaml
links:
- nat1 + hA # 站点 A → nat1 的 eth1
- nat2 + hB # 站点 B → nat2 的 eth1
- nat1 + nat2 # WAN → 两台各自的 eth2排查方法:配任何二层/隧道之前,先确认接口含义。
bash
vppctl show interface addr | grep -A1 '^host-eth'看每个口上的地址,比看接口名可靠得多。
GRE 还是 VXLAN
text
✓ 用 GRE ✓ 用 VXLAN
──────────────────────────── ──────────────────────────────
两个站点是不同的网段 两个站点要在同一个二层域
只要三层可达 需要跨站点做二层广播
想省开销(24 vs 50 字节) 需要多租户隔离(VNI)
跨互联网,MTU 不可控 需要 ECMP 多路径分担
底层 MTU 可控(数据中心)一个常见误区是"VXLAN 更现代所以更好"。二层域拉长是有代价的 —— 广播域变大、故障域变大、生成树/环路风险跨站点传播。 如果三层能解决,就不要拉二层。
VXLAN 真正不可替代的场景是:虚拟机/容器需要跨物理位置保持同一个二层网段 (在线迁移、集群心跳),或者需要大规模多租户隔离。
小结
| 层次 | 二层 overlay,封装完整以太网帧 |
| 封装 | 外层 IP(20) + UDP(8, 端口 4789) + VXLAN(8) + 内层以太网头 = 50 字节 |
| VNI | 24 位,1600 万个二层域,多租户隔离的基础 |
| 配置 | create vxlan tunnel ... vni N + 桥域 + set interface l2 bridge |
| 前置 | 进桥域前必须先摘掉接口的三层地址 |
| 决定性证据 | 主机能学到对端主机的 MAC |
| 转发路径 | l2-input → l2-learn → l2-fwd/flood → vxlan4-encap |
| 为什么用 UDP | 能穿 NAT;外层源端口带内层哈希,支持 ECMP |
| MTU | 比 GRE 更紧张,数据中心靠巨帧解决 |
| 实验中的坑 | netlab 按链路顺序分配 ethN,两端接口含义可能相反 |