[Dualtor][Prefix-route]: Fix NHG member stale OID causing remove failure on dualtor prefix-route mode - #4886
rajkumar1-arista wants to merge 3 commits into
Conversation
On dualtor topologies with neighbor_mode=prefix-route, when mux cables transition to standby, MuxPrefixBasedNbrHandler::disable() calls invalidnexthopinNextHopGroup() to remove NHG members from SAI. Unlike MuxNbrHandler (host-route mode) which always pairs invalidnexthop with validnexthop to swap members, the prefix-route handler intentionally does not add tunnel replacements. route-to-tunnel redirection is handled separately via setBulkRouteNH() at the per-prefix level. However, invalidnexthopinNextHopGroup() does not update the in-memory nhopgroup_members map after removing members from SAI. The stale SAI OIDs persist in the map. When the route is later deleted, removeNextHopGroup() reads these stale OIDs and submits them to the ObjectBulker for bulk removal. SAI meta validation fails with SAI_STATUS_ITEM_NOT_FOUND for the first stale OID, and SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR causes remaining members to get SAI_STATUS_NOT_EXECUTED. This triggers handleSaiFailure(), setting a persistent orchagent unhealthy flag that floods syslog with ERR messages every ~1 second. Fix invalidnexthopinNextHopGroup() to set the member OID to SAI_NULL_OBJECT_ID after successful SAI removal, preserving seq_id for ordered ECMP re-add. Fix removeNextHopGroup() to skip members with SAI_NULL_OBJECT_ID since they are already removed from SAI. Add missing UTs and swss tests Signed-off-by: rajkumar1 <rajkumar1@arista.com>
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
|
This PR has backport request for branch(es): 202605. ---Powered by SONiC BuildBot
|
|
The Tested branch section has been ticked and Test result is provided for branch(es): 202605. Added label(s): Tested for 202605 Branch. ---Powered by SONiC BuildBot
|
|
Hi @Ndancejic - can you help review? |
|
Looks good to me! @rajkumar1-arista have you tested with both prefix and host route mode to confirm the behavior for host route mode hasn't changed? |
|
@manamand2020 for review as well |
|
LGTM. @rajkumar1-arista do you want to verify the nexthop ref count as well in the tests since invalidnexthopinNextHopGroup() only removes SAI members; NeighOrch refcount is unchanged until the NHG itself is destroyed. |
Yes, this was verified for host-route mode. Click to expandadmin@gd274:~$ show version --brief
SONiC Software Version: SONiC.branch.202605-ars.34c55f68-buildimage.94f39efbfba9878881126e45c3b926decb74dd48-review.801796.6-2026.09.15.21.27
SONiC OS Version: 13
Distribution: Debian 13.7
Kernel: 6.12.41+deb13-sonic-amd64
Build commit: 2c28d7a75
Build date: Tue Sep 15 22:15:20 UTC 2026
Built by: jenkins@jenkins-arsonic-k8s-arsonic-backend-k8s-117770-cqt2r-g680m
Platform: x86_64-arista_7260cx3_64
HwSKU: Arista-7260CX3-D108C8
ASIC: broadcom
ASIC Count: 1
Serial Number: SSJ18010321
Model Number: DCS-7260CX3-64
Hardware Revision: 03.00
Uptime: 05:40:51 up 22:45, 1 user, load average: 1.50, 1.54, 1.36
Date: Thu 17 Sep 2026 05:40:51
admin@gd274:~$ sudo grep "SAI_STATUS_NOT_EXECUTED" /var/log/syslog | tail -5
admin@gd274:~$
admin@gd274:~$
admin@gd274:~$ show mux config | head -8
SWITCH_NAME PEER_TOR
------------- ----------
gd333 10.1.0.33
port state ipv4 ipv6 cable_type soc_ipv4 soc_ipv6 prober_type neighbor_mode
----------- ------- --------------- ----------------- ------------ ---------- ---------- ------------- ---------------
Ethernet0 auto 192.168.0.2/32 fc02:1000::2/128 software host-route
Ethernet4 auto 192.168.0.3/32 fc02:1000::3/128 software host-route
Ethernet8 auto 192.168.0.4/32 fc02:1000::4/128 software host-route
admin@gd274:~$
admin@gd274:~$
admin@gd274:~$ show mux status | head -5
PORT STATUS SERVER_STATUS HEALTH HWSTATUS LAST_SWITCHOVER_TIME
----------- -------- --------------- --------- ---------- ---------------------------
Ethernet0 standby standby unhealthy consistent 2026-Sep-16 13:06:18.366025
Ethernet4 standby standby unhealthy consistent 2026-Sep-16 13:06:17.726109
Ethernet8 standby standby unhealthy consistent 2026-Sep-17 04:49:28.457891
admin@gd274:~$
admin@gd274:~$ sudo config mux mode active Ethernet4
port state
--------- ----------
Ethernet4 INPROGRESS
admin@gd274:~$ sudo config mux mode active Ethernet8
port state
--------- ----------
Ethernet8 INPROGRESS
admin@gd274:~$ show mux status | head -5
PORT STATUS SERVER_STATUS HEALTH HWSTATUS LAST_SWITCHOVER_TIME
----------- -------- --------------- --------- ---------- ---------------------------
Ethernet0 standby standby unhealthy consistent 2026-Sep-16 13:06:18.366025
Ethernet4 active active unhealthy consistent 2026-Sep-17 05:41:34.602152
Ethernet8 active active unhealthy consistent 2026-Sep-17 05:41:39.322464
admin@gd274:~$ sudo ip neigh replace 192.168.0.3 lladdr aa:bb:cc:dd:ee:01 dev Vlan1000
admin@gd274:~$ sudo ip neigh replace 192.168.0.4 lladdr aa:bb:cc:dd:ee:02 dev Vlan1000
admin@gd274:~$ sudo config route add prefix 9.9.9.0/24 nexthop 192.168.0.3,192.168.0.4
admin@gd274:~$ show ip route 9.9.9.0/24
Routing entry for 9.9.9.0/24
Known via "static", distance 1, metric 0, best
Last update 00:00:09 ago
* 192.168.0.3, via Vlan1000
* 192.168.0.4, via Vlan1000
admin@gd274:~$ sudo config mux mode standby Ethernet4
port state
--------- ----------
Ethernet4 INPROGRESS
admin@gd274:~$ sudo config mux mode standby Ethernet8
port state
--------- ----------
Ethernet8 INPROGRESS
admin@gd274:~$ show mux status | head -5
PORT STATUS SERVER_STATUS HEALTH HWSTATUS LAST_SWITCHOVER_TIME
----------- -------- --------------- --------- ------------ ---------------------------
Ethernet0 standby standby unhealthy consistent 2026-Sep-16 13:06:18.366025
Ethernet4 standby standby unhealthy consistent 2026-Sep-17 05:42:43.686706
Ethernet8 standby standby unhealthy consistent 2026-Sep-17 05:42:47.686158
admin@gd274:~$ sudo config route del prefix 9.9.9.0/24
admin@gd274:~$ sudo grep "SAI_STATUS_NOT_EXECUTED" /var/log/syslog | tail -5
admin@gd274:~$ sudo grep "SAI_STATUS_NOT_EXECUTED" /var/log/syslog | wc -l
0
admin@gd274:~$ |
Signed-off-by: rajkumar1 <rajkumar1@arista.com>
|
/azp run |
Thanks, added in the UT |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
Why I did it
Fixes: #4885
On dualtor topologies with
neighbor_mode: prefix-route, deleting an ECMPstatic route after all its nexthop mux cables have transitioned to standby
causes a persistent orchagent failure. The
SAI_API_NEXT_HOP_GROUPremoveoperation fails with
SAI_STATUS_NOT_EXECUTED.When mux cables go to standby,
MuxPrefixBasedNbrHandler::disable()callsinvalidnexthopinNextHopGroup()to remove NHG members from SAI. Unlike thehost-route handler which always pairs invalidate with validate to swap members,
the prefix-route handler intentionally does not add tunnel replacements —
route-to-tunnel redirection is handled separately via
setBulkRouteNH().However,
invalidnexthopinNextHopGroup()does not update the in-memorynhopgroup_membersmap after removing members from SAI. The stale OIDs remainin the map. When the route is later deleted,
removeNextHopGroup()reads thesestale OIDs and submits them for bulk removal. SAI meta validation fails with
SAI_STATUS_ITEM_NOT_FOUND, andSAI_BULK_OP_ERROR_MODE_STOP_ON_ERRORcausesthe remaining members to get
SAI_STATUS_NOT_EXECUTED.The issue does not occur with
neighbor_mode: host-routebecause that handleralways calls
validnexthopinNextHopGroup()after invalidation, which overwritesthe stale OID with a fresh one.
Work item tracking
How I did it
invalidnexthopinNextHopGroup(), set the member OID toSAI_NULL_OBJECT_IDafter successful SAI removal. This preservesseq_idfor ordered ECMP re-add via
validnexthopinNextHopGroup()while clearlymarking the member as already removed from SAI.
removeNextHopGroup(), skip members whose OID isSAI_NULL_OBJECT_IDsince they have already been removed from SAI.
RemoveNhgAfterAllMembersInvalidatedWithoutReplacement)that exercises the exact sequence: create ECMP route, invalidate all members
without replacement, delete route and verifies no SAI failures occur.
test_multi_nexthop_all_standby_then_delete_route)that creates an ECMP route while mux is active, transitions all mux ports to
standby, deletes the route, and verifies: NHG members are cleaned up from
ASIC DB, no SAI error is logged, and orchagent remains healthy.
How to verify it
On an active-standby DualToR device with
neighbor_mode: prefix-route:RemoveNhgAfterAllMembersInvalidatedWithoutReplacementin
tests/mock_tests/routeorch_ut.cpp.test_multi_nexthop_all_standby_then_delete_routeintests/test_mux_prefixroute.py.Which release branch to backport (provide reason below if selected)
Tracking issue/work item for backport/cherry-pick request (GitHub issue or Microsoft ADO): #4885
Failure type: day-one issue
Reason for backport: the issue is reproducible on 202605 active-standby
DualToR setups with
neighbor_mode: prefix-routeand causes sonic-mgmt tests likeroute/test_static_route.pyto fail due to presence of syslog error that is being caught by logAnalyzerTested branch
Test result
202605: SONiC.branch.202605-ars.f113c325-buildimage.ccd774c0f0bab05d35518f9fab1ac40a401b5ca1-review.801796.5-2026.09.13.15.46 -
Passing_test_static_route.xml
NHG_bug_fixed.log
Description for the changelog
Fix NHG member stale OID causing SAI remove failure on dualtor with prefix-route neighbor mode.
Link to config_db schema for YANG module changes
N/A — no YANG or config_db schema changes.
A picture of a cute animal (not mandatory but encouraged)