[vpp] Add MPLS data-plane support (INSEG + IP-route push) - #2008
Conversation
|
/azp run |
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
There was a problem hiding this comment.
Pull request overview
Adds MPLS data-plane programming to the VPP SAI backend (vslib/vpp) so SONiC MPLS dataplane tests can run on the sonic-vpp testbed. This introduces INSEG (local label) handling into VPP’s MPLS FIB, plus label imposition on IP routes via fib-path label stacks, and enables MPLS on router interfaces.
Changes:
- Implement INSEG (
SAI_OBJECT_TYPE_INSEG_ENTRY) create/remove handling by translating to VPP MPLS route programming (including eos handling and pop vs swap/push behavior). - Extend VPP translation/plumbing to support MPLS table/route APIs and fib-path label stacks for both MPLS routes and IP routes.
- Honor
SAI_ROUTER_INTERFACE_ATTR_ADMIN_MPLS_STATEto enable MPLS on the underlying VPP interface and ensure the MPLS table exists.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| vslib/vpp/vppxlate/SaiVppXlate.h | Adds MPLS label-stack limits and new MPLS route/nexthop structs + API declarations. |
| vslib/vpp/vppxlate/SaiVppXlate.c | Adds VPP MPLS API integration and implements MPLS table/route programming + label stacks on IP fib paths. |
| vslib/vpp/SwitchVppRoute.cpp | Propagates per-next-hop label stacks into VPP IP route programming. |
| vslib/vpp/SwitchVppRif.cpp | Enables/disables MPLS per RIF using VPP API and ensures MPLS table exists. |
| vslib/vpp/SwitchVppNexthop.h | Extends next-hop group member structure with MPLS label stack fields. |
| vslib/vpp/SwitchVppNexthop.cpp | Reads MPLS next-hop label stacks and resolves attached egress sw_if_index for labeled forwarding. |
| vslib/vpp/SwitchVppMpls.cpp | New INSEG→VPP MPLS FIB programming implementation (pop + swap/push). |
| vslib/vpp/SwitchVpp.h | Adds MPLS route helpers and tracks MPLS table creation state. |
| vslib/vpp/SwitchVpp.cpp | Dispatches INSEG create/remove to the new MPLS implementation. |
| vslib/Makefile.am | Adds the new SwitchVppMpls.cpp to the build. |
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
|
Thanks — both review comments were valid, and I've pushed fixes in 6c02b43. 1.
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.
Suppressed comments (2)
vslib/vpp/SwitchVppMpls.cpp:254
mpls_route_add_del()is invoked for multiple EOS keys, but rollback only happens on add. If a multi-EOS delete fails after removing one entry, the SAI object remains (because remove_internal is not reached) while some VPP FIB entries have already been removed, leaving dataplane state inconsistent with the in-memory object. Consider rolling back partial deletes (re-add any successfully removed EOS entries) the same way partial adds are rolled back.
if (ret != 0 && is_add) {
for (int e = 0; e < programmed; e++) {
route->eos = eos_list[e];
mpls_route_add_del(route, false);
}
vslib/vpp/vppxlate/SaiVppXlate.c:2820
ip_route_add_del_get_stats()now forwardsnexthop->n_labelsdirectly into the VPP API message. Ifn_labelsis ever >VPP_MPLS_MAX_LABELS, VPP will be told there are more labels than the message actually populates (only up to the max), which can lead to invalid API input. Clamp (or validate+fail)n_labelsbefore assigning it tofib_path->n_labels.
fib_path->n_labels = nexthop->n_labels;
for (uint8_t l = 0; l < nexthop->n_labels && l < VPP_MPLS_MAX_LABELS; l++) {
fib_path->label_stack[l].label = htonl(nexthop->label_stack[l]);
fib_path->label_stack[l].ttl = 64;
fib_path->label_stack[l].exp = 0;
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.
Suppressed comments (3)
vslib/vpp/vppxlate/SaiVppXlate.c:2621
mpls_route_add_del()storesroute->nexthop_cntinpath_countbut later writesmr->mr_n_paths = (u8)path_countwithout validating the range. Ifnexthop_cnt > 255, the value will truncate and the allocated message size (sizeof(vl_api_fib_path_t) * path_count) won’t match what gets encoded, leading to incorrect programming or a potential overrun.
path_count = route->nexthop_cnt;
vslib/vpp/vppxlate/SaiVppXlate.c:2666
- When
nexthop->hwif_namecan’t be resolved to a sw_if_index, the code currently falls back to~0and continues. For MPLS routes this can silently turn an intended attached path into a recursive one, which (per the PR’s own constraints) can result in traffic being dropped while the API still reports success. It’s safer to treat an unknownhwif_nameas an error and fail the operation.
} else if (nexthop->hwif_name) {
idx = get_swif_idx(vam, nexthop->hwif_name);
fib_path->sw_if_index = htonl(idx != (u32) -1 ? idx : (uint32_t)~0);
} else {
fib_path->sw_if_index = htonl((uint32_t)~0);
}
vslib/vpp/SwitchVppMpls.cpp:256
- The log message reports
out_labelsusingroute->nexthop[0].n_labels, but in the pop/disposition case the code injects an implicit-null label and setsn_labelsto 1. That makes the log misleading (it will show 1 out-label for a pop). Logging based onhas_outlabelspreserves the intended meaning.
SWSS_LOG_NOTICE("%s inseg label %u out_labels %u status %d",
(is_add ? "Add" : "Remove"), inseg_entry.label,
route->nexthop[0].n_labels, ret);
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
|
Pushed Fixed1. Valid, and the more important of the two. The code assigned It is currently unreachable — 2. Misleading Also valid. The pop case injects an implicit-null label and sets Declined, with reasoning3. Roll back partial deletes the way partial adds are rolled back I do not think this one should be actioned. Rolling back a failed delete means re-installing MPLS FIB entries during a teardown that is already failing — re-adding forwarding state for a next hop that is on its way out is worse than the transient inconsistency it would fix. It is also self-healing: 4. True in the abstract, but this matches the existing convention exactly: the neighbouring 5. Treat an unresolvable The fallback is deliberate and documented in Happy to revisit any of these three if a reviewer disagrees. VerificationRebuilt against VPP 2606 to match the sonic-vpp image — clean, zero warnings under Both changes here are on paths the functional tests already cover: the label-count clamp sits in the IP-route imposition path exercised by |
|
/azp run Azure.sonic-sairedis |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
Implement the VPP SAI backend for MPLS so the tests/mpls data-plane tests
can run on the sonic-vpp testbed (sonic-buildimage#25782).
INSEG (SAI_OBJECT_TYPE_INSEG_ENTRY) -> VPP MPLS FIB:
- SwitchVppMpls.cpp: translate INSEG add/remove into mpls_route_add_del.
- pop: inject an implicit-null out-label in UNIFORM LSP mode so the
disposition derives the inner IP TTL from the popped MPLS TTL.
- swap/push: read the SAI nexthop out-label stack, supplying the list
buffer so the read does not silently drop the labels (which turned a
swap into a bare pop).
- resolve the nexthop router interface to its VPP egress hwif so the
path is programmed attached, which is required for VPP to insert the
MPLS disposition and to resolve a labelled path.
- SwitchVppRif.cpp: honour SAI_ROUTER_INTERFACE_ATTR_ADMIN_MPLS_STATE
(sw_interface_set_mpls_enable + ensure the MPLS table exists).
IP route MPLS push (ingress LER):
- SwitchVppNexthop.{cpp,h} / SwitchVppRoute.cpp: carry the MPLS out-label
stack on IP-route next hops and impose it (gated on n_labels>0 so plain
IP routing is unchanged).
VPP API plumbing:
- SaiVppXlate.{c,h}: mpls_table_add_del, mpls_route_add_del and the MPLS
label stack on fib paths (for both mpls and ip routes).
Verified on vms-kvm-vpp-t1-lag: test_pop_label, test_swap_label and
test_swap_labelstack pass.
Signed-off-by: Augustine Lee <augustinelee@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Two defects found in review of the MPLS backend added by this PR. SAI_NEXT_HOP_ATTR_LABELSTACK is a list attribute. When the stack is deeper than VPP_MPLS_MAX_LABELS the get returns SAI_STATUS_BUFFER_OVERFLOW, sets count to the required size and copies nothing. Both label-stack reads tested only for SAI_STATUS_SUCCESS, so they fell through with zero labels and programmed a bare pop instead of a swap/push, silently misforwarding traffic. Handle BUFFER_OVERFLOW explicitly and fail with SAI_STATUS_NOT_SUPPORTED. Other failures still mean "no label stack", which is a valid pop path. The cnt > VPP_MPLS_MAX_LABELS clamps are removed: on SUCCESS the returned count can never exceed the supplied 16-entry buffer, so they were dead code that implied a bound check which never actually ran. MplsRouteAddRemove programs two FIB entries (eos=0 then eos=1) for a swap/push. If eos=0 succeeded and eos=1 failed, the eos=0 entry was left programmed in VPP with no SAI object referring to it, because addMplsRoute returns via CHECK_STATUS before setting route_programmed. Unwind whatever the loop managed to program. Removing an entry that was never added is normalized to success by vpp_normalize_ret. Signed-off-by: Augustine Lee <augustinelee@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 251d571f-a53b-47f8-9eb4-293dbc6ff7a4
Move MPLS_DEFAULT_OUT_TTL into SaiVppXlate.h so both label-imposition paths use it. The IP-route push path in ip_route_add_del_get_stats hardcoded 64 while SwitchVppMpls.cpp defined the same value as a named constant. Also document why vpp_ip_nexthop_t carries a bare uint32_t label stack while vpp_mpls_nexthop_t carries a full vpp_mpls_label_t: the TTL of a label imposed on an IP path is derived from the IP header, so there is no per-label ttl/exp to express there. No functional change. Signed-off-by: Augustine Lee <augustinelee@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 251d571f-a53b-47f8-9eb4-293dbc6ff7a4
Two issues raised by the automated reviewer. ip_route_add_del_get_stats assigned nexthop->n_labels straight into fib_path->n_labels while only populating up to VPP_MPLS_MAX_LABELS entries. A deeper stack would tell VPP the message carries more labels than it actually does. Clamp before assigning, so the count and the populated entries always agree. mpls_route_add_del already validates this and returns -EINVAL; the IP path had no equivalent. MplsRouteAddRemove logged route->nexthop[0].n_labels as the out-label count, but the pop case injects an implicit-null label and sets n_labels to 1, so a pop was logged as having one out-label. Report the SAI-visible count instead. Signed-off-by: Augustine Lee <augustinelee@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 251d571f-a53b-47f8-9eb4-293dbc6ff7a4
Upstream commit 51fe70f ([vslib] Add support for SPAN mirror sessions, sonic-net#1920) landed after this branch was cut and added its own get_sw_if_idx(). Both definitions merge cleanly textually but the result does not compile: SaiVppXlate.c:5494:5: error: redefinition of 'get_sw_if_idx' Remove ours and use the upstream one, which is strictly better: it takes VPP_LOCK() around get_swif_idx(). The not-found result is unchanged, since (int)(u32)-1 == -1, which is what our version returned explicitly. Signed-off-by: Augustine Lee <augustinelee@microsoft.com>
14401c7 to
de99c7a
Compare
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
|
Rebased onto current master ( What brokeTwo consecutive builds failed at Compile sonic sairedis with coverage enabled: This is a semantic merge conflict, which is why it wasn't visible earlier:
Git merges both cleanly — the PR reported FixDropped ours and kept the upstream definition, which is strictly better: it takes No header change was needed: the VerificationFull CI replication in
The four functional commits are unchanged by the rebase; only the new fifth commit differs. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.
Suppressed comments (1)
vslib/vpp/vppxlate/SaiVppXlate.c:2953
- sw_interface_set_mpls_enable() normalizes the VPP return code as if the operation is always an "add" (vpp_normalize_ret(..., false)). For enable/disable toggles, disable behaves like a delete in terms of idempotency (similar to sw_interface_ip6_enable_disable), so repeated disables can legitimately return NO_SUCH_ENTRY and should be treated as success. Using !enable here avoids failing router-interface create/update when MPLS is already disabled/enabled.
ret = vpp_normalize_ret(ret, false, __func__);
|
CI is green on the rebased head That includes the two jobs that were failing before the rebase - For anyone reviewing the timeline: the earlier red builds were the |
| route->label = inseg_entry.label; | ||
| route->is_multipath = false; | ||
| route->nexthop_cnt = 1; | ||
| route->eos_proto_af = AF_INET; |
There was a problem hiding this comment.
can you derive eos_proto_af from nexthop family, instead of hardcode?
| uint32_t cnt = attr.value.u32list.count; | ||
| nxt_grp_member->n_labels = (uint8_t)cnt; | ||
| for (uint32_t li = 0; li < cnt; li++) { | ||
| nxt_grp_member->label_stack[li] = attr.value.u32list.list[li]; |
There was a problem hiding this comment.
can we set label stack is_uniform and ttl value based on sai attribute SAI_NEXT_HOP_ATTR_OUTSEG_TTL_MODE and SAI_NEXT_HOP_ATTR_OUTSEG_TTL_VALUE?
| sai_attribute_t port_attr; | ||
| port_attr.id = SAI_ROUTER_INTERFACE_ATTR_PORT_ID; | ||
| if (have_rif && | ||
| get(SAI_OBJECT_TYPE_ROUTER_INTERFACE, nxt_grp_member->rif_oid, 1, &port_attr) == SAI_STATUS_SUCCESS && |
There was a problem hiding this comment.
minor: you can use get_linked_object to get rif object from nexthop
| fib_path->label_stack[l].label = htonl(nexthop->label_stack[l]); | ||
| fib_path->label_stack[l].ttl = MPLS_DEFAULT_OUT_TTL; | ||
| fib_path->label_stack[l].exp = 0; | ||
| fib_path->label_stack[l].is_uniform = 1; |
There was a problem hiding this comment.
Can we support ttl/qos mode and ttl/exp value from SAI attribute instead of hardcode here? It seems not requiring a lot of code
| _In_ const sai_attribute_t *attr_list); | ||
| sai_status_t removeMplsRoute( | ||
| _In_ const std::string &serializedObjectId); | ||
| sai_status_t MplsRouteAddRemove( |
| route->nexthop[0].label_stack[0].label = MPLS_IMPLICIT_NULL_LABEL; | ||
| route->nexthop[0].label_stack[0].ttl = 0; | ||
| route->nexthop[0].label_stack[0].exp = 0; | ||
| route->nexthop[0].label_stack[0].is_uniform = 1; |
There was a problem hiding this comment.
should we set is_uniform based on SAI_INSEG_ENTRY_ATTR_POP_TTL_MODE?
Description of PR
Summary:
Part of sonic-net/sonic-buildimage#25782
Adds MPLS data-plane support to the VPP SAI backend so the
tests/mplsdata-planetests can run on the sonic-vpp testbed. Today
SAI_OBJECT_TYPE_INSEG_ENTRYis nothandled at all in
vslib/vpp, so MPLS traffic is never programmed into VPP.Note
Companion PR sonic-net/sonic-mgmt#26619 enables
mpls/test_mpls.pyon sonic-vpp anddepends on this change being in the image, so it merges after this one.
Type of change
Approach
What is the motivation for this PR?
sonic-buildimage#25782 asks for MPLS support in sonic-vpp so that
mpls/test_mpls.pycan be enabled on the VPP KVM testbed. The tests currently can't run because the VPP
SAI backend has no INSEG handling.
Work item tracking
How did you do it?
10 files, +737 / -5, all under
vslib/vpp:vslib/vpp/SwitchVppMpls.cpp(new)vslib/vpp/SwitchVpp.{cpp,h}SAI_OBJECT_TYPE_INSEG_ENTRYfromcreate()/remove(); declare the MPLS helpers and the MPLS-table state.vslib/vpp/SwitchVppNexthop.{cpp,h}n_labelsis explicitly zeroed infillNHGrpMember().vslib/vpp/SwitchVppRoute.cppn_labels > 0.vslib/vpp/SwitchVppRif.cppSAI_ROUTER_INTERFACE_ATTR_ADMIN_MPLS_STATE(sw_interface_set_mpls_enable, ensure the MPLS table exists).vslib/vpp/vppxlate/SaiVppXlate.{c,h}mpls_table_add_del(),mpls_route_add_del(), and the label stack on fib paths for both MPLS and IP routes.vslib/Makefile.amDetails worth a reviewer's attention:
derives the inner IP TTL from the popped MPLS TTL. Without it VPP defaults the
disposition to PIPE and the inner TTL is only decremented once by the IP stage.
SAI_NEXT_HOP_ATTR_LABELSTACKis a list attribute, so the output buffer has to be supplied before the get,
otherwise the read fails and the labels are silently dropped - which turns a swap
into a bare pop.
programmed attached rather than recursive. VPP only inserts the MPLS disposition
for an attached next hop, and a recursive labelled path fails to resolve and is
dropped at the MPLS DROP DPO.
{label, eos}, so eos=1 is always programmed and eos=0 as well when out-labels arepresent, so a non-bottom label in a stack is handled.
mpls_route_add_del()validates every path (address family and label count) beforeallocating the API message, matching what
ip_route_add_del_get_stats()already does,so the error path can't leak the message.
Status is propagated the same way the neighbouring
addIpRoute()/removeIpRoute()do it:
addMplsRoute()rolls back the VPP programming ifcreate_internal()fails,and
ensureMplsTable()only latches its "created" flag once the table really exists.How did you verify/test it?
With this change in the image. A throwaway sonic-buildimage build carrying this PR
produced image
SONiC.master-28652.1177040-4e2ccc26c. Run on avms-kvm-vpp-t1-lagKVMtestbed together with the companion sonic-mgmt PR, ElasticTest plan
6a69da68f481df03c4e59c5e- SUCCESS, 22 tests, 17 passed / 5 skipped / 0 failed /0 errors:
Without this change in the image (negative control). The dependency was verified
rather than assumed. The identical test code, run by the
t1-lag-vppPR checker on astock sonic-vpp image that does not carry this PR, fails:
(ElasticTest plan
6a70603deb2c1b23503d2e2f, build 1182699; same signature on theearlier build 1178163.)
mpls/test_mpls.pyis the only failure in that run - the jobexecutes the whole
t1-lag-vpplist. That is exactly the gap this PR closes.Regression check. The same image also ran the full
t1-lag-vppsuite(1762 tests, 1222 passed) to check this doesn't regress anything else on VPP.
test_push_labelis skipped for a reason outside this change: it injects the pushroute directly into
ROUTE_TABLEand orchagent does not install that route intoASIC_DB, so it never reaches the SAI backend.
Any platform specific information?
sonic-vpp only - everything is under
vslib/vpp. Non-MPLS traffic is unaffected: theINSEG path only runs for INSEG objects, the next-hop label handling is gated on
SAI_NEXT_HOP_TYPE_MPLS, and label imposition is gated onn_labels > 0.Known limitations, called out deliberately rather than half-implemented - happy to
follow up on any of these if reviewers would prefer them in scope:
eos_proto_afis IPv4.set()does not reprogram VPP (create/remove only).NUM_OF_POP> 1, and non-default POP TTL/QoS modes, are not implemented.Documentation
No user-facing documentation change.