VXLAN 中的 ARP 代答:从原理到 SONiC 代码实现

本文基于本地 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 VXLAN proxy、bridge neigh_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 网络通常希望:

  1. 控制面提前学习 IP/MAC/VTEP/VNI 关系。
  2. 数据面在 ARP Request 到达时优先本地回复。
  3. 对未知流量进行 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_MAPVXLAN_REMOTE_VNIVXLAN_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_labelrouter_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.pytest_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。后续由 vxlanmgrdorchagent 消费 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 在代码里有两层落地:

  1. Linux bridge/VXLAN netdevice 层。
  2. SAI VLAN flood control 层。

7.1 Linux netdevice 层

src/sonic-swss/cfgmgr/vxlanmgr.cppcreateVxlanNetdevice() 中,会拼出类似下面的命令:

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 offbcast_flood offmcast_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

它做的事情可以概括为:

  1. 以原 ARP Request 报文为基础。
  2. 把以太网目的 MAC 改成原请求方的源 MAC。
  3. 把 ARP opcode 改成 ARPOP_REPLY
  4. 交换 ARP sender IP 和 target IP。
  5. 把 ARP target hardware address 改成原请求方 MAC。
  6. 用本接口 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.pyremotevni()

show vxlan remotemac 对应 src/sonic-utilities/show/vxlan.pyremotemac(),它读取 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 代答命中,通常能看到:

  1. access 侧主机发出 ARP Request。
  2. 本地很快出现 ARP Reply。
  3. 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_hostflood_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 的大文件开始硬啃,可以按下面顺序来:

  1. src/sonic-utilities/config/vxlan.py
    先理解 CLI 写了哪些 CONFIG_DB 表。
  2. src/sonic-yang-models/yang-models/sonic-vxlan.yang
    看 VXLAN 配置模型,理解 VXLAN_TUNNEL_MAPVXLAN_REMOTE_VNIVXLAN_FDB
  3. src/sonic-swss/cfgmgr/vxlanmgr.cpp
    VxlanMgr::doTask() 如何分发配置,看 createVxlanNetdevice() 如何创建 Linux VXLAN netdevice。
  4. src/sonic-swss/orchagent/vxlanorch.cpp
    看 tunnel、tunnel map、remote VNI 和 SAI tunnel next-hop 如何编排。
  5. src/sonic-swss/orchagent/neighorch.cpp
    看本地邻居如何写入 VXLAN_FDB_TABLE,以及 redistribute_host 如何影响 ip 字段。
  6. src/sonic-swss/orchagent/fdborch.cpp
    看 VXLAN 学习到的 MAC 如何进入 FDB 处理流程。
  7. 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 代答就不再是一个黑盒功能了。

相关推荐
计算机毕设定制辅导-无忧学长1 小时前
《基于SpringBoot的马术俱乐部管理系统》
java·spring boot·后端
摇滚侠1 小时前
《SpringBoot 3:入门与应用实战》第 12 章 JDBC 与事务 JDBC 事务管理 阅读笔记 33
spring boot·笔记·后端
学长毕业设计2 小时前
基于SpringBoot的民间艺术传承管理系统(源码+文档+讲解视频)
java·spring boot·后端
小蒜学长2 小时前
基于Springboot+Vue的环保行动志愿者招募系统设计与实现(代码+数据库+LW)
java·数据库·vue.js·spring boot·后端
用户233376852182 小时前
Ubuntu上fpm多架构打包实战
后端
JavaGuide3 小时前
轻量开源版 IDEA 来了!
前端·后端
Json____3 小时前
springboot开发高校选课管理系统:从零构建前后端分离的全栈实践
java·spring boot·后端·毕业设计·毕设·wwwoop.com
站大爷IP3 小时前
Python的列表推导式把我写崩了,原来圆括号和方括号不是一回事
后端
梦在远山后3 小时前
Python 中字符串常用写法
人工智能·后端