本文基于本地
sonic代码整理,适合作为 VXLAN、EVPN、ARP suppression、SONiC 数据面编排的学习笔记。
摘要
在传统二层网络里,ARP Request 是广播报文。到了 VXLAN 网络中,一个 VLAN 可能被扩展到多个 VTEP,ARP 广播如果直接进入 overlay,就会变成跨 VTEP 的 BUM 流量复制,带来带宽浪费、控制面压力和故障扩散风险。
VXLAN ARP 代答,也常被叫作 ARP suppression,本质是让本地 VTEP 在已经掌握 IP/MAC/VNI/VTEP 关系时,直接替远端主机回复 ARP,避免把 ARP Request flood 到整个 VXLAN 网络。
结合本地 SONiC 代码来看,这个能力不是一个孤立函数完成的,而是由配置面、FDB/邻居学习、EVPN 控制面、Linux bridge/VXLAN netdevice 以及 SAI 编排共同完成。尤其要理解两个开关:
redistribute_host:决定本地学到的邻居是否以 MAC+IP Type-2 的形式发布出去。flood_suppress:决定 VXLAN VLAN 上 unknown/broadcast/multicast flood 是否被抑制,并触发 Linux VXLANproxy、bridgeneigh_suppress等能力。
关键词
VXLAN、EVPN、VTEP、VNI、ARP 代答、ARP suppression、BUM、SONiC、SWSS、NeighOrch、FdbOrch、VxlanMgr、SAI
1. 先建立直觉:ARP 代答到底在代谁答?
假设有两台主机:
less
Host A: 10.1.1.10 / MAC_A,在 VTEP1 后面
Host B: 10.1.1.20 / MAC_B,在 VTEP2 后面
VLAN 100 映射到 VNI 10000
Host A 想访问 Host B,首先要知道 10.1.1.20 对应哪个 MAC,于是发 ARP:
Who has 10.1.1.20? Tell 10.1.1.10
如果没有 ARP 代答,VTEP1 会把这个广播封装成 VXLAN BUM 流量,复制到其他远端 VTEP。远端 VTEP2 收到后,再交给 Host B,Host B 回 ARP Reply。
如果有 ARP 代答,并且 VTEP1 已经知道:
rust
10.1.1.20 -> MAC_B -> VNI 10000 -> remote VTEP2
那么 VTEP1 就可以直接在本地回复 Host A:
csharp
10.1.1.20 is at MAC_B
这样 ARP Request 就不需要进入 VXLAN overlay。
一句话总结:
ARP 代答的核心不是"会构造 ARP Reply",而是"VTEP 已经知道目标 IP 对应的 MAC,以及这个 MAC 属于哪个 VNI、在哪个远端 VTEP 后面"。
2. 没有 ARP 代答时的 VXLAN 广播问题
VXLAN 把二层网络建在三层 underlay 之上。一个二层广播域可能跨越多个机架、多个交换机和多个 VTEP。
ARP Request 是广播报文,因此它天然属于 BUM 流量:
- Broadcast:广播,例如 ARP Request。
- Unknown unicast:未知目的 MAC 的单播。
- Multicast:组播。
没有代答时,ARP 的典型路径如下:
css
flowchart LR
A[Host A\n10.1.1.10] -->|ARP Request| V1[VTEP1]
V1 -->|VXLAN BUM copy| V2[VTEP2]
V1 -->|VXLAN BUM copy| V3[VTEP3]
V1 -->|VXLAN BUM copy| V4[VTEP4]
V2 --> B[Host B\n10.1.1.20]
B -->|ARP Reply| V2
V2 -->|VXLAN unicast| V1
V1 --> A
如果一个 VNI 下挂了很多 VTEP,广播复制会被放大。主机越多、ARP 越频繁,overlay 里的无效流量越多。
因此 VXLAN 网络通常希望:
- 控制面提前学习 IP/MAC/VTEP/VNI 关系。
- 数据面在 ARP Request 到达时优先本地回复。
- 对未知流量进行 flood 抑制,避免广播风暴式扩散。
3. 有 ARP 代答时的逻辑
有代答时,路径会短很多:
css
flowchart TD
A[Host A 发 ARP Request\nWho has 10.1.1.20?] --> V1[VTEP1]
V1 --> DB[(本地学习表\nIP -> MAC -> VNI -> VTEP)]
DB -->|命中| R[VTEP1 本地构造 ARP Reply]
R --> A
A -->|后续业务报文\n目的 MAC=MAC_B| V1
V1 -->|VXLAN 单播封装\nOuter DIP=VTEP2\nVNI=10000| V2[VTEP2]
V2 --> B[Host B]
用伪代码表达就是:
java
收到 ARP Request(target_ip):
if 本地表中存在 target_ip -> target_mac:
回复 ARP Reply(target_ip is target_mac)
else:
if flood_suppress enabled:
抑制 flood,等待控制面学习或静态配置
else:
按 VXLAN BUM 复制到远端 VTEP
4. SONiC 代码中的关键模块
下面是本文涉及的本地代码索引:
| 模块 | 关键文件 | 作用 |
|---|---|---|
| CLI | src/sonic-utilities/config/vxlan.py |
提供 config vxlan ... 命令,写入 CONFIG_DB |
| show | src/sonic-utilities/show/vxlan.py |
提供 show vxlan ... 命令,查看 remote VNI、remote MAC、状态 |
| YANG | src/sonic-yang-models/yang-models/sonic-vxlan.yang |
定义 VXLAN_TUNNEL_MAP、VXLAN_REMOTE_VNI、VXLAN_FDB 等配置结构 |
| cfgmgr | src/sonic-swss/cfgmgr/vxlanmgr.cpp |
把 CONFIG_DB 的 VXLAN 配置转成 APP_DB,并创建 Linux VXLAN netdevice |
| orchagent | src/sonic-swss/orchagent/vxlanorch.cpp |
编程 VXLAN tunnel、tunnel map、remote VNI、SAI tunnel next-hop |
| FDB | src/sonic-swss/orchagent/fdborch.cpp |
消费 VXLAN_FDB_TABLE,处理 VXLAN 学习的 MAC |
| Neighbor | src/sonic-swss/orchagent/neighorch.cpp |
本地邻居学习后写入 VXLAN_FDB_TABLE,控制 MAC+IP Type-2 语义 |
| Route | src/sonic-swss/orchagent/routeorch.cpp |
处理 overlay next-hop,解析 vni_label、router_mac 等字段 |
| FPM | src/sonic-swss/fpmsyncd/fpmlink.cpp |
接收 FRR/zebra 的 FPM/netlink 信息,识别 EVPN FDB 相关消息 |
| ARP responder 示例 | src/sonic-restapi/arp_responder/*.cc |
展示 ARP Request 如何被改造成 ARP Reply |
| 测试 | src/sonic-swss/tests/evpn_tunnel.py、test_evpn_fdb.py |
验证 EVPN/VXLAN tunnel、remote VNI、tunnel next-hop、FDB 行为 |
5. 配置面:从 config vxlan 到 CONFIG_DB
SONiC 的 VXLAN CLI 入口在:
arduino
src/sonic-utilities/config/vxlan.py
本地代码中可以看到这些命令入口:
| 命令 | Python 函数 | 写入的数据 |
|---|---|---|
config vxlan add <vxlan_name> <src_ip> |
add_vxlan() |
CONFIG_DB:VXLAN_TUNNEL |
config vxlan evpn_nvo add <nvo_name> <vxlan_name> |
add_vxlan_evpn_nvo() |
CONFIG_DB:VXLAN_EVPN_NVO |
config vxlan map add <vxlan_name> <vlan_id> <vni> |
add_vxlan_map() |
CONFIG_DB:VXLAN_TUNNEL_MAP |
config vxlan neighbor add <vlan_id> <vni> <remote_vtep_ip> |
add_vxlan_neighbor() |
CONFIG_DB:VXLAN_REMOTE_VNI |
config vxlan redistribute_host enable/disable <vlan_id> |
_set_redistribute_host() |
更新 VXLAN_TUNNEL_MAP.redistribute_host |
config vxlan flood-suppress enable/disable <vlan_id> |
_set_flood_suppress() |
更新 VXLAN_TUNNEL_MAP.flood_suppress |
config vxlan mac add <vni> <mac> <remote_vtep_ip> |
add_vxlan_mac() |
CONFIG_DB:VXLAN_FDB |
配置面的关键点是:用户操作不会直接改硬件,而是先写 CONFIG_DB。后续由 vxlanmgrd 和 orchagent 消费 DB 事件,逐层下发。
流程如下:
lua
flowchart TD
CLI[config vxlan ...] --> CDB[(CONFIG_DB)]
CDB --> VXLANMGR[vxlanmgrd\nVxlanMgr::doTask]
VXLANMGR --> APP1[(APPL_DB\nVXLAN_TUNNEL_TABLE)]
VXLANMGR --> APP2[(APPL_DB\nVXLAN_TUNNEL_MAP_TABLE)]
VXLANMGR --> APP3[(APPL_DB\nVXLAN_REMOTE_VNI_TABLE)]
VXLANMGR --> APP4[(APPL_DB\nVXLAN_FDB_TABLE)]
VXLANMGR --> KERNEL[Linux VXLAN netdevice\nbridge link flags]
APP1 --> ORCH[orchagent]
APP2 --> ORCH
APP3 --> ORCH
APP4 --> ORCH
ORCH --> ASIC[(ASIC_DB / SAI)]
6. vxlanmgrd:把 VXLAN 配置翻译成 APP_DB 和 Linux netdevice
VxlanMgr::doTask() 位于:
bash
src/sonic-swss/cfgmgr/vxlanmgr.cpp
它根据表名分发处理:
scss
VXLAN_TUNNEL -> doVxlanTunnelCreateTask()
VXLAN_TUNNEL_MAP -> doVxlanTunnelMapCreateTask()
VXLAN_EVPN_NVO -> doVxlanEvpnNvoCreateTask()
VXLAN_REMOTE_VNI -> doVxlanRemoteVniCreateTask()
VXLAN_FDB -> doVxlanFdbCreateTask()
其中跟 ARP 代答最相关的是 VXLAN_TUNNEL_MAP,因为 VLAN-VNI 映射是 ARP suppression 的作用范围。没有 VLAN 到 VNI 的映射,VTEP 就不知道这个二层域对应哪个 overlay 网络。
在 doVxlanTunnelMapCreateTask() 里,代码会读取:
vlan
vni
flood_suppress
然后调用:
scss
createVxlanNetdevice(..., proxy_arp_enabled, flood_suppress_enabled)
本地代码中的逻辑可以概括为:
ini
proxy_arp_enabled = flood_suppress_enabled || isVlanProxyArpEnabled(vlan)
也就是说,只要 flood_suppress 打开,或者 VLAN interface 本身启用了 proxy ARP,创建 VXLAN netdevice 时就会打开 proxy 相关能力。
7. flood_suppress:抑制 flood,也触发 ARP/ND suppression 能力
flood_suppress 在代码里有两层落地:
- Linux bridge/VXLAN netdevice 层。
- SAI VLAN flood control 层。
7.1 Linux netdevice 层
在 src/sonic-swss/cfgmgr/vxlanmgr.cpp 的 createVxlanNetdevice() 中,会拼出类似下面的命令:
bash
ip link add <vxlan_dev> address <switch_mac> type vxlan id <vni> local <src_ip> dstport 4789 ... proxy
bridge link set dev <vxlan_dev> neigh_suppress on
bridge link set dev <vxlan_dev> flood off
bridge link set dev <vxlan_dev> bcast_flood off
bridge link set dev <vxlan_dev> mcast_flood off
这里要分清两个动作:
proxy+neigh_suppress on:让 Linux bridge/VXLAN 具备邻居代答/抑制能力。flood off、bcast_flood off、mcast_flood off:抑制未知单播、广播和组播的 flood。
因此 flood_suppress 不只是 ARP 的开关,它更像是 VXLAN 二层域里 BUM 控制的开关。
7.2 SAI 层
src/sonic-swss/orchagent/vxlanorch.cpp 中,VxlanTunnelMapOrch::addOperation() 会读取 flood_suppress,并调用:
scss
gPortsOrch->setVlanFloodSuppress(vlan_id, flood_suppress_enable)
PortsOrch::setVlanFloodSuppress() 位于:
bash
src/sonic-swss/orchagent/portsorch.cpp
它把 VLAN 的 flood control 设置为:
bash
enable -> SAI_VLAN_FLOOD_CONTROL_TYPE_NONE
disable -> SAI_VLAN_FLOOD_CONTROL_TYPE_ALL
这说明 flood_suppress 最终会影响硬件 VLAN 的 unknown unicast 和 broadcast flood 行为。
流程图:
rust
flowchart TD
CMD[config vxlan flood-suppress enable VlanX] --> CDB[(CONFIG_DB\nVXLAN_TUNNEL_MAP.flood_suppress=true)]
CDB --> MGR[VxlanMgr::doVxlanTunnelMapCreateTask]
MGR --> NETDEV[createVxlanNetdevice]
NETDEV --> L1[ip link add ... proxy]
NETDEV --> L2[bridge link set ... neigh_suppress on]
NETDEV --> L3[bridge link set ... flood/bcast_flood/mcast_flood off]
MGR --> APP[(APPL_DB\nVXLAN_TUNNEL_MAP_TABLE)]
APP --> ORCH[VxlanTunnelMapOrch::addOperation]
ORCH --> PORTS[PortsOrch::setVlanFloodSuppress]
PORTS --> SAI[SAI VLAN flood control NONE]
8. redistribute_host:决定远端能不能学到 IP/MAC
ARP 问的是 IP 到 MAC 的映射。因此,远端 VTEP 想做 ARP 代答,不能只知道 MAC,还要知道 IP 对应哪个 MAC。
这正是 redistribute_host 的意义。
在本地代码 src/sonic-swss/orchagent/neighorch.cpp 中,本地主机邻居学习进入 NeighOrch::addNeighbor()。如果这个邻居属于 VLAN interface,并且该 VLAN 有 VNI 映射,代码会调用:
arduino
writeVxlanFdbEntry(vlan_name, macAddress, ip_address, vni, true)
writeVxlanFdbEntry() 里会判断:
ini
rd_host_enable = tunnel_orch->isRedistributeHostEnabled(vlan_id)
当 redistribute_host 打开时,写入 VXLAN_FDB_TABLE 的字段包含 ip:
ini
key: VlanX:<mac>
fields:
vni=<vni>
type=dynamic
remote_vtep=<local_vtep_ip>
ip=<host_ip>
当 redistribute_host 关闭时,写入的是 MAC-only:
ini
key: VlanX:<mac>
fields:
vni=<vni>
type=dynamic
remote_vtep=<local_vtep_ip>
差异非常关键:
| 模式 | EVPN 语义 | 对 ARP 代答的影响 |
|---|---|---|
| MAC-only Type-2 | 只告诉远端"这个 MAC 在哪个 VTEP 后面" | 远端不能仅凭 MAC-only 精确回答"某 IP 是哪个 MAC" |
| MAC+IP Type-2 | 告诉远端"这个 IP 对应这个 MAC,在这个 VTEP 后面" | 远端可以建立 IP/MAC 缓存,支持本地 ARP 代答 |
流程图:
sql
flowchart TD
HOST[本地主机产生邻居\nIP + MAC + VLAN] --> NEIGH[NeighOrch::addNeighbor]
NEIGH --> CHECK{VLAN 是否映射到 VNI?}
CHECK -- 否 --> NORMAL[普通邻居处理]
CHECK -- 是 --> WRITE[writeVxlanFdbEntry]
WRITE --> RD{redistribute_host enabled?}
RD -- 是 --> FDB1[(VXLAN_FDB_TABLE\n包含 ip 字段)]
RD -- 否 --> FDB2[(VXLAN_FDB_TABLE\n不包含 ip 字段)]
FDB1 --> TYPE2[EVPN MAC+IP Type-2]
FDB2 --> TYPE2M[EVPN MAC-only Type-2]
TYPE2 --> REMOTE[远端 VTEP 可用于 ARP 代答]
9. 远端 VTEP 与远端 MAC 如何进入本机
VXLAN 网络不只需要知道"本地主机在哪里",还需要知道"远端主机在哪里"。
远端 VTEP/VNI 信息主要体现在:
makefile
APPL_DB:VXLAN_REMOTE_VNI_TABLE
远端 MAC 信息主要体现在:
makefile
APPL_DB:VXLAN_FDB_TABLE
src/sonic-swss/fpmsyncd/fpmlink.cpp 中有一个很关键的判断:
rust
RTM_NEWNEIGH / RTM_DELNEIGH + AF_BRIDGE -> EVPN FDB handler
代码注释说明这类消息携带 remote VTEP 和 VNI 信息,用于 VXLAN tunnel setup。
整体流程可以理解成:
css
flowchart TD
RVTEP[远端 VTEP 学到 Host B\nIP/MAC/VNI] --> BGP[EVPN Type-2/Type-3]
BGP --> FRR[本机 FRR/bgpd]
FRR --> ZEBRA[zebra]
ZEBRA --> FPM[fpmsyncd]
FPM --> APP[(APPL_DB\nremote VNI / VXLAN FDB / route)]
APP --> ORCH[orchagent]
ORCH --> SAI[SAI tunnel / FDB / next-hop]
SAI --> DATA[本机数据面具备转发和代答基础]
10. SAI tunnel next-hop:为什么 TUNNEL_MAC 很重要
在 VXLAN overlay 路由场景中,数据面需要知道:
ini
外层目的 IP = remote VTEP IP
VNI = overlay 网络标识
内层目的 MAC = remote host/router MAC
在 src/sonic-swss/orchagent/vxlanorch.cpp 中,create_nexthop_tunnel() 会创建 SAI tunnel next-hop。代码里可以看到这些属性:
ini
SAI_NEXT_HOP_ATTR_TYPE = SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP
SAI_NEXT_HOP_ATTR_IP = remote VTEP IP
SAI_NEXT_HOP_ATTR_TUNNEL_ID = tunnel object
SAI_NEXT_HOP_ATTR_TUNNEL_VNI = VNI
SAI_NEXT_HOP_ATTR_TUNNEL_MAC = inner destination MAC
其中 SAI_NEXT_HOP_ATTR_TUNNEL_MAC 表示硬件下一跳不只是"发到哪个 VTEP",还知道内层要封装成哪个目的 MAC。
本地测试文件 src/sonic-swss/tests/evpn_tunnel.py 中也对 SAI_NEXT_HOP_ATTR_TUNNEL_MAC 做了检查,说明这是 EVPN/VXLAN overlay next-hop 的重要属性。
11. ARP Reply 报文本身是怎么构造的
上面讲的是 VXLAN/EVPN 主链路。代码里还有一块很适合教学的 ARP responder:
bash
src/sonic-restapi/arp_responder
它不是 VXLAN 主链路的全部,但可以直观看到"收到 ARP Request 后如何改成 ARP Reply"。
核心函数是:
vbnet
Arp::make_reply_from_request(const Interface& iface)
位于:
bash
src/sonic-restapi/arp_responder/arp.cc
它做的事情可以概括为:
- 以原 ARP Request 报文为基础。
- 把以太网目的 MAC 改成原请求方的源 MAC。
- 把 ARP opcode 改成
ARPOP_REPLY。 - 交换 ARP sender IP 和 target IP。
- 把 ARP target hardware address 改成原请求方 MAC。
- 用本接口 MAC 填充以太网源 MAC和 ARP sender hardware address。
流程图:
css
flowchart TD
REQ[收到 ARP Request] --> VALID[校验 ARP 报文]
VALID --> OP[opcode 改为 ARPOP_REPLY]
OP --> ETH[ether_dhost = 原请求方 MAC]
ETH --> IP[交换 sender IP 和 target IP]
IP --> MAC[arp_tha = 原 arp_sha]
MAC --> SRC[源 MAC 填成本接口 MAC]
SRC --> SEND[发送 ARP Reply]
arpresponder_bm.cc 的处理很直接:
css
ARPResponder::process(fd):
接收 RawArp
如果无效,丢弃
如果是 ARP Request:
arp.make_reply_from_request(*iface)
iface->send(...)
arpresponder_msee.cc 则多了控制面:
ADD_INTERFACE:添加接口。ADD_IP:记录某接口/tag 组合可代理的 IP。REQUEST_MAC_*:主动发 ARP Request 学习 MAC。process_intf():收到 ARP Request 后查proxy_arp表,命中才回复。
这段代码说明:ARP 代答报文动作并不复杂,难点在于"什么时候允许代答"和"代答所需的 IP/MAC 数据从哪里来"。
12. 一张总流程图:从学习到代答
css
flowchart TD
subgraph LocalLearn[本地主机学习]
H1[本地主机] -->|ARP/ND 学习| NO[NeighOrch::addNeighbor]
NO --> W[writeVxlanFdbEntry]
W --> RD{redistribute_host?}
RD -- enable --> L1[(VXLAN_FDB_TABLE\nMAC + IP)]
RD -- disable --> L2[(VXLAN_FDB_TABLE\nMAC only)]
L1 --> E1[EVPN MAC+IP Type-2]
L2 --> E2[EVPN MAC-only Type-2]
end
subgraph RemoteLearn[远端信息学习]
R1[远端 EVPN 路由/FDB] --> FRR[FRR/zebra]
FRR --> FPM[fpmsyncd]
FPM --> APP[(APPL_DB)]
APP --> OA[orchagent]
OA --> SAI[SAI/ASIC]
end
subgraph Suppress[ARP/BUM 抑制]
CFG[config vxlan flood-suppress] --> VM[vxlanmgrd]
VM --> NETDEV[Linux VXLAN netdevice proxy]
VM --> NS[bridge neigh_suppress]
VM --> FLOOD[bridge flood off]
VM --> VF[SAI VLAN flood control]
end
SAI --> ANSWER[本地具备 ARP 代答/抑制基础]
NETDEV --> ANSWER
NS --> ANSWER
13. 常用排查命令
13.1 看 VXLAN 配置
perl
sonic-db-cli CONFIG_DB keys 'VXLAN*'
sonic-db-cli CONFIG_DB hgetall 'VXLAN_TUNNEL|<vtep_name>'
sonic-db-cli CONFIG_DB hgetall 'VXLAN_TUNNEL_MAP|<vtep_name>|<map_name>'
sonic-db-cli CONFIG_DB hgetall 'VXLAN_REMOTE_VNI|Vlan100|<remote_vtep>'
sonic-db-cli CONFIG_DB hgetall 'VXLAN_FDB|Vlan100:<mac>'
13.2 看 APP_DB 是否生成
perl
sonic-db-cli APPL_DB keys 'VXLAN_TUNNEL_TABLE*'
sonic-db-cli APPL_DB keys 'VXLAN_TUNNEL_MAP_TABLE*'
sonic-db-cli APPL_DB keys 'VXLAN_REMOTE_VNI_TABLE*'
sonic-db-cli APPL_DB keys 'VXLAN_FDB_TABLE*'
13.3 看 show 命令
sql
show vxlan name
show vxlan vlanvnimap
show vxlan remotevni all
show vxlan remotemac all
show vxlan status
show vxlan remotevni 对应 src/sonic-utilities/show/vxlan.py 的 remotevni()。
show vxlan remotemac 对应 src/sonic-utilities/show/vxlan.py 的 remotemac(),它读取 VXLAN_FDB_TABLE。
13.4 看 Linux VXLAN/bridge 状态
sql
ip -d link show type vxlan
bridge link show
bridge fdb show
ip neigh show dev Vlan100
重点关注:
- VXLAN netdevice 是否存在。
bridge link show是否能看到neigh_suppress on。- flood/bcast_flood/mcast_flood 是否符合预期。
ip neigh是否存在目标 IP/MAC。- 远端 EVPN 学到的邻居是否带
extern_learn。
13.5 看 ASIC_DB
perl
sonic-db-cli ASIC_DB keys 'ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL*'
sonic-db-cli ASIC_DB keys 'ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL_MAP*'
sonic-db-cli ASIC_DB keys 'ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP*'
sonic-db-cli ASIC_DB keys 'ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY*'
如果 overlay next-hop 带内层 MAC,应该重点关注类似:
SAI_NEXT_HOP_ATTR_TUNNEL_MAC
SAI_NEXT_HOP_ATTR_TUNNEL_VNI
SAI_NEXT_HOP_ATTR_IP
13.6 抓包验证
xml
tcpdump -eni <access_port> arp
tcpdump -eni <underlay_port> udp port 4789
如果 ARP 代答命中,通常能看到:
- access 侧主机发出 ARP Request。
- 本地很快出现 ARP Reply。
- underlay 侧不应出现对应 ARP Request 被 VXLAN 封装后 flood 出去。
如果未命中且允许 flood,underlay 侧会看到 UDP 4789 的 VXLAN BUM 流量。
14. 常见问题
14.1 为什么配置了 VXLAN,ARP 代答还是不生效?
常见原因:
- VLAN 没有映射到 VNI。
- 本地或远端没有学到 IP/MAC 绑定。
- EVPN Type-2 只有 MAC,没有 IP。
redistribute_host被关闭,导致本地主机不带 IP 发布。flood_suppress未按预期打开。- Linux VXLAN netdevice 没有
proxy或 bridge port 没有neigh_suppress on。 - 远端 VTEP 没有加入对应 VNI,
VXLAN_REMOTE_VNI_TABLE缺失。
14.2 redistribute_host 和 flood_suppress 谁更重要?
它们解决的问题不同。
redistribute_host 决定"有没有 IP/MAC 关系可以被远端学习"。没有 MAC+IP,远端无法准确回答 ARP。
flood_suppress 决定"未知或广播流量是否继续 flood"。它能减少 BUM,但如果数据库里没有目标 IP/MAC,打开它也不能凭空生成正确 ARP Reply。
14.3 MAC-only Type-2 为什么不够?
ARP 问的是 IP,不是 MAC。MAC-only Type-2 只能告诉远端 MAC 的位置,不能告诉远端某个 IP 对应哪个 MAC。因此要做 ARP 代答,最好需要 MAC+IP Type-2。
14.4 ARP 代答是不是一定由 CPU 构造报文?
不一定。不同平台可能由 Linux bridge/VXLAN、ASIC 或控制面代理协同完成。本文基于本地 SONiC 代码能看到的是:配置面会打开 Linux VXLAN proxy、bridge neigh_suppress,并通过 SAI 设置 VLAN flood control;同时通过 EVPN/DB/SAI 建立远端 MAC/IP/VTEP/VNI 信息。具体数据面实现会和平台能力有关。
15. 推荐阅读代码顺序
如果第一次读 SONiC VXLAN 代码,建议不要从 orchagent 的大文件开始硬啃,可以按下面顺序来:
src/sonic-utilities/config/vxlan.py
先理解 CLI 写了哪些 CONFIG_DB 表。src/sonic-yang-models/yang-models/sonic-vxlan.yang
看 VXLAN 配置模型,理解VXLAN_TUNNEL_MAP、VXLAN_REMOTE_VNI、VXLAN_FDB。src/sonic-swss/cfgmgr/vxlanmgr.cpp
看VxlanMgr::doTask()如何分发配置,看createVxlanNetdevice()如何创建 Linux VXLAN netdevice。src/sonic-swss/orchagent/vxlanorch.cpp
看 tunnel、tunnel map、remote VNI 和 SAI tunnel next-hop 如何编排。src/sonic-swss/orchagent/neighorch.cpp
看本地邻居如何写入VXLAN_FDB_TABLE,以及redistribute_host如何影响ip字段。src/sonic-swss/orchagent/fdborch.cpp
看 VXLAN 学习到的 MAC 如何进入 FDB 处理流程。src/sonic-restapi/arp_responder/arp.cc
最后看 ARP Reply 报文如何被构造,加深对"代答"动作本身的理解。
16. 结语
VXLAN ARP 代答可以拆成两句话:
第一句,原理上它是为了减少 ARP 广播在 VXLAN overlay 中的 BUM 扩散。
第二句,工程上它依赖控制面提前学到 IP/MAC/VNI/VTEP,并把这些信息正确地下发到 Linux bridge/VXLAN netdevice、APP_DB、orchagent、SAI 和硬件。
结合本地 SONiC 代码,最值得抓住的两个开关是:
redistribute_host影响 MAC+IP Type-2 学习,是"能不能知道 IP/MAC"的问题。flood_suppress影响 proxy/neigh_suppress 和 flood control,是"未知流量还要不要扩散"的问题。
把这两点讲清楚,再顺着 config vxlan -> CONFIG_DB -> vxlanmgrd -> APP_DB -> orchagent -> SAI 的链路走,VXLAN ARP 代答就不再是一个黑盒功能了。