From f7d733de4dad0e081f4fece690c295c729377468 Mon Sep 17 00:00:00 2001 From: mssonicbld <79238446+mssonicbld@users.noreply.github.com> Date: Thu, 25 Jun 2026 04:13:17 +1000 Subject: [PATCH] [dashhaorch]: Update in-memory ha_role on HA scope set (#4659) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What I did In `DashHaOrch::updateHaScopeStateForSwitchOwner`, log a `SWSS_LOG_WARN` when the referenced HA Set entry is missing, and still proceed to update the HA Scope state DB. Early-return is now taken only when the HA Set exists and its owner is not `HA_OWNER_SWITCH`. ### Why I did it Previously the function returned silently when the HA Set entry was not yet available, making it hard to diagnose why `DPU_STATE_DB` HA Scope state was not refreshed. ### How I verified it Built locally and reviewed call sites — `m_ha_set_entries.find()` is guarded before any dereference, and `m_ha_scope_entries[key]` is only reached after the entry has been inserted. Signed-off-by: Sonic Build Admin --- orchagent/dash/dashhaorch.cpp | 8 +++++-- tests/mock_tests/dashhaorch_ut.cpp | 35 ++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/orchagent/dash/dashhaorch.cpp b/orchagent/dash/dashhaorch.cpp index 09c644ca..2b2e8b10 100644 --- a/orchagent/dash/dashhaorch.cpp +++ b/orchagent/dash/dashhaorch.cpp @@ -733,8 +733,12 @@ void DashHaOrch::updateHaScopeStateForSwitchOwner(const std::string &key, const std::string ha_set_id = entry.ha_set_id().empty() ? key : entry.ha_set_id(); auto ha_set_it = m_ha_set_entries.find(ha_set_id); - if (ha_set_it == m_ha_set_entries.end() || - ha_set_it->second.metadata.owner() != dash::types::HA_OWNER_SWITCH) + if (ha_set_it == m_ha_set_entries.end()) + { + SWSS_LOG_WARN("HA Set entry %s does not exist, still updating HA Scope state for %s", + ha_set_id.c_str(), key.c_str()); + } + else if (ha_set_it->second.metadata.owner() != dash::types::HA_OWNER_SWITCH) { return; } diff --git a/tests/mock_tests/dashhaorch_ut.cpp b/tests/mock_tests/dashhaorch_ut.cpp index 472ba307..845da7d8 100644 --- a/tests/mock_tests/dashhaorch_ut.cpp +++ b/tests/mock_tests/dashhaorch_ut.cpp @@ -1229,4 +1229,39 @@ namespace dashhaorch_ut RemoveHaScope(); RemoveHaSet(); } + + TEST_F(DashHaOrchTestSwitchOwner, SwitchOwnerSetRoleUpdatesStateWhenHaSetMissing) + { + // Create switch-owner HA Set, then HA Scope. + EXPECT_CALL(*mock_sai_dash_ha_api, create_ha_set) + .Times(1).WillOnce(Return(SAI_STATUS_SUCCESS)); + CreateSwitchOwnerDpuScopeHaSet(); + + EXPECT_CALL(*mock_sai_dash_ha_api, create_ha_scope) + .Times(1).WillOnce(Return(SAI_STATUS_SUCCESS)); + CreateHaScope(); + + // Remove the HA Set while HA Scope still exists. This makes the HA Set + // lookup inside updateHaScopeStateForSwitchOwner fail. + EXPECT_CALL(*mock_sai_dash_ha_api, remove_ha_set) + .Times(1).WillOnce(Return(SAI_STATUS_SUCCESS)); + RemoveHaSet(); + ASSERT_TRUE(m_dashHaOrch->getHaSetEntries().find("HA_SET_1") == m_dashHaOrch->getHaSetEntries().end()); + + // Trigger a role change. The new code path should emit a warning that + // the HA Set is missing but still update the in-memory ha_state for the + // HA Scope entry (previously this path would silently early-return). + EXPECT_CALL(*mock_sai_dash_ha_api, set_ha_scope_attribute) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + SetHaScopeHaRole("active"); + + auto scope_it = m_dashHaOrch->getHaScopeEntries().find("HA_SET_1"); + ASSERT_NE(scope_it, m_dashHaOrch->getHaScopeEntries().end()); + EXPECT_EQ(scope_it->second.ha_state, SAI_DASH_HA_STATE_ACTIVE); + EXPECT_EQ(to_sai(scope_it->second.metadata.ha_role()), SAI_DASH_HA_ROLE_ACTIVE); + + EXPECT_CALL(*mock_sai_dash_ha_api, remove_ha_scope) + .Times(1).WillOnce(Return(SAI_STATUS_SUCCESS)); + RemoveHaScope(); + } }