diff --git a/orchagent/dash/dashhaorch.cpp b/orchagent/dash/dashhaorch.cpp index a883a1be8d3..c9b04348ede 100644 --- a/orchagent/dash/dashhaorch.cpp +++ b/orchagent/dash/dashhaorch.cpp @@ -390,6 +390,12 @@ bool DashHaOrch::addHaScopeEntry(const std::string &key, const dash::ha_scope::H repeated_message = false; } + if (ha_scope_it->second.metadata.disabled() != entry.disabled()) + { + success = success && setHaScopeDisabled(key, entry.disabled()); + repeated_message = false; + } + if (repeated_message) { SWSS_LOG_WARN("HA Scope entry already exists for %s", key.c_str()); @@ -435,6 +441,11 @@ bool DashHaOrch::addHaScopeEntry(const std::string &key, const dash::ha_scope::H ha_role_attr.value.u16 = to_sai(entry.ha_role()); ha_scope_attrs.push_back(ha_role_attr); + sai_attribute_t disabled_attr = {}; + disabled_attr.id = SAI_HA_SCOPE_ATTR_ADMIN_STATE; + disabled_attr.value.booldata = !entry.disabled(); + ha_scope_attrs.push_back(disabled_attr); + if (entry.has_vip_v4() && entry.vip_v4().has_ipv4()) { sai_ip_address_t sai_vip_v4 = {}; @@ -638,6 +649,35 @@ bool DashHaOrch::setHaScopeActivateRoleRequest(const std::string &key) return true; } +bool DashHaOrch::setHaScopeDisabled(const std::string &key, bool disabled) +{ + SWSS_LOG_ENTER(); + + sai_object_id_t ha_scope_id = m_ha_scope_entries[key].ha_scope_id; + + sai_attribute_t ha_scope_attr; + ha_scope_attr.id = SAI_HA_SCOPE_ATTR_ADMIN_STATE; + ha_scope_attr.value.booldata = !disabled; + + sai_status_t status = sai_dash_ha_api->set_ha_scope_attribute(ha_scope_id, + &ha_scope_attr); + + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set HA Scope admin state to %d in SAI for %s", disabled, key.c_str()); + task_process_status handle_status = handleSaiSetStatus((sai_api_t) SAI_API_DASH_HA, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } + } + + m_ha_scope_entries[key].metadata.set_disabled(disabled); + SWSS_LOG_NOTICE("Set HA Scope admin state for %s to %d", key.c_str(), !disabled); + + return true; +} + bool DashHaOrch::setEniHaScopeId(const sai_object_id_t eni_id, const sai_object_id_t ha_scope_id) { SWSS_LOG_ENTER(); @@ -708,6 +748,12 @@ void DashHaOrch::doTaskHaScopeTable(ConsumerBase &consumer) { dash::ha_scope::HaScope entry; + auto existing_it = m_ha_scope_entries.find(key); + if (existing_it != m_ha_scope_entries.end()) + { + // Start with existing entry to preserve unmodified fields + entry.CopyFrom(existing_it->second.metadata); + } /* * For HA internal tables, kfv format was used instead of serialized pb objects in the end. @@ -1066,4 +1112,4 @@ bool DashHaOrch::convertKfvToHaScopePb(const std::vector &kfv, } } return true; -} +} \ No newline at end of file diff --git a/orchagent/dash/dashhaorch.h b/orchagent/dash/dashhaorch.h index 424f00b1bbc..af8f3644a7e 100644 --- a/orchagent/dash/dashhaorch.h +++ b/orchagent/dash/dashhaorch.h @@ -62,6 +62,7 @@ class DashHaOrch : public ZmqOrch bool setHaScopeHaRole(const std::string &key, const dash::ha_scope::HaScope &entry); bool setHaScopeFlowReconcileRequest(const std::string &key); bool setHaScopeActivateRoleRequest(const std::string &key); + bool setHaScopeDisabled(const std::string &key, bool disabled); bool setEniHaScopeId(const sai_object_id_t eni_id, const sai_object_id_t ha_scope_id); bool register_ha_set_notifier(); bool register_ha_scope_notifier(); diff --git a/tests/mock_tests/dashhaorch_ut.cpp b/tests/mock_tests/dashhaorch_ut.cpp index e3c7ca7432b..6ba4543f12f 100644 --- a/tests/mock_tests/dashhaorch_ut.cpp +++ b/tests/mock_tests/dashhaorch_ut.cpp @@ -246,7 +246,8 @@ namespace dashhaorch_ut {"ha_role", "dead"}, {"ha_set_id", "HA_SET_1"}, {"vip_v4", "10.0.0.1"}, - {"vip_v6", "3:2::1:0"} + {"vip_v6", "3:2::1:0"}, + {"disabled", "true"} } } } @@ -312,7 +313,8 @@ namespace dashhaorch_ut SET_COMMAND, { {"version", "1"}, - {"ha_role", role} + {"ha_role", role}, + {"disabled", "false"} } } } @@ -715,11 +717,13 @@ namespace dashhaorch_ut CreateHaScope(); EXPECT_EQ(to_sai(m_dashHaOrch->getHaScopeEntries().find("HA_SET_1")->second.metadata.ha_role()), SAI_DASH_HA_ROLE_DEAD); + EXPECT_TRUE(m_dashHaOrch->getHaScopeEntries().find("HA_SET_1")->second.metadata.disabled()); SetHaScopeHaRole(); HaScopeEvent(SAI_HA_SCOPE_EVENT_STATE_CHANGED, SAI_DASH_HA_ROLE_ACTIVE, SAI_DASH_HA_STATE_ACTIVE); EXPECT_EQ(to_sai(m_dashHaOrch->getHaScopeEntries().find("HA_SET_1")->second.metadata.ha_role()), SAI_DASH_HA_ROLE_ACTIVE); + EXPECT_FALSE(m_dashHaOrch->getHaScopeEntries().find("HA_SET_1")->second.metadata.disabled()); SetHaScopeHaRole(""); HaScopeEvent(SAI_HA_SCOPE_EVENT_STATE_CHANGED, @@ -788,8 +792,7 @@ namespace dashhaorch_ut EXPECT_EQ(to_sai(m_dashHaOrch->getHaScopeEntries().find("HA_SET_1")->second.metadata.ha_role()), SAI_DASH_HA_ROLE_SWITCHING_TO_ACTIVE); EXPECT_CALL(*mock_sai_dash_ha_api, set_ha_scope_attribute) - .Times(2) // Set ha_role and activate_role_requested - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + .Times(2); // Set ha_role and activate_role_requested SetHaScopeActivateRoleRequest(); @@ -810,12 +813,15 @@ namespace dashhaorch_ut HaScopeEvent(SAI_HA_SCOPE_EVENT_FLOW_RECONCILE_NEEDED, SAI_DASH_HA_ROLE_ACTIVE, SAI_DASH_HA_STATE_ACTIVE); + EXPECT_TRUE(m_dashHaOrch->getHaScopeEntries().find("HA_SET_1")->second.metadata.disabled()); + EXPECT_CALL(*mock_sai_dash_ha_api, set_ha_scope_attribute) - .Times(1) - .WillOnce(Return(SAI_STATUS_SUCCESS)); + .Times(1); SetHaScopeFlowReconcileRequest(); + EXPECT_TRUE(m_dashHaOrch->getHaScopeEntries().find("HA_SET_1")->second.metadata.disabled()); + RemoveHaScope(); RemoveHaSet(); }