Skip to content

vpp: support punting ARP, LLDP, LACP, DHCP via member interface in VLAN (re-opened) - #1981

Merged
yejianquan merged 4 commits into
sonic-net:masterfrom
dypet:vlan_bvi_new
Jul 15, 2026
Merged

yejianquan merged 4 commits into
sonic-net:masterfrom
dypet:vlan_bvi_new

Conversation

@dypet

@dypet dypet commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Description of PR

Summary:
Fixes #26936

Opening PR for #1959 while original owner is out of office.

Type of change

  • Bug fix
  • New feature
  • Refactor / cleanup
  • Documentation update
  • Test improvement

Approach

What is the motivation for this PR?

SONiC on the VPP virtual-switch platform needs L2 bridging with an L3 SVI (VLAN interface) for both tagged and untagged VLAN members. The standard SONiC data model (VLAN + VLAN_INTERFACE with an IP + VLAN_MEMBER tagged/untagged) maps to a VPP bridge-domain (BD) with a Bridge Virtual Interface (BVI), but VPP does not wire this up to SONiC's punt model out of the box. Two problems had to be solved:

No per-member control-plane punt. SONiC expects the NPU to punt control traffic (ARP, LLDP, LACP, DHCP, and L3-to-SVI) to the member interface so Linux sees frames on the same netdev it would on real hardware — never on a virtual Vlan/PortChannel netdev directly. VPP's BVI is a purely internal L3 endpoint with no kernel-facing punt path, so the original member ingress (and its wire VLAN tag) is lost once a frame is bridged/flooded.

DHCP must be trapped, not flooded. A DHCP client broadcast (dst=ff:ff:ff:ff:ff:ff) entering the BD would hit l2-flood and fan out to every other member port, which sonic-mgmt's DHCPBroadcastNotFloodedTest forbids — a real ASIC traps DHCP to the CPU and removes it from the forwarding pipeline (SAI_PACKET_ACTION_TRAP). Routing DHCP through the BVI/L3 path is also wrong: it can't disambiguate which bridge the discover came from, and the L3 path subjects DHCP to IP/UDP checksum validation that drops malformed frames the control plane is supposed to count.

This PR implements the VPP-VS data path for VLAN BVI plus the SAI/classify plumbing needed to punt control traffic to the correct member interface. Design details are in vlan-bvi-hld.md (sonic-buildimage).

Work item tracking
  • Microsoft ADO (number only):

How did you do it?

VLAN BVI + members (SwitchVppFdb.cpp, SwitchVppRif.cpp, SwitchVppHostif.cpp): create a BVI per SVI and add it to the bridge domain. Tagged members join via a dot1q sub-interface with symmetric VTR (pop 1/push); untagged members join the BD directly. Explicit LCP pairs are created for sub-port RIFs (since lcp-auto-subint is disabled), and promiscuous mode is enabled on each phy so tagged frames reach VPP.

L2 classifier punt (SwitchVppFdb.cpp): attach l2-input-classify tables to each member that match LLDP and DHCPv4 client broadcasts before l2-flood, so they are trapped to the CPU instead of flooded (emulating SAI_PACKET_ACTION_TRAP). Untagged DHCP punts straight to linux-cp-punt; tagged DHCP goes through sonic-ext-l2-trap-fixup to reach the parent phy's host tap with its .1Q tag intact.

New VPP API wrappers (SaiVppXlate.c/.h): classify table create/delete, session add/del, set-interface-l2-tables, add-node-next, and set-promiscuous.

WR macro timeout change. The previous WR macro waited up to a fixed 1 second for a reply. Under bursts of unsolicited events (link state, counters, etc.) the reply-queue can be saturated long enough for that budget to elapse before our reply is drained, producing spurious -99 failures in unrelated call sites. The macro now uses a 10s hard cap with a 1s idle cap that resets on each processed message.

How did you verify/test it?

Verified on the sonic-vpp platform with sonic-mgmt DHCP relay tests (DHCP punted to the member tap, not flooded — DHCPBroadcastNotFloodedTest) and LLDP/ARP punt landing on the correct member netdev for both tagged and untagged members.

Any platform specific information?

Documentation

202605 backport validation

Back port request

  • 202605

Tested branch

  • 202605

Test result

dypet added 2 commits July 8, 2026 14:09
Signed-off-by: dypet <dypeters@cisco.com>
Signed-off-by: dypet <dypeters@cisco.com>
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dypet
dypet marked this pull request as ready for review July 8, 2026 18:28
@dypet dypet changed the title Vlan bvi new vpp: support punting ARP, LLDP, LACP, DHCP via member interface in VLAN (re-opened) Jul 8, 2026
lolyu
lolyu previously approved these changes Jul 9, 2026

@lolyu lolyu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving at head f9cb68e.

This is #1959 re-opened (original owner OOO). I reviewed #1959 earlier with five findings; since this is a new PR number, that inline history doesn't carry over, so here's the status verified against source at this head:

Resolved (4/5):

  1. Null-deref in the new reply handlers (the one real bug) — fixed. classify_add_del_table, get_next_index, and add_node_next handlers now all guard if (msg->context) { ...; if (ptr) {...} }, so a stale/duplicate reply (NULL from get_index_ptr on generation mismatch) can no longer be dereferenced. Matches the create_subif guard pattern.
  2. l2_punt_classify_apply return value — now checked. Both call sites in vpp_create_vlan_member log a WARN on failure with an explicit best-effort comment; a member no longer silently reports success with punt unconfigured.
  3. Lazy-init threading assumption — documented. l2_punt_classify_init now states it's called only from the single SAI processing thread, so the s_* globals need no locking.
  4. WR macro change — now disclosed. The description has a dedicated "WR macro timeout change" section explaining the 1s→10s hard cap / 1s idle-cap rationale. That was my ask: it's a cross-cutting change to all ~67 WR call sites and shouldn't ride silently in a feature PR. Sound change, now called out. (Minor, non-blocking: worth confirming vl_socket_client_read(1) == 0 reliably means "one message processed" and can't refresh the idle deadline on a spurious wakeup.)

One non-blocking cleanup remains (inline): vpp_classify_table_delete / vpp_classify_session_del are still dead — defined and exported but never called; l2_punt_classify_remove only detaches tables, never deletes them (tables are process-lifetime by design). Either drop them + the header decls, or add a one-line note that they're kept intentionally. Cleanup, not a blocker.

The core design is unchanged and remains excellent — the l2-input-classify slot-selection reasoning (IP4 vs OTHER by outer ethertype, the tagged/untagged offset math, why LACP and tagged-LLDP bypass the BD) is genuinely well-documented. The one substantive bug is fixed and verified. Approving; please tidy the dead wrappers in a follow-up or a quick push.

return ret;
}

int vpp_classify_table_delete(uint32_t table_index)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Non-blocking — dead code (carried over from #1959). vpp_classify_table_delete (here) and vpp_classify_session_del (~L4487) are defined and declared in the header but never called anywhere — verified across SaiVppXlate.c and SwitchVppFdb.cpp. l2_punt_classify_remove only detaches tables from the interface via vpp_classify_set_interface_l2_tables(hwif, ~0, ~0, ~0); it never deletes a table or session, and the classify tables are process-lifetime by design. So these two wrappers are unused exported API. Suggest either dropping them + their header decls, or adding a one-line comment noting the tables are intentionally process-lifetime and the delete wrappers are kept for symmetry/future teardown. Cleanup only — not blocking the approval.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping for symmetry of the add/del pair and to avoid a follow-up PR when needed.

@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Signed-off-by: dypet <dypeters@cisco.com>
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@dypet
dypet requested a review from lolyu July 9, 2026 15:03
@dypet

dypet commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

@lolyu , @yejianquan , please help review and merge.

@yejianquan yejianquan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@yejianquan
yejianquan merged commit cfe265d into sonic-net:master Jul 15, 2026
19 checks passed
@vaibhavhd

Copy link
Copy Markdown
Contributor

[Exception] Approved. This is a new feature. The cherry pick rules prohibit feature picks. Since this change is limited to vslib I am signing off. Please still update the PR with a justification for this exception according to you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[sonic-vpp][Data Plane][t0] Vlan1000 is not responding to ARP request from ptf

6 participants