From a4647299f63d367d433779fd3ead85053e6fb7d0 Mon Sep 17 00:00:00 2001 From: Stepan Blyshchak <38952541+stepanblyschak@users.noreply.github.com> Date: Mon, 25 Mar 2024 22:20:47 +0200 Subject: [PATCH 01/34] [portsorch] process only updated APP_DB fields when port is already created (#3025) * [portsorch] process only updated APP_DB fields when port is already created What I did Fixing an issue when setting some port attribute in APPL_DB triggers serdes parameters to be re-programmed with port toggling. Made portsorch to handle only those attributes that were pushed to APPL_DB, so that serdes programming happens only by xcvrd's request to do so. --- orchagent/port/porthlpr.cpp | 2 +- orchagent/port/porthlpr.h | 3 +- orchagent/portsorch.cpp | 69 ++++++++++++++++++++++++------- tests/mock_tests/portsorch_ut.cpp | 30 +++++++++++++- 4 files changed, 86 insertions(+), 18 deletions(-) diff --git a/orchagent/port/porthlpr.cpp b/orchagent/port/porthlpr.cpp index 64c05b2aec..f6463b0af5 100644 --- a/orchagent/port/porthlpr.cpp +++ b/orchagent/port/porthlpr.cpp @@ -1001,7 +1001,7 @@ bool PortHelper::parsePortConfig(PortConfig &port) const } } - return this->validatePortConfig(port); + return true; } bool PortHelper::validatePortConfig(PortConfig &port) const diff --git a/orchagent/port/porthlpr.h b/orchagent/port/porthlpr.h index 4bcae7fca5..6729a83a4d 100644 --- a/orchagent/port/porthlpr.h +++ b/orchagent/port/porthlpr.h @@ -28,6 +28,7 @@ class PortHelper final std::string getAdminStatusStr(const PortConfig &port) const; bool parsePortConfig(PortConfig &port) const; + bool validatePortConfig(PortConfig &port) const; private: std::string getFieldValueStr(const PortConfig &port, const std::string &field) const; @@ -52,6 +53,4 @@ class PortHelper final bool parsePortRole(PortConfig &port, const std::string &field, const std::string &value) const; bool parsePortAdminStatus(PortConfig &port, const std::string &field, const std::string &value) const; bool parsePortDescription(PortConfig &port, const std::string &field, const std::string &value) const; - - bool validatePortConfig(PortConfig &port) const; }; diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 23c1bc324e..67265af5f6 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -3572,28 +3572,59 @@ void PortsOrch::doPortTask(Consumer &consumer) if (op == SET_COMMAND) { - auto &fvMap = m_portConfigMap[key]; - - for (const auto &cit : kfvFieldsValues(keyOpFieldsValues)) + auto parsePortFvs = [&](auto& fvMap) -> bool { - auto fieldName = fvField(cit); - auto fieldValue = fvValue(cit); + for (const auto &cit : kfvFieldsValues(keyOpFieldsValues)) + { + auto fieldName = fvField(cit); + auto fieldValue = fvValue(cit); - SWSS_LOG_INFO("FIELD: %s, VALUE: %s", fieldName.c_str(), fieldValue.c_str()); + SWSS_LOG_INFO("FIELD: %s, VALUE: %s", fieldName.c_str(), fieldValue.c_str()); - fvMap[fieldName] = fieldValue; - } + fvMap[fieldName] = fieldValue; + } - pCfg.fieldValueMap = fvMap; + pCfg.fieldValueMap = fvMap; + + if (!m_portHlpr.parsePortConfig(pCfg)) + { + return false; + } - if (!m_portHlpr.parsePortConfig(pCfg)) + return true; + }; + + if (m_portList.find(key) == m_portList.end()) { - it = taskMap.erase(it); - continue; + // Aggregate configuration while the port is not created. + auto &fvMap = m_portConfigMap[key]; + + if (!parsePortFvs(fvMap)) + { + it = taskMap.erase(it); + continue; + } + + if (!m_portHlpr.validatePortConfig(pCfg)) + { + it = taskMap.erase(it); + continue; + } + + /* Collect information about all received ports */ + m_lanesAliasSpeedMap[pCfg.lanes.value] = pCfg; } + else + { + // Port is already created, gather updated field-values. + std::unordered_map fvMap; - /* Collect information about all received ports */ - m_lanesAliasSpeedMap[pCfg.lanes.value] = pCfg; + if (!parsePortFvs(fvMap)) + { + it = taskMap.erase(it); + continue; + } + } // TODO: // Fix the issue below @@ -3709,6 +3740,9 @@ void PortsOrch::doPortTask(Consumer &consumer) PortSerdesAttrMap_t serdes_attr; getPortSerdesAttr(serdes_attr, pCfg); + // Saved configured admin status + bool admin_status = p.m_admin_state_up; + if (pCfg.autoneg.is_set) { if (!p.m_an_cfg || p.m_autoneg != pCfg.autoneg.value) @@ -4269,6 +4303,13 @@ void PortsOrch::doPortTask(Consumer &consumer) /* create host_tx_ready field in state-db */ initHostTxReadyState(p); + // Restore admin status if the port was brought down + if (admin_status != p.m_admin_state_up) + { + pCfg.admin_status.is_set = true; + pCfg.admin_status.value = admin_status; + } + /* Last step set port admin status */ if (pCfg.admin_status.is_set) { diff --git a/tests/mock_tests/portsorch_ut.cpp b/tests/mock_tests/portsorch_ut.cpp index db50c63e66..5b775d8d31 100644 --- a/tests/mock_tests/portsorch_ut.cpp +++ b/tests/mock_tests/portsorch_ut.cpp @@ -926,7 +926,6 @@ namespace portsorch_test std::deque kfvSerdes = {{ "Ethernet0", SET_COMMAND, { - { "admin_status", "up" }, { "idriver" , "0x6,0x6,0x6,0x6" } } }}; @@ -953,6 +952,35 @@ namespace portsorch_test ASSERT_EQ(_sai_set_admin_state_down_count, ++current_sai_api_call_count); ASSERT_EQ(_sai_set_admin_state_up_count, current_sai_api_call_count); + // Configure non-serdes attribute that does not trigger admin state change + std::deque kfvMtu = {{ + "Ethernet0", + SET_COMMAND, { + { "mtu", "1234" }, + } + }}; + + // Refill consumer + consumer->addToSync(kfvMtu); + + _hook_sai_port_api(); + current_sai_api_call_count = _sai_set_admin_state_down_count; + + // Apply configuration + static_cast(gPortsOrch)->doTask(); + + _unhook_sai_port_api(); + + ASSERT_TRUE(gPortsOrch->getPort("Ethernet0", p)); + ASSERT_TRUE(p.m_admin_state_up); + + // Verify mtu is set + ASSERT_EQ(p.m_mtu, 1234); + + // Verify no admin-disable then admin-enable + ASSERT_EQ(_sai_set_admin_state_down_count, current_sai_api_call_count); + ASSERT_EQ(_sai_set_admin_state_up_count, current_sai_api_call_count); + // Dump pending tasks std::vector taskList; gPortsOrch->dumpPendingTasks(taskList); From 80e0b57d5a85252d4099e9ea1303358e3ad8ac0a Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Wed, 27 Mar 2024 16:28:03 -0700 Subject: [PATCH 02/34] [Copp]Refactor coppmgr tests (#3093) What I did Refactoring coppmgr mock tests Why I did it After migration to bookworm, coppmgr tests started failing due to the use of sudo commands. --- cfgmgr/coppmgr.cpp | 10 ++++++---- cfgmgr/coppmgr.h | 3 ++- tests/mock_tests/Makefile.am | 3 ++- tests/mock_tests/copp_ut.cpp | 26 ++------------------------ 4 files changed, 12 insertions(+), 30 deletions(-) diff --git a/cfgmgr/coppmgr.cpp b/cfgmgr/coppmgr.cpp index cfa94988d9..9b2c3ee4d7 100644 --- a/cfgmgr/coppmgr.cpp +++ b/cfgmgr/coppmgr.cpp @@ -21,10 +21,11 @@ static set g_copp_init_set; void CoppMgr::parseInitFile(void) { - std::ifstream ifs(COPP_INIT_FILE); + std::ifstream ifs(m_coppCfgfile); + if (ifs.fail()) { - SWSS_LOG_ERROR("COPP init file %s not found", COPP_INIT_FILE); + SWSS_LOG_ERROR("COPP init file %s not found", m_coppCfgfile.c_str()); return; } json j = json::parse(ifs); @@ -293,7 +294,7 @@ bool CoppMgr::isDupEntry(const std::string &key, std::vector &f return true; } -CoppMgr::CoppMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector &tableNames) : +CoppMgr::CoppMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector &tableNames, const string copp_init_file) : Orch(cfgDb, tableNames), m_cfgCoppTrapTable(cfgDb, CFG_COPP_TRAP_TABLE_NAME), m_cfgCoppGroupTable(cfgDb, CFG_COPP_GROUP_TABLE_NAME), @@ -301,7 +302,8 @@ CoppMgr::CoppMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, c m_appCoppTable(appDb, APP_COPP_TABLE_NAME), m_stateCoppTrapTable(stateDb, STATE_COPP_TRAP_TABLE_NAME), m_stateCoppGroupTable(stateDb, STATE_COPP_GROUP_TABLE_NAME), - m_coppTable(appDb, APP_COPP_TABLE_NAME) + m_coppTable(appDb, APP_COPP_TABLE_NAME), + m_coppCfgfile(copp_init_file) { SWSS_LOG_ENTER(); parseInitFile(); diff --git a/cfgmgr/coppmgr.h b/cfgmgr/coppmgr.h index 44549d3bec..86f1b0e4e2 100644 --- a/cfgmgr/coppmgr.h +++ b/cfgmgr/coppmgr.h @@ -62,7 +62,7 @@ class CoppMgr : public Orch { public: CoppMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, - const std::vector &tableNames); + const std::vector &tableNames, const std::string copp_init_file = COPP_INIT_FILE); using Orch::doTask; private: @@ -75,6 +75,7 @@ class CoppMgr : public Orch CoppCfg m_coppGroupInitCfg; CoppCfg m_coppTrapInitCfg; CoppCfg m_featuresCfgTable; + std::string m_coppCfgfile; void doTask(Consumer &consumer); diff --git a/tests/mock_tests/Makefile.am b/tests/mock_tests/Makefile.am index 651fbcd7b0..b00d4af1f4 100644 --- a/tests/mock_tests/Makefile.am +++ b/tests/mock_tests/Makefile.am @@ -130,7 +130,8 @@ tests_SOURCES = aclorch_ut.cpp \ $(top_srcdir)/orchagent/dash/dashvnetorch.cpp \ $(top_srcdir)/cfgmgr/buffermgrdyn.cpp \ $(top_srcdir)/warmrestart/warmRestartAssist.cpp \ - $(top_srcdir)/orchagent/dash/pbutils.cpp + $(top_srcdir)/orchagent/dash/pbutils.cpp \ + $(top_srcdir)/cfgmgr/coppmgr.cpp tests_SOURCES += $(FLEX_CTR_DIR)/flex_counter_manager.cpp $(FLEX_CTR_DIR)/flex_counter_stat_manager.cpp $(FLEX_CTR_DIR)/flow_counter_handler.cpp $(FLEX_CTR_DIR)/flowcounterrouteorch.cpp tests_SOURCES += $(DEBUG_CTR_DIR)/debug_counter.cpp $(DEBUG_CTR_DIR)/drop_counter.cpp diff --git a/tests/mock_tests/copp_ut.cpp b/tests/mock_tests/copp_ut.cpp index 1c3b766e1c..f5d0b85cf5 100644 --- a/tests/mock_tests/copp_ut.cpp +++ b/tests/mock_tests/copp_ut.cpp @@ -4,34 +4,14 @@ #include "warm_restart.h" #include "ut_helper.h" #include "coppmgr.h" -#include "coppmgr.cpp" #include #include + using namespace std; using namespace swss; -void create_init_file() -{ - int status = system("sudo mkdir /etc/sonic/"); - ASSERT_EQ(status, 0); - - status = system("sudo chmod 777 /etc/sonic/"); - ASSERT_EQ(status, 0); - - status = system("sudo cp copp_cfg.json /etc/sonic/"); - ASSERT_EQ(status, 0); -} - -void cleanup() -{ - int status = system("sudo rm -rf /etc/sonic/"); - ASSERT_EQ(status, 0); -} - TEST(CoppMgrTest, CoppTest) { - create_init_file(); - const vector cfg_copp_tables = { CFG_COPP_TRAP_TABLE_NAME, CFG_COPP_GROUP_TABLE_NAME, @@ -65,12 +45,10 @@ TEST(CoppMgrTest, CoppTest) {"trap_ids", "ip2me"} }); - CoppMgr coppmgr(&cfgDb, &appDb, &stateDb, cfg_copp_tables); + CoppMgr coppmgr(&cfgDb, &appDb, &stateDb, cfg_copp_tables, "./copp_cfg.json"); string overide_val; coppTable.hget("queue1_group1", "cbs",overide_val); EXPECT_EQ( overide_val, "6000"); - - cleanup(); } From c96a2f84b506665dca18765932cc4c0de9d0e507 Mon Sep 17 00:00:00 2001 From: Neetha John Date: Fri, 29 Mar 2024 09:11:42 -0700 Subject: [PATCH 03/34] Revert "[acl] Add IN_PORTS qualifier for L3 table (#3078)" (#3092) This reverts commit 9d4a3addacba4289b42ce82626b3bc54a6e8b0bd. *Revert "[acl] Add IN_PORTS qualifier for L3 table" --- orchagent/aclorch.cpp | 2 -- tests/test_acl.py | 42 ------------------------------------------ 2 files changed, 44 deletions(-) diff --git a/orchagent/aclorch.cpp b/orchagent/aclorch.cpp index 5ca4d2a44c..6906744cc2 100644 --- a/orchagent/aclorch.cpp +++ b/orchagent/aclorch.cpp @@ -3223,7 +3223,6 @@ void AclOrch::initDefaultTableTypes() .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_SRC_PORT)) .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT)) .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_TCP_FLAGS)) - .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_IN_PORTS)) .build() ); @@ -3241,7 +3240,6 @@ void AclOrch::initDefaultTableTypes() .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_SRC_PORT)) .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT)) .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_TCP_FLAGS)) - .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_IN_PORTS)) .build() ); diff --git a/tests/test_acl.py b/tests/test_acl.py index 1dbaa30590..cf68d1516e 100644 --- a/tests/test_acl.py +++ b/tests/test_acl.py @@ -243,29 +243,6 @@ def test_AclRuleInPorts(self, dvs_acl, mirror_acl_table): dvs_acl.verify_acl_rule_status(MIRROR_TABLE_NAME, MIRROR_RULE_NAME, None) dvs_acl.verify_no_acl_rules() - def test_AclRuleInPortsL3(self, dvs_acl, l3_acl_table): - """ - Verify IN_PORTS matches on ACL rule. - Using L3 table type for IN_PORTS matches. - """ - config_qualifiers = { - "IN_PORTS": "Ethernet8,Ethernet12", - } - - expected_sai_qualifiers = { - "SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS": dvs_acl.get_port_list_comparator(["Ethernet8", "Ethernet12"]) - } - - dvs_acl.create_acl_rule(L3_TABLE_NAME, L3_RULE_NAME, config_qualifiers) - # Verify status is written into STATE_DB - dvs_acl.verify_acl_rule_status(L3_TABLE_NAME, L3_RULE_NAME, "Active") - dvs_acl.verify_acl_rule(expected_sai_qualifiers) - - dvs_acl.remove_acl_rule(L3_TABLE_NAME, L3_RULE_NAME) - # Verify the STATE_DB entry is removed - dvs_acl.verify_acl_rule_status(L3_TABLE_NAME, L3_RULE_NAME, None) - dvs_acl.verify_no_acl_rules() - def test_AclRuleOutPorts(self, dvs_acl, mclag_acl_table): """ Verify OUT_PORTS matches on ACL rule. @@ -569,25 +546,6 @@ def test_V6AclRuleVlanId(self, dvs_acl, l3v6_acl_table): dvs_acl.verify_acl_rule_status(L3V6_TABLE_NAME, L3V6_RULE_NAME, None) dvs_acl.verify_no_acl_rules() - def test_v6AclRuleInPorts(self, dvs_acl, l3v6_acl_table): - config_qualifiers = { - "IN_PORTS": "Ethernet8,Ethernet12", - } - - expected_sai_qualifiers = { - "SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS": dvs_acl.get_port_list_comparator(["Ethernet8", "Ethernet12"]) - } - - dvs_acl.create_acl_rule(L3V6_TABLE_NAME, L3V6_RULE_NAME, config_qualifiers) - dvs_acl.verify_acl_rule(expected_sai_qualifiers) - # Verify status is written into STATE_DB - dvs_acl.verify_acl_rule_status(L3V6_TABLE_NAME, L3V6_RULE_NAME, "Active") - - dvs_acl.remove_acl_rule(L3V6_TABLE_NAME, L3V6_RULE_NAME) - # Verify the STATE_DB entry is removed - dvs_acl.verify_acl_rule_status(L3V6_TABLE_NAME, L3V6_RULE_NAME, None) - dvs_acl.verify_no_acl_rules() - def test_InsertAclRuleBetweenPriorities(self, dvs_acl, l3_acl_table): rule_priorities = ["10", "20", "30", "40"] From 95a747500ab11cd39cab6b395109e614b937f3ba Mon Sep 17 00:00:00 2001 From: xiaodong hu <32903206+huseratgithub@users.noreply.github.com> Date: Tue, 2 Apr 2024 04:49:20 +0800 Subject: [PATCH 04/34] [orchagent] TWAMP Light orchagent implementation (#2927) * [orchagent] TWAMP Light orchagent implementation. (#2927) * What I did Implemented the TWAMP Light feature according to the SONiC TWAMP Light HLD(sonic-net/SONiC#1320). --- orchagent/Makefile.am | 3 +- orchagent/crmorch.cpp | 19 +- orchagent/crmorch.h | 3 +- orchagent/notifications.cpp | 6 + orchagent/notifications.h | 1 + orchagent/orchdaemon.cpp | 5 + orchagent/orchdaemon.h | 1 + orchagent/saihelper.cpp | 3 + orchagent/twamporch.cpp | 1052 ++++++++++++++++++++++++ orchagent/twamporch.h | 136 +++ tests/conftest.py | 9 + tests/dvslib/dvs_twamp.py | 98 +++ tests/mock_tests/Makefile.am | 4 +- tests/mock_tests/mock_orchagent_main.h | 2 + tests/mock_tests/portal.h | 14 + tests/mock_tests/twamporch_ut.cpp | 975 ++++++++++++++++++++++ tests/mock_tests/ut_saihelper.cpp | 2 + tests/test_twamp.py | 182 ++++ 18 files changed, 2507 insertions(+), 8 deletions(-) create mode 100644 orchagent/twamporch.cpp create mode 100644 orchagent/twamporch.h create mode 100644 tests/dvslib/dvs_twamp.py create mode 100644 tests/mock_tests/twamporch_ut.cpp create mode 100644 tests/test_twamp.py diff --git a/orchagent/Makefile.am b/orchagent/Makefile.am index 6af8189c95..e7743ab44d 100644 --- a/orchagent/Makefile.am +++ b/orchagent/Makefile.am @@ -113,7 +113,8 @@ orchagent_SOURCES = \ dash/dashaclorch.cpp \ dash/dashaclgroupmgr.cpp \ dash/dashtagmgr.cpp \ - dash/pbutils.cpp + dash/pbutils.cpp \ + twamporch.cpp orchagent_SOURCES += flex_counter/flex_counter_manager.cpp flex_counter/flex_counter_stat_manager.cpp flex_counter/flow_counter_handler.cpp flex_counter/flowcounterrouteorch.cpp orchagent_SOURCES += debug_counter/debug_counter.cpp debug_counter/drop_counter.cpp diff --git a/orchagent/crmorch.cpp b/orchagent/crmorch.cpp index 966ab96dd9..b5844bbea3 100644 --- a/orchagent/crmorch.cpp +++ b/orchagent/crmorch.cpp @@ -64,6 +64,7 @@ const map crmResTypeNameMap = { CrmResourceType::CRM_DASH_IPV6_ACL_GROUP, "DASH_IPV6_ACL_GROUP" }, { CrmResourceType::CRM_DASH_IPV4_ACL_RULE, "DASH_IPV4_ACL_RULE" }, { CrmResourceType::CRM_DASH_IPV6_ACL_RULE, "DASH_IPV6_ACL_RULE" }, + { CrmResourceType::CRM_TWAMP_ENTRY, "TWAMP_ENTRY" } }; const map crmResSaiAvailAttrMap = @@ -84,6 +85,7 @@ const map crmResSaiAvailAttrMap = { CrmResourceType::CRM_IPMC_ENTRY, SAI_SWITCH_ATTR_AVAILABLE_IPMC_ENTRY}, { CrmResourceType::CRM_SNAT_ENTRY, SAI_SWITCH_ATTR_AVAILABLE_SNAT_ENTRY }, { CrmResourceType::CRM_DNAT_ENTRY, SAI_SWITCH_ATTR_AVAILABLE_DNAT_ENTRY }, + { CrmResourceType::CRM_TWAMP_ENTRY, SAI_SWITCH_ATTR_AVAILABLE_TWAMP_SESSION } }; const map crmResSaiObjAttrMap = @@ -125,6 +127,7 @@ const map crmResSaiObjAttrMap = { CrmResourceType::CRM_DASH_IPV6_ACL_GROUP, (sai_object_type_t)SAI_OBJECT_TYPE_DASH_ACL_GROUP }, { CrmResourceType::CRM_DASH_IPV4_ACL_RULE, (sai_object_type_t)SAI_OBJECT_TYPE_DASH_ACL_RULE }, { CrmResourceType::CRM_DASH_IPV6_ACL_RULE, (sai_object_type_t)SAI_OBJECT_TYPE_DASH_ACL_RULE }, + { CrmResourceType::CRM_TWAMP_ENTRY, SAI_OBJECT_TYPE_NULL } }; const map crmResAddrFamilyAttrMap = @@ -185,7 +188,8 @@ const map crmThreshTypeResMap = { "dash_ipv4_acl_group_threshold_type", CrmResourceType::CRM_DASH_IPV4_ACL_GROUP }, { "dash_ipv6_acl_group_threshold_type", CrmResourceType::CRM_DASH_IPV6_ACL_GROUP }, { "dash_ipv4_acl_rule_threshold_type", CrmResourceType::CRM_DASH_IPV4_ACL_RULE }, - { "dash_ipv6_acl_rule_threshold_type", CrmResourceType::CRM_DASH_IPV6_ACL_RULE } + { "dash_ipv6_acl_rule_threshold_type", CrmResourceType::CRM_DASH_IPV6_ACL_RULE }, + { "twamp_entry_threshold_type", CrmResourceType::CRM_TWAMP_ENTRY } }; const map crmThreshLowResMap = @@ -226,7 +230,8 @@ const map crmThreshLowResMap = { "dash_ipv4_acl_group_low_threshold", CrmResourceType::CRM_DASH_IPV4_ACL_GROUP }, { "dash_ipv6_acl_group_low_threshold", CrmResourceType::CRM_DASH_IPV6_ACL_GROUP }, { "dash_ipv4_acl_rule_low_threshold", CrmResourceType::CRM_DASH_IPV4_ACL_RULE }, - { "dash_ipv6_acl_rule_low_threshold", CrmResourceType::CRM_DASH_IPV6_ACL_RULE } + { "dash_ipv6_acl_rule_low_threshold", CrmResourceType::CRM_DASH_IPV6_ACL_RULE }, + { "twamp_entry_low_threshold", CrmResourceType::CRM_TWAMP_ENTRY } }; const map crmThreshHighResMap = @@ -267,7 +272,8 @@ const map crmThreshHighResMap = { "dash_ipv4_acl_group_high_threshold", CrmResourceType::CRM_DASH_IPV4_ACL_GROUP }, { "dash_ipv6_acl_group_high_threshold", CrmResourceType::CRM_DASH_IPV6_ACL_GROUP }, { "dash_ipv4_acl_rule_high_threshold", CrmResourceType::CRM_DASH_IPV4_ACL_RULE }, - { "dash_ipv6_acl_rule_high_threshold", CrmResourceType::CRM_DASH_IPV6_ACL_RULE } + { "dash_ipv6_acl_rule_high_threshold", CrmResourceType::CRM_DASH_IPV6_ACL_RULE }, + { "twamp_entry_high_threshold", CrmResourceType::CRM_TWAMP_ENTRY } }; const map crmThreshTypeMap = @@ -315,7 +321,8 @@ const map crmAvailCntsTableMap = { "crm_stats_dash_ipv4_acl_group_available", CrmResourceType::CRM_DASH_IPV4_ACL_GROUP }, { "crm_stats_dash_ipv6_acl_group_available", CrmResourceType::CRM_DASH_IPV6_ACL_GROUP }, { "crm_stats_dash_ipv4_acl_rule_available", CrmResourceType::CRM_DASH_IPV4_ACL_RULE }, - { "crm_stats_dash_ipv6_acl_rule_available", CrmResourceType::CRM_DASH_IPV6_ACL_RULE } + { "crm_stats_dash_ipv6_acl_rule_available", CrmResourceType::CRM_DASH_IPV6_ACL_RULE }, + { "crm_stats_twamp_entry_available", CrmResourceType::CRM_TWAMP_ENTRY } }; const map crmUsedCntsTableMap = @@ -356,7 +363,8 @@ const map crmUsedCntsTableMap = { "crm_stats_dash_ipv4_acl_group_used", CrmResourceType::CRM_DASH_IPV4_ACL_GROUP }, { "crm_stats_dash_ipv6_acl_group_used", CrmResourceType::CRM_DASH_IPV6_ACL_GROUP }, { "crm_stats_dash_ipv4_acl_rule_used", CrmResourceType::CRM_DASH_IPV4_ACL_RULE }, - { "crm_stats_dash_ipv6_acl_rule_used", CrmResourceType::CRM_DASH_IPV6_ACL_RULE } + { "crm_stats_dash_ipv6_acl_rule_used", CrmResourceType::CRM_DASH_IPV6_ACL_RULE }, + { "crm_stats_twamp_entry_used", CrmResourceType::CRM_TWAMP_ENTRY }, }; CrmOrch::CrmOrch(DBConnector *db, string tableName): @@ -877,6 +885,7 @@ void CrmOrch::getResAvailableCounters() case CrmResourceType::CRM_DASH_IPV6_OUTBOUND_CA_TO_PA: case CrmResourceType::CRM_DASH_IPV4_ACL_GROUP: case CrmResourceType::CRM_DASH_IPV6_ACL_GROUP: + case CrmResourceType::CRM_TWAMP_ENTRY: { getResAvailability(res.first, res.second); break; diff --git a/orchagent/crmorch.h b/orchagent/crmorch.h index 9eb6001185..961bfaebe4 100644 --- a/orchagent/crmorch.h +++ b/orchagent/crmorch.h @@ -49,7 +49,8 @@ enum class CrmResourceType CRM_DASH_IPV4_ACL_GROUP, CRM_DASH_IPV6_ACL_GROUP, CRM_DASH_IPV4_ACL_RULE, - CRM_DASH_IPV6_ACL_RULE + CRM_DASH_IPV6_ACL_RULE, + CRM_TWAMP_ENTRY }; enum class CrmThresholdType diff --git a/orchagent/notifications.cpp b/orchagent/notifications.cpp index 442e93d75a..9455620fb5 100644 --- a/orchagent/notifications.cpp +++ b/orchagent/notifications.cpp @@ -27,6 +27,12 @@ void on_bfd_session_state_change(uint32_t count, sai_bfd_session_state_notificat // which causes concurrency access to the DB } +void on_twamp_session_event(uint32_t count, sai_twamp_session_event_notification_data_t *data) +{ + // don't use this event handler, because it runs by libsairedis in a separate thread + // which causes concurrency access to the DB +} + void on_switch_shutdown_request(sai_object_id_t switch_id) { SWSS_LOG_ENTER(); diff --git a/orchagent/notifications.h b/orchagent/notifications.h index 81d49efee0..403b358a12 100644 --- a/orchagent/notifications.h +++ b/orchagent/notifications.h @@ -7,6 +7,7 @@ extern "C" { void on_fdb_event(uint32_t count, sai_fdb_event_notification_data_t *data); void on_port_state_change(uint32_t count, sai_port_oper_status_notification_t *data); void on_bfd_session_state_change(uint32_t count, sai_bfd_session_state_notification_t *data); +void on_twamp_session_event(uint32_t count, sai_twamp_session_event_notification_data_t *data); // The function prototype information can be found here: // https://github.com/sonic-net/sonic-sairedis/blob/master/meta/NotificationSwitchShutdownRequest.cpp#L49 diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index a2e7f86ad9..63fd037fa6 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -727,6 +727,11 @@ bool OrchDaemon::init() gP4Orch = new P4Orch(m_applDb, p4rt_tables, vrf_orch, gCoppOrch); m_orchList.push_back(gP4Orch); + TableConnector confDbTwampTable(m_configDb, CFG_TWAMP_SESSION_TABLE_NAME); + TableConnector stateDbTwampTable(m_stateDb, STATE_TWAMP_SESSION_TABLE_NAME); + TwampOrch *twamp_orch = new TwampOrch(confDbTwampTable, stateDbTwampTable, gSwitchOrch, gPortsOrch, vrf_orch); + m_orchList.push_back(twamp_orch); + if (WarmStart::isWarmStart()) { bool suc = warmRestoreAndSyncUp(); diff --git a/orchagent/orchdaemon.h b/orchagent/orchdaemon.h index 803a720c3c..2473848bf5 100644 --- a/orchagent/orchdaemon.h +++ b/orchagent/orchdaemon.h @@ -46,6 +46,7 @@ #include "bfdorch.h" #include "srv6orch.h" #include "nvgreorch.h" +#include "twamporch.h" #include "dash/dashaclorch.h" #include "dash/dashorch.h" #include "dash/dashrouteorch.h" diff --git a/orchagent/saihelper.cpp b/orchagent/saihelper.cpp index 6fcf4c5014..d731b7b8ac 100644 --- a/orchagent/saihelper.cpp +++ b/orchagent/saihelper.cpp @@ -82,6 +82,7 @@ sai_dash_inbound_routing_api_t* sai_dash_inbound_routing_api; sai_dash_eni_api_t* sai_dash_eni_api; sai_dash_vip_api_t* sai_dash_vip_api; sai_dash_direction_lookup_api_t* sai_dash_direction_lookup_api; +sai_twamp_api_t* sai_twamp_api; extern sai_object_id_t gSwitchId; @@ -217,6 +218,7 @@ void initSaiApi() sai_api_query((sai_api_t)SAI_API_DASH_ENI, (void**)&sai_dash_eni_api); sai_api_query((sai_api_t)SAI_API_DASH_VIP, (void**)&sai_dash_vip_api); sai_api_query((sai_api_t)SAI_API_DASH_DIRECTION_LOOKUP, (void**)&sai_dash_direction_lookup_api); + sai_api_query(SAI_API_TWAMP, (void **)&sai_twamp_api); sai_log_set(SAI_API_SWITCH, SAI_LOG_LEVEL_NOTICE); sai_log_set(SAI_API_BRIDGE, SAI_LOG_LEVEL_NOTICE); @@ -256,6 +258,7 @@ void initSaiApi() sai_log_set(SAI_API_BFD, SAI_LOG_LEVEL_NOTICE); sai_log_set(SAI_API_MY_MAC, SAI_LOG_LEVEL_NOTICE); sai_log_set(SAI_API_GENERIC_PROGRAMMABLE, SAI_LOG_LEVEL_NOTICE); + sai_log_set(SAI_API_TWAMP, SAI_LOG_LEVEL_NOTICE); } void initSaiRedis() diff --git a/orchagent/twamporch.cpp b/orchagent/twamporch.cpp new file mode 100644 index 0000000000..58f7b5921f --- /dev/null +++ b/orchagent/twamporch.cpp @@ -0,0 +1,1052 @@ +#include "twamporch.h" +#include "vrforch.h" +#include "crmorch.h" +#include "logger.h" +#include "swssnet.h" +#include "converter.h" +#include "sai_serialize.h" +#include "tokenize.h" +#include "notifier.h" +#include "notifications.h" + +#include + +using namespace std; +using namespace swss; + +/* TWAMP infor */ +#define TWAMP_SESSION_MODE "MODE" +#define TWAMP_SESSION_ROLE "ROLE" +#define TWAMP_SESSION_VRF_NAME "VRF_NAME" +#define TWAMP_SESSION_HW_LOOKUP "HW_LOOKUP" + +/* TWAMP-test packet */ +#define TWAMP_SESSION_SRC_IP "SRC_IP" +#define TWAMP_SESSION_SRC_UDP_PORT "SRC_UDP_PORT" +#define TWAMP_SESSION_DST_IP "DST_IP" +#define TWAMP_SESSION_DST_UDP_PORT "DST_UDP_PORT" +#define TWAMP_SESSION_DSCP "DSCP" +#define TWAMP_SESSION_TTL "TTL" +#define TWAMP_SESSION_PACKET_TIMESTAMP_FORMAT "TIMESTAMP_FORMAT" +#define TWAMP_SESSION_PACKET_PADDING_SIZE "PADDING_SIZE" + +/* Session-Sender */ +#define TWAMP_SESSION_TX_PACKET_COUNT "PACKET_COUNT" +#define TWAMP_SESSION_TX_MONITOR_TIME "MONITOR_TIME" +#define TWAMP_SESSION_TX_INTERVAL "TX_INTERVAL" +#define TWAMP_SESSION_TIMEOUT "TIMEOUT" +#define TWAMP_SESSION_STATISTICS_INTERVAL "STATISTICS_INTERVAL" +#define TWAMP_SESSION_ADMIN_STATE "ADMIN_STATE" + +/* TWAMP session status */ +#define TWAMP_SESSION_STATUS "status" +#define TWAMP_SESSION_STATUS_ACTIVE "active" +#define TWAMP_SESSION_STATUS_INACTIVE "inactive" + +#define TWAMP_SESSION_TX_MODE_PACKET_NUM "packet_num" +#define TWAMP_SESSION_TX_MODE_CONTINUOUS "continuous" + +#define TWAMP_SESSION_DSCP_MIN 0 +#define TWAMP_SESSION_DSCP_MAX 63 + +#define TWAMP_SESSION_TIMEOUT_MIN 1 +#define TWAMP_SESSION_TIMEOUT_MAX 10 + +static map twamp_role_map = +{ + { "SENDER", SAI_TWAMP_SESSION_ROLE_SENDER }, + { "REFLECTOR", SAI_TWAMP_SESSION_ROLE_REFLECTOR } +}; + +static map twamp_mode_map = +{ + { "FULL", SAI_TWAMP_MODE_FULL }, + { "LIGHT", SAI_TWAMP_MODE_LIGHT } +}; + +static map timestamp_format_map = +{ + { "NTP", SAI_TWAMP_TIMESTAMP_FORMAT_NTP }, + { "PTP", SAI_TWAMP_TIMESTAMP_FORMAT_PTP } +}; + +static map session_admin_state_map = +{ + { "ENABLED", true }, + { "DISABLED", false } +}; + +static map hw_lookup_map = +{ + { "TRUE", true }, + { "FALSE", false } +}; + +/* Global variables */ +extern sai_object_id_t gSwitchId; +extern sai_object_id_t gVirtualRouterId; +extern sai_switch_api_t *sai_switch_api; +extern sai_twamp_api_t *sai_twamp_api; +extern CrmOrch *gCrmOrch; + +const vector twamp_session_stat_ids = +{ + SAI_TWAMP_SESSION_STAT_RX_PACKETS, + SAI_TWAMP_SESSION_STAT_RX_BYTE, + SAI_TWAMP_SESSION_STAT_TX_PACKETS, + SAI_TWAMP_SESSION_STAT_TX_BYTE, + SAI_TWAMP_SESSION_STAT_DROP_PACKETS, + SAI_TWAMP_SESSION_STAT_MAX_LATENCY, + SAI_TWAMP_SESSION_STAT_MIN_LATENCY, + SAI_TWAMP_SESSION_STAT_AVG_LATENCY, + SAI_TWAMP_SESSION_STAT_MAX_JITTER, + SAI_TWAMP_SESSION_STAT_MIN_JITTER, + SAI_TWAMP_SESSION_STAT_AVG_JITTER +}; + + + +TwampOrch::TwampOrch(TableConnector confDbConnector, TableConnector stateDbConnector, SwitchOrch *switchOrch, PortsOrch *portOrch, VRFOrch *vrfOrch) : + Orch(confDbConnector.first, confDbConnector.second), + m_stateDbTwampTable(stateDbConnector.first, stateDbConnector.second), + m_switchOrch(switchOrch), + m_portsOrch(portOrch), + m_vrfOrch(vrfOrch) +{ + /* Set entries count to 0 */ + m_maxTwampSessionCount = m_twampSessionCount = 0; + + /* Get the Maximum supported TWAMP sessions */ + SWSS_LOG_INFO("Get the Maximum supported TWAMP sessions"); + sai_attribute_t attr; + attr.id = SAI_SWITCH_ATTR_MAX_TWAMP_SESSION; + sai_status_t status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_NOTICE("Twamp session resource availability is not supported. Skipping ..."); + return; + } + else + { + m_maxTwampSessionCount = attr.value.u32; + } + + /* Set MAX entries to state DB */ + if (m_maxTwampSessionCount) + { + vector fvTuple; + fvTuple.emplace_back("MAX_TWAMP_SESSION_COUNT", to_string(m_maxTwampSessionCount)); + m_switchOrch->set_switch_capability(fvTuple); + } + else + { + SWSS_LOG_NOTICE("Twamp session resource availability is not supported. Skipping ..."); + return; + } + + /* Add TWAMP session event notification support */ + DBConnector *notificationsDb = new DBConnector("ASIC_DB", 0); + m_twampNotificationConsumer = new swss::NotificationConsumer(notificationsDb, "NOTIFICATIONS"); + auto twampNotifier = new Notifier(m_twampNotificationConsumer, this, "TWAMP_NOTIFICATIONS"); + Orch::addExecutor(twampNotifier); + register_event_notif = false; + + /* Initialize DB connectors */ + m_asicDb = shared_ptr(new DBConnector("ASIC_DB", 0)); + m_countersDb = shared_ptr(new DBConnector("COUNTERS_DB", 0)); + + /* Initialize VIDTORID table */ + m_vidToRidTable = unique_ptr(new Table(m_asicDb.get(), "VIDTORID")); + + /* Initialize counter tables */ + m_counterTwampSessionNameMapTable = unique_ptr
(new Table(m_countersDb.get(), COUNTERS_TWAMP_SESSION_NAME_MAP)); + m_countersTable = unique_ptr
(new Table(m_countersDb.get(), COUNTERS_TABLE)); +} + +bool TwampOrch::isSessionExists(const string& name) +{ + SWSS_LOG_ENTER(); + + return m_twampEntries.find(name) != m_twampEntries.end(); +} + +bool TwampOrch::getSessionName(const sai_object_id_t oid, string& name) +{ + SWSS_LOG_ENTER(); + + for (const auto& it: m_twampEntries) + { + if (it.second.session_id == oid) + { + name = it.first; + return true; + } + } + + return false; +} + +bool TwampOrch::validateUdpPort(uint16_t udp_port) +{ + if (udp_port == 862) + { + return true; + } + if (udp_port == 863) + { + return true; + } + if (udp_port >= 1025) + { + return true; + } + return false; +} + +void TwampOrch::increaseTwampSessionCount(void) +{ + m_twampSessionCount++; +} + +void TwampOrch::decreaseTwampSessionCount(void) +{ + m_twampSessionCount--; +} + +bool TwampOrch::checkTwampSessionCount(void) +{ + return m_twampSessionCount < m_maxTwampSessionCount; +} + +void TwampOrch::setSessionStatus(const string& name, const string& status) +{ + SWSS_LOG_ENTER(); + + vector fvVector; + fvVector.emplace_back(TWAMP_SESSION_STATUS, status); + m_stateDbTwampTable.set(name, fvVector); +} + +bool TwampOrch::getSessionStatus(const string &name, string& status) +{ + SWSS_LOG_ENTER(); + + if (m_stateDbTwampTable.hget(name, TWAMP_SESSION_STATUS, status)) + { + return true; + } + return false; +} + +void TwampOrch::removeSessionStatus(const string& name) +{ + SWSS_LOG_ENTER(); + + m_stateDbTwampTable.del(name); +} + +void TwampOrch::removeSessionCounter(const sai_object_id_t session_id) +{ + SWSS_LOG_ENTER(); + + string key_pattern = "COUNTERS:" + sai_serialize_object_id(session_id) + "*"; + auto keys = m_countersDb->keys(key_pattern); + for (auto& k : keys) + { + m_countersDb->del(k); + } +} + +void TwampOrch::initSessionStats(const string& name) +{ + SWSS_LOG_ENTER(); + + auto it = m_twampStatistics.find(name); + if (it == m_twampStatistics.end()) + { + SWSS_LOG_ERROR("Failed to init non-existent twamp session %s stat info", name.c_str()); + return; + } + + TwampStats& total_stats = it->second; + + total_stats.rx_packets = 0; + total_stats.rx_bytes = 0; + total_stats.tx_packets = 0; + total_stats.tx_bytes = 0; + total_stats.drop_packets = 0; + total_stats.max_latency = 0; + total_stats.min_latency = 0; + total_stats.avg_latency = 0; + total_stats.max_jitter = 0; + total_stats.min_jitter = 0; + total_stats.avg_jitter = 0; + total_stats.avg_latency_total = 0; + total_stats.avg_jitter_total = 0; +} + +bool TwampOrch::registerTwampEventNotification(void) +{ + sai_attribute_t attr; + sai_status_t status; + sai_attr_capability_t capability; + + status = sai_query_attribute_capability(gSwitchId, SAI_OBJECT_TYPE_SWITCH, + SAI_SWITCH_ATTR_TWAMP_SESSION_EVENT_NOTIFY, + &capability); + + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_NOTICE("Unable to query the TWAMP event notification capability"); + return false; + } + + if (!capability.set_implemented) + { + SWSS_LOG_NOTICE("TWAMP register event notification not supported"); + return false; + } + + attr.id = SAI_SWITCH_ATTR_TWAMP_SESSION_EVENT_NOTIFY; + attr.value.ptr = (void *)on_twamp_session_event; + + status = sai_switch_api->set_switch_attribute(gSwitchId, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to register TWAMP notification handler"); + return false; + } + + return true; +} + +bool TwampOrch::activateSession(const string& name, TwampEntry& entry) +{ + SWSS_LOG_ENTER(); + + sai_status_t status; + sai_attribute_t attr; + vector attrs; + + attr.id = SAI_TWAMP_SESSION_ATTR_TWAMP_MODE; + attr.value.s32 = entry.mode; + attrs.emplace_back(attr); + + attr.id = SAI_TWAMP_SESSION_ATTR_SESSION_ROLE; + attr.value.s32 = entry.role; + attrs.emplace_back(attr); + + attr.id = SAI_TWAMP_SESSION_ATTR_HW_LOOKUP_VALID; + attr.value.booldata = entry.hw_lookup; + attrs.emplace_back(attr); + + if (entry.vrf_id) + { + attr.id = SAI_TWAMP_SESSION_ATTR_VIRTUAL_ROUTER; + attr.value.oid = entry.vrf_id; + attrs.emplace_back(attr); + } + + attr.id = SAI_TWAMP_SESSION_ATTR_SRC_IP; + copy(attr.value.ipaddr, entry.src_ip); + attrs.emplace_back(attr); + + attr.id = SAI_TWAMP_SESSION_ATTR_DST_IP; + copy(attr.value.ipaddr, entry.dst_ip); + attrs.emplace_back(attr); + + attr.id = SAI_TWAMP_SESSION_ATTR_UDP_SRC_PORT; + attr.value.u32 = entry.src_udp_port; + attrs.emplace_back(attr); + + attr.id = SAI_TWAMP_SESSION_ATTR_UDP_DST_PORT; + attr.value.u32 = entry.dst_udp_port; + attrs.emplace_back(attr); + + if (entry.role == SAI_TWAMP_SESSION_ROLE_SENDER) + { + if (entry.tx_mode == TWAMP_SESSION_TX_MODE_PACKET_NUM) + { + attr.id = SAI_TWAMP_SESSION_ATTR_TWAMP_PKT_TX_MODE; + attr.value.s32 = SAI_TWAMP_PKT_TX_MODE_PACKET_COUNT; + attrs.emplace_back(attr); + + attr.id = SAI_TWAMP_SESSION_ATTR_TX_PKT_CNT; + attr.value.u32 = entry.packet_count; + attrs.emplace_back(attr); + } + else if (entry.tx_mode == TWAMP_SESSION_TX_MODE_CONTINUOUS) + { + if (entry.monitor_time) + { + attr.id = SAI_TWAMP_SESSION_ATTR_TWAMP_PKT_TX_MODE; + attr.value.u32 = SAI_TWAMP_PKT_TX_MODE_PERIOD; + attrs.emplace_back(attr); + + attr.id = SAI_TWAMP_SESSION_ATTR_TX_PKT_PERIOD; + attr.value.u32 = entry.monitor_time; + attrs.emplace_back(attr); + } + else + { + attr.id = SAI_TWAMP_SESSION_ATTR_TWAMP_PKT_TX_MODE; + attr.value.u32 = SAI_TWAMP_PKT_TX_MODE_CONTINUOUS; + attrs.emplace_back(attr); + } + } + + attr.id = SAI_TWAMP_SESSION_ATTR_TX_INTERVAL; + attr.value.u32 = entry.tx_interval; + attrs.emplace_back(attr); + + attr.id = SAI_TWAMP_SESSION_ATTR_TIMEOUT; + attr.value.u32 = entry.timeout; + attrs.emplace_back(attr); + + attr.id = SAI_TWAMP_SESSION_ATTR_STATISTICS_INTERVAL; + attr.value.u32 = entry.statistics_interval; + attrs.emplace_back(attr); + + attr.id = SAI_TWAMP_SESSION_ATTR_SESSION_ENABLE_TRANSMIT; + attr.value.booldata = entry.admin_state; + attrs.emplace_back(attr); + } + + setSessionStatus(name, TWAMP_SESSION_STATUS_INACTIVE); + + status = sai_twamp_api->create_twamp_session(&entry.session_id, gSwitchId, (uint32_t)attrs.size(), attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create twamp session %s, status %d", name.c_str(), status); + task_process_status handle_status = handleSaiRemoveStatus(SAI_API_TWAMP, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } + } + + /* increase VRF reference count */ + m_vrfOrch->increaseVrfRefCount(entry.vrf_id); + gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_TWAMP_ENTRY); + + increaseTwampSessionCount(); + + if (entry.role == SAI_TWAMP_SESSION_ROLE_REFLECTOR) + { + setSessionStatus(name, TWAMP_SESSION_STATUS_ACTIVE); + } + + return true; +} + +bool TwampOrch::deactivateSession(const string& name, TwampEntry& entry) +{ + SWSS_LOG_ENTER(); + sai_status_t status; + + status = sai_twamp_api->remove_twamp_session(entry.session_id); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to remove twamp session %s, status %d", name.c_str(), status); + task_process_status handle_status = handleSaiRemoveStatus(SAI_API_TWAMP, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } + } + + /* decrease VRF reference count */ + m_vrfOrch->decreaseVrfRefCount(entry.vrf_id); + gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_TWAMP_ENTRY); + + decreaseTwampSessionCount(); + + setSessionStatus(name, TWAMP_SESSION_STATUS_INACTIVE); + + return true; +} + +bool TwampOrch::setSessionTransmitEn(TwampEntry& entry, string admin_state) +{ + SWSS_LOG_ENTER(); + + if (entry.role != SAI_TWAMP_SESSION_ROLE_SENDER) + { + return false; + } + + auto found = session_admin_state_map.find(admin_state); + if (found == session_admin_state_map.end()) + { + SWSS_LOG_ERROR("Incorrect transmit value: %s", admin_state.c_str()); + return false; + } + + sai_attribute_t attr; + attr.id = SAI_TWAMP_SESSION_ATTR_SESSION_ENABLE_TRANSMIT; + attr.value.booldata = found->second; + sai_status_t status = sai_twamp_api->set_twamp_session_attribute(entry.session_id, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set twamp session %" PRIx64 " %s transmit, status %d", + entry.session_id, admin_state.c_str(), status); + task_process_status handle_status = handleSaiRemoveStatus(SAI_API_TWAMP, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } + } + + return true; +} + +task_process_status TwampOrch::createEntry(const string& key, const vector& data) +{ + SWSS_LOG_ENTER(); + + if (!register_event_notif) + { + if (!registerTwampEventNotification()) + { + SWSS_LOG_ERROR("TWAMP session for %s cannot be created", key.c_str()); + return task_process_status::task_failed; + } + register_event_notif = true; + } + + if (!checkTwampSessionCount()) + { + SWSS_LOG_NOTICE("Failed to create twamp session %s: resources are not available", key.c_str()); + return task_process_status::task_failed; + } + + TwampEntry entry; + for (auto i : data) + { + try { + string attr_name = to_upper(fvField(i)); + string attr_value = fvValue(i); + + if (attr_name == TWAMP_SESSION_MODE) + { + string value = to_upper(attr_value); + if (twamp_mode_map.find(value) == twamp_mode_map.end()) + { + SWSS_LOG_ERROR("Failed to parse valid mode %s", attr_value.c_str()); + return task_process_status::task_invalid_entry; + } + entry.mode = twamp_mode_map[value]; + } + else if (attr_name == TWAMP_SESSION_ROLE) + { + string value = to_upper(attr_value); + if (twamp_role_map.find(value) == twamp_role_map.end()) + { + SWSS_LOG_ERROR("Failed to parse valid role %s", attr_value.c_str()); + return task_process_status::task_invalid_entry; + } + entry.role = twamp_role_map[value]; + } + else if (attr_name == TWAMP_SESSION_SRC_IP) + { + entry.src_ip = attr_value; + } + else if (attr_name == TWAMP_SESSION_DST_IP) + { + entry.dst_ip = attr_value; + } + else if (attr_name == TWAMP_SESSION_SRC_UDP_PORT) + { + uint16_t value = to_uint(attr_value); + if (!validateUdpPort(value)) + { + SWSS_LOG_ERROR("Failed to parse valid souce udp port %d", value); + return task_process_status::task_invalid_entry; + } + entry.src_udp_port = value; + } + else if (attr_name == TWAMP_SESSION_DST_UDP_PORT) + { + uint16_t value = to_uint(attr_value); + if (!validateUdpPort(value)) + { + SWSS_LOG_ERROR("Failed to parse valid destination udp port %d", value); + return task_process_status::task_invalid_entry; + } + entry.dst_udp_port = to_uint(attr_value); + } + else if (attr_name == TWAMP_SESSION_VRF_NAME) + { + if (attr_value == "default") + { + entry.vrf_id = gVirtualRouterId; + } + else + { + if (!m_vrfOrch->isVRFexists(attr_value)) + { + SWSS_LOG_WARN("Vrf '%s' hasn't been created yet", attr_value.c_str()); + return task_process_status::task_invalid_entry; + } + entry.vrf_id = m_vrfOrch->getVRFid(attr_value); + } + } + else if (attr_name == TWAMP_SESSION_DSCP) + { + entry.dscp = to_uint(attr_value, TWAMP_SESSION_DSCP_MIN, TWAMP_SESSION_DSCP_MAX); + } + else if (attr_name == TWAMP_SESSION_TTL) + { + entry.ttl = to_uint(attr_value); + } + else if (attr_name == TWAMP_SESSION_PACKET_TIMESTAMP_FORMAT) + { + string value = to_upper(attr_value); + if (timestamp_format_map.find(value) == timestamp_format_map.end()) + { + SWSS_LOG_ERROR("Failed to parse timestamp format value: %s", attr_value.c_str()); + return task_process_status::task_invalid_entry; + } + entry.timestamp_format = timestamp_format_map[value]; + } + else if (attr_name == TWAMP_SESSION_PACKET_PADDING_SIZE) + { + entry.padding_size = to_uint(attr_value); + } + else if (attr_name == TWAMP_SESSION_TX_PACKET_COUNT) + { + if (entry.tx_mode == TWAMP_SESSION_TX_MODE_CONTINUOUS) + { + SWSS_LOG_ERROR("Configured packet count %s is conflict with monitor time", attr_value.c_str()); + return task_process_status::task_invalid_entry; + } + + entry.packet_count = to_uint(attr_value); + entry.tx_mode = TWAMP_SESSION_TX_MODE_PACKET_NUM; + } + else if (attr_name == TWAMP_SESSION_TX_MONITOR_TIME) + { + if (entry.tx_mode == TWAMP_SESSION_TX_MODE_PACKET_NUM) + { + SWSS_LOG_ERROR("Configured monitor time %s is conflict with packet count", attr_value.c_str()); + return task_process_status::task_invalid_entry; + } + + entry.monitor_time = to_uint(attr_value); + entry.tx_mode = TWAMP_SESSION_TX_MODE_CONTINUOUS; + } + else if (attr_name == TWAMP_SESSION_TX_INTERVAL) + { + entry.tx_interval = to_uint(attr_value); + } + else if (attr_name == TWAMP_SESSION_STATISTICS_INTERVAL) + { + entry.statistics_interval = to_uint(attr_value); + } + else if (attr_name == TWAMP_SESSION_TIMEOUT) + { + entry.timeout = to_uint(attr_value, TWAMP_SESSION_TIMEOUT_MIN, TWAMP_SESSION_TIMEOUT_MAX); + } + else if (attr_name == TWAMP_SESSION_ADMIN_STATE) + { + string value = to_upper(attr_value); + if (session_admin_state_map.find(value) == session_admin_state_map.end()) + { + SWSS_LOG_ERROR("Failed to parse transmit mode value: %s", attr_value.c_str()); + return task_process_status::task_invalid_entry; + } + entry.admin_state = session_admin_state_map[value]; + } + else if (attr_name == TWAMP_SESSION_HW_LOOKUP) + { + string value = to_upper(attr_value); + if (hw_lookup_map.find(value) == hw_lookup_map.end()) + { + SWSS_LOG_ERROR("Failed to parse hw lookup value: %s", attr_value.c_str()); + return task_process_status::task_invalid_entry; + } + entry.hw_lookup = hw_lookup_map[value]; + } + else + { + SWSS_LOG_ERROR("Failed to parse session %s configuration. Unknown attribute %s", key.c_str(), attr_name.c_str()); + return task_process_status::task_invalid_entry; + } + } + catch (const exception& e) + { + SWSS_LOG_ERROR("Failed to parse session %s attribute %s error: %s.", key.c_str(), fvField(i).c_str(), e.what()); + return task_process_status::task_invalid_entry; + } + catch (...) + { + SWSS_LOG_ERROR("Failed to parse session %s attribute %s. Unknown error has been occurred", key.c_str(), fvField(i).c_str()); + return task_process_status::task_failed; + } + } + + m_twampEntries.emplace(key, entry); + + if (entry.role == SAI_TWAMP_SESSION_ROLE_SENDER) + { + TwampStats hw_stats; + m_twampStatistics.emplace(key, hw_stats); + initSessionStats(key); + } + + auto &session = m_twampEntries.find(key)->second; + if (!activateSession(key, session)) + { + SWSS_LOG_ERROR("Failed to create twamp session %s", key.c_str()); + return task_process_status::task_failed; + } + + return task_process_status::task_success; +} + +task_process_status TwampOrch::updateEntry(const string& key, const vector& data) +{ + SWSS_LOG_ENTER(); + + auto it = m_twampEntries.find(key); + if (it == m_twampEntries.end()) + { + SWSS_LOG_NOTICE("Failed to set twamp session, session %s not exists", key.c_str()); + return task_process_status::task_invalid_entry; + } + TwampEntry& entry = it->second; + + for (auto i : data) + { + try { + const auto &attr_field = to_upper(fvField(i)); + const auto &attr_value = fvValue(i); + + if (attr_field == TWAMP_SESSION_ADMIN_STATE) + { + string value = to_upper(attr_value); + if (setSessionTransmitEn(entry, value)) + { + entry.admin_state = session_admin_state_map[value]; + if (entry.admin_state) + { + string running_status; + getSessionStatus(key, running_status); + if (running_status == TWAMP_SESSION_STATUS_INACTIVE) + { + removeSessionCounter(entry.session_id); + initSessionStats(key); + } + setSessionStatus(key, TWAMP_SESSION_STATUS_ACTIVE); + SWSS_LOG_NOTICE("Activated twamp session %s", key.c_str()); + } + else + { + setSessionStatus(key, TWAMP_SESSION_STATUS_INACTIVE); + SWSS_LOG_NOTICE("Deactivated twamp session %s", key.c_str()); + } + } + else + { + SWSS_LOG_ERROR("Failed to set twamp session %s transmit %s", key.c_str(), attr_value.c_str()); + } + } + else + { + SWSS_LOG_DEBUG("Ignore to parse session %s configuration attribute %s", key.c_str(), fvField(i).c_str()); + } + } + catch (const exception& e) + { + SWSS_LOG_ERROR("Failed to parse session %s attribute %s error: %s.", key.c_str(), fvField(i).c_str(), e.what()); + return task_process_status::task_invalid_entry; + } + catch (...) + { + SWSS_LOG_ERROR("Failed to parse session %s attribute %s. Unknown error has been occurred", key.c_str(), fvField(i).c_str()); + return task_process_status::task_failed; + } + } + + return task_process_status::task_success; +} + +task_process_status TwampOrch::deleteEntry(const string& key) +{ + SWSS_LOG_ENTER(); + + auto it = m_twampEntries.find(key); + if (it == m_twampEntries.end()) + { + SWSS_LOG_ERROR("Failed to remove non-existent twamp session %s", key.c_str()); + return task_process_status::task_invalid_entry; + } + + TwampEntry& entry = it->second; + + if (!deactivateSession(key, entry)) + { + SWSS_LOG_ERROR("Failed to remove twamp session %s", key.c_str()); + return task_process_status::task_failed; + } + + /* remove TWAMP session in STATE_DB */ + removeSessionStatus(key); + + /* remove TWAMP session maps in COUNTERS_DB */ + m_counterTwampSessionNameMapTable->hdel("", key); + + /* remove TWAMP session in COUNTER_DB */ + removeSessionCounter(entry.session_id); + + /* remove soft table in orchagent */ + m_twampEntries.erase(key); + m_twampStatistics.erase(key); + + SWSS_LOG_NOTICE("Removed twamp session %s", key.c_str()); + + return task_process_status::task_success; +} + +void TwampOrch::doTask(Consumer& consumer) +{ + SWSS_LOG_ENTER(); + + if (!m_portsOrch->allPortsReady()) + { + return; + } + + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + KeyOpFieldsValuesTuple t = it->second; + + string key = kfvKey(t); + string op = kfvOp(t); + auto data = kfvFieldsValues(t); + task_process_status task_status = task_process_status::task_failed; + + if (op == SET_COMMAND) + { + if (!isSessionExists(key)) + { + task_status = createEntry(key, data); + } + else + { + task_status = updateEntry(key, data); + } + } + else if (op == DEL_COMMAND) + { + task_status = deleteEntry(key); + } + else + { + SWSS_LOG_ERROR("Unknown operation type %s", op.c_str()); + } + + /* Specifically retry the task when asked */ + if (task_status == task_process_status::task_need_retry) + { + it++; + } + else + { + it = consumer.m_toSync.erase(it); + } + } +} + +bool TwampOrch::addCounterNameMap(const string& name, const sai_object_id_t session_id) +{ + SWSS_LOG_ENTER(); + + string value; + const auto id = sai_serialize_object_id(session_id); + + if (m_vidToRidTable->hget("", id, value)) + { + vector fields; + fields.emplace_back(name, id); + m_counterTwampSessionNameMapTable->set("", fields); + + return true; + } + else + { + SWSS_LOG_NOTICE("TWAMP session counter %s already exists.", name.c_str()); + return true; + } + + return false; +} + +void TwampOrch::saveSessionStatsLatest(const sai_object_id_t session_id, const uint32_t index, const vector& stats) +{ + SWSS_LOG_ENTER(); + + vector values; + + for (const auto& it: twamp_session_stat_ids) + { + values.emplace_back(sai_serialize_twamp_session_stat(it), to_string(stats[it])); + } + + m_countersTable->set(sai_serialize_object_id(session_id) + ":INDEX:" + to_string(index), values); + + return; +} + +void TwampOrch::calculateCounters(const string& name, const uint32_t index, const vector& stats) +{ + SWSS_LOG_ENTER(); + + auto it = m_twampStatistics.find(name); + if (it == m_twampStatistics.end()) + { + SWSS_LOG_ERROR("Failed to caculate non-existent twamp session %s", name.c_str()); + return; + } + + TwampStats& total_stats = it->second; + /* packets */ + total_stats.rx_packets += stats[SAI_TWAMP_SESSION_STAT_RX_PACKETS]; + total_stats.rx_bytes += stats[SAI_TWAMP_SESSION_STAT_RX_BYTE]; + total_stats.tx_packets += stats[SAI_TWAMP_SESSION_STAT_TX_PACKETS]; + total_stats.tx_bytes += stats[SAI_TWAMP_SESSION_STAT_TX_BYTE]; + total_stats.drop_packets += stats[SAI_TWAMP_SESSION_STAT_DROP_PACKETS]; + + /* latency */ + total_stats.max_latency = (stats[SAI_TWAMP_SESSION_STAT_MAX_LATENCY] > total_stats.max_latency) ? + stats[SAI_TWAMP_SESSION_STAT_MAX_LATENCY] : total_stats.max_latency; + total_stats.min_latency = (index == 1) ? stats[SAI_TWAMP_SESSION_STAT_MIN_LATENCY] : + ((stats[SAI_TWAMP_SESSION_STAT_MIN_LATENCY] < total_stats.min_latency) ? + stats[SAI_TWAMP_SESSION_STAT_MIN_LATENCY] : total_stats.min_latency); + total_stats.avg_latency_total += stats[SAI_TWAMP_SESSION_STAT_AVG_LATENCY]; + total_stats.avg_latency = total_stats.avg_latency_total / index; + + /* jitter */ + total_stats.max_jitter = (stats[SAI_TWAMP_SESSION_STAT_MAX_JITTER] > total_stats.max_jitter) ? + stats[SAI_TWAMP_SESSION_STAT_MAX_JITTER] : total_stats.max_jitter; + total_stats.min_jitter = (index == 1) ? stats[SAI_TWAMP_SESSION_STAT_MIN_JITTER] : + ((stats[SAI_TWAMP_SESSION_STAT_MIN_JITTER] < total_stats.min_jitter) ? + stats[SAI_TWAMP_SESSION_STAT_MIN_JITTER] : total_stats.min_jitter); + total_stats.avg_jitter_total += stats[SAI_TWAMP_SESSION_STAT_AVG_JITTER]; + total_stats.avg_jitter = total_stats.avg_jitter_total / index; +} + +void TwampOrch::saveCountersTotal(const string& name, const sai_object_id_t session_id) +{ + SWSS_LOG_ENTER(); + + vector values; + + auto it = m_twampStatistics.find(name); + if (it == m_twampStatistics.end()) + { + SWSS_LOG_ERROR("Failed to caculate non-existent twamp session %s", + name.c_str()); + return; + } + + TwampStats& total_stats = it->second; + + values.emplace_back(sai_serialize_twamp_session_stat(SAI_TWAMP_SESSION_STAT_RX_PACKETS), to_string(total_stats.rx_packets)); + values.emplace_back(sai_serialize_twamp_session_stat(SAI_TWAMP_SESSION_STAT_RX_BYTE), to_string(total_stats.rx_bytes)); + values.emplace_back(sai_serialize_twamp_session_stat(SAI_TWAMP_SESSION_STAT_TX_PACKETS), to_string(total_stats.tx_packets)); + values.emplace_back(sai_serialize_twamp_session_stat(SAI_TWAMP_SESSION_STAT_TX_BYTE), to_string(total_stats.tx_bytes)); + values.emplace_back(sai_serialize_twamp_session_stat(SAI_TWAMP_SESSION_STAT_DROP_PACKETS), to_string(total_stats.drop_packets)); + values.emplace_back(sai_serialize_twamp_session_stat(SAI_TWAMP_SESSION_STAT_MAX_LATENCY), to_string(total_stats.max_latency)); + values.emplace_back(sai_serialize_twamp_session_stat(SAI_TWAMP_SESSION_STAT_MIN_LATENCY), to_string(total_stats.min_latency)); + values.emplace_back(sai_serialize_twamp_session_stat(SAI_TWAMP_SESSION_STAT_AVG_LATENCY), to_string(total_stats.avg_latency)); + values.emplace_back(sai_serialize_twamp_session_stat(SAI_TWAMP_SESSION_STAT_MAX_JITTER), to_string(total_stats.max_jitter)); + values.emplace_back(sai_serialize_twamp_session_stat(SAI_TWAMP_SESSION_STAT_MIN_JITTER), to_string(total_stats.min_jitter)); + values.emplace_back(sai_serialize_twamp_session_stat(SAI_TWAMP_SESSION_STAT_AVG_JITTER), to_string(total_stats.avg_jitter)); + + m_countersTable->set(sai_serialize_object_id(session_id), values); +} + +void TwampOrch::doTask(NotificationConsumer& consumer) +{ + SWSS_LOG_ENTER(); + + if (!m_portsOrch->allPortsReady()) + { + return; + } + + std::string op; + std::string data; + std::vector values; + + consumer.pop(op, data, values); + + if (&consumer != m_twampNotificationConsumer) + { + return; + } + + if (op == "twamp_session_event") + { + uint32_t count = 0; + sai_twamp_session_event_notification_data_t *twamp_session = nullptr; + + sai_deserialize_twamp_session_event_ntf(data, count, &twamp_session); + + for (uint32_t i = 0; i < count; i++) + { + string name; + sai_object_id_t session_id = twamp_session[i].twamp_session_id; + sai_twamp_session_state_t session_state = twamp_session[i].session_state; + uint32_t stats_index = twamp_session[i].session_stats.index; + + if (!getSessionName(session_id, name)) + { + continue; + } + + /* update state db */ + if (session_state == SAI_TWAMP_SESSION_STATE_ACTIVE) + { + setSessionStatus(name, TWAMP_SESSION_STATUS_ACTIVE); + } + else + { + setSessionStatus(name, TWAMP_SESSION_STATUS_INACTIVE); + } + + /* save counter db */ + if (twamp_session[i].session_stats.number_of_counters) + { + if (0 == stats_index) + { + continue; + } + else if (1 == stats_index) + { + addCounterNameMap(name, session_id); + } + + vector hw_stats; + hw_stats.resize(twamp_session_stat_ids.size()); + for (uint32_t j = 0; j < twamp_session[i].session_stats.number_of_counters; j++) + { + uint32_t counters_id = twamp_session[i].session_stats.counters_ids[j]; + auto it = find(twamp_session_stat_ids.begin(), twamp_session_stat_ids.end(), counters_id); + if (it != twamp_session_stat_ids.end()) + { + hw_stats[counters_id] = twamp_session[i].session_stats.counters[j]; + } + } + + saveSessionStatsLatest(session_id, stats_index, hw_stats); + calculateCounters(name, stats_index, hw_stats); + saveCountersTotal(name, session_id); + } + } + + sai_deserialize_free_twamp_session_event_ntf(count, twamp_session); + } +} diff --git a/orchagent/twamporch.h b/orchagent/twamporch.h new file mode 100644 index 0000000000..09134f6be4 --- /dev/null +++ b/orchagent/twamporch.h @@ -0,0 +1,136 @@ +#ifndef SWSS_TWAMPORCH_H +#define SWSS_TWAMPORCH_H + +#include "orch.h" +#include "observer.h" +#include "switchorch.h" +#include "portsorch.h" +#include "vrforch.h" +#include "ipaddress.h" +#include "table.h" +#include + +struct TwampStats +{ + uint64_t rx_packets; + uint64_t rx_bytes; + uint64_t tx_packets; + uint64_t tx_bytes; + uint64_t drop_packets; + uint64_t max_latency; + uint64_t min_latency; + uint64_t avg_latency; + uint64_t max_jitter; + uint64_t min_jitter; + uint64_t avg_jitter; + uint64_t avg_latency_total; + uint64_t avg_jitter_total; +}; + +struct TwampEntry +{ + uint8_t mode; /* twamp mode: full, light */ + uint8_t role; /* sender, reflector */ + bool admin_state; /* test packet state. enabled, disabled */ + bool hw_lookup; + + sai_object_id_t vrf_id; + IpAddress src_ip; + IpAddress dst_ip; + uint16_t src_udp_port; + uint16_t dst_udp_port; + uint16_t padding_size; + uint8_t dscp; + uint8_t ttl; + uint8_t timestamp_format; + + /* sender attr */ + string tx_mode; + uint32_t packet_count; + uint32_t monitor_time; /* second */ + uint32_t tx_interval; /* millisecond */ + uint32_t statistics_interval; /* millisecond */ + uint8_t timeout; /* second */ + + sai_object_id_t session_id; + + TwampEntry() + { + session_id = 0; + admin_state = false; + hw_lookup = true; + vrf_id = 0; + packet_count = 0; + monitor_time = 0; + tx_interval = 0; + statistics_interval = 0; + timeout = 0; + }; +}; + +typedef map TwampEntryTable; +typedef map TwampStatsTable; + +class TwampOrch : public Orch +{ +public: + TwampOrch(TableConnector confDbConnector, TableConnector stateDbConnector, + SwitchOrch *switchOrch, PortsOrch *portOrch, VRFOrch *vrfOrch); + + ~TwampOrch() + { + // do nothing + } + + bool isSessionExists(const string&); + bool getSessionName(const sai_object_id_t oid, string& name); + +private: + SwitchOrch *m_switchOrch; + PortsOrch *m_portsOrch; + VRFOrch *m_vrfOrch; + NotificationConsumer* m_twampNotificationConsumer; + bool register_event_notif; + + unsigned int m_twampSessionCount; + unsigned int m_maxTwampSessionCount; + + TwampEntryTable m_twampEntries; + TwampStatsTable m_twampStatistics; + + shared_ptr m_asicDb; + shared_ptr m_countersDb; + unique_ptr
m_counterTwampSessionNameMapTable; + unique_ptr
m_countersTable; + unique_ptr
m_vidToRidTable; + Table m_stateDbTwampTable; + + bool validateUdpPort(uint16_t udp_port); + void increaseTwampSessionCount(void); + void decreaseTwampSessionCount(void); + bool checkTwampSessionCount(void); + + void setSessionStatus(const string&, const string&); + bool getSessionStatus(const string&, string&); + void removeSessionStatus(const string&); + void removeSessionCounter(const sai_object_id_t); + void initSessionStats(const string&); + + bool registerTwampEventNotification(void); + bool activateSession(const string&, TwampEntry&); + bool deactivateSession(const string&, TwampEntry&); + bool setSessionTransmitEn(TwampEntry&, string test_start); + + task_process_status createEntry(const string&, const vector&); + task_process_status updateEntry(const string&, const vector&); + task_process_status deleteEntry(const string&); + void doTask(Consumer& consumer); + + bool addCounterNameMap(const string&, const sai_object_id_t session_id); + void saveSessionStatsLatest(const sai_object_id_t session_id, const uint32_t index, const vector& stats); + void calculateCounters(const string&, const uint32_t index, const vector& stats); + void saveCountersTotal(const string&, const sai_object_id_t session_id); + void doTask(NotificationConsumer& consumer); +}; + +#endif /* SWSS_TWAMPORCH_H */ diff --git a/tests/conftest.py b/tests/conftest.py index ef95cd96bd..93f54c824e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -29,6 +29,7 @@ from dvslib import dvs_policer from dvslib import dvs_hash from dvslib import dvs_switch +from dvslib import dvs_twamp from buffer_model import enable_dynamic_buffer @@ -1992,6 +1993,14 @@ def dvs_hash_manager(request, dvs): def dvs_switch_manager(request, dvs): request.cls.dvs_switch = dvs_switch.DVSSwitch(dvs.get_asic_db()) +@pytest.fixture(scope="class") +def dvs_twamp_manager(request, dvs): + request.cls.dvs_twamp = dvs_twamp.DVSTwamp(dvs.get_asic_db(), + dvs.get_config_db(), + dvs.get_state_db(), + dvs.get_counters_db(), + dvs.get_app_db()) + ##################### DPB fixtures ########################################### def create_dpb_config_file(dvs): cmd = "sonic-cfggen -j /etc/sonic/init_cfg.json -j /tmp/ports.json --print-data > /tmp/dpb_config_db.json" diff --git a/tests/dvslib/dvs_twamp.py b/tests/dvslib/dvs_twamp.py new file mode 100644 index 0000000000..864b072bd6 --- /dev/null +++ b/tests/dvslib/dvs_twamp.py @@ -0,0 +1,98 @@ +"""Utilities for interacting with TWAMP Light objects when writing VS tests.""" + +class DVSTwamp(object): + def __init__(self, adb, cdb, sdb, cntrdb, appdb): + self.asic_db = adb + self.config_db = cdb + self.state_db = sdb + self.counters_db = cntrdb + self.app_db = appdb + + def create_twamp_light_session_sender_packet_count(self, name, sip, sport, dip, dport, packet_count=100, tx_interval=100, timeout=5, stats_interval=None): + twamp_light_entry = {"mode": "LIGHT", + "role": "SENDER", + "src_ip": sip, + "src_udp_port": sport, + "dst_ip": dip, + "dst_udp_port": dport, + "packet_count": packet_count, + "tx_interval": tx_interval, + "timeout": timeout + } + if stats_interval: + twamp_light_entry["statistics_interval"] = str(stats_interval) + else: + twamp_light_entry["statistics_interval"] = str(int(packet_count) * int(tx_interval) + int(timeout)*1000) + self.config_db.create_entry("TWAMP_SESSION", name, twamp_light_entry) + + def create_twamp_light_session_sender_continuous(self, name, sip, sport, dip, dport, monitor_time=0, tx_interval=100, timeout=5, stats_interval=None): + twamp_light_entry = {"mode": "LIGHT", + "role": "SENDER", + "src_ip": sip, + "src_udp_port": sport, + "dst_ip": dip, + "dst_udp_port": dport, + "monitor_time": monitor_time, + "tx_interval": tx_interval, + "timeout": timeout + } + if stats_interval: + twamp_light_entry["statistics_interval"] = str(stats_interval) + else: + twamp_light_entry["statistics_interval"] = str(int(monitor_time)*1000) + self.config_db.create_entry("TWAMP_SESSION", name, twamp_light_entry) + + def create_twamp_light_session_reflector(self, name, sip, sport, dip, dport): + twamp_light_entry = {"mode": "LIGHT", + "role": "REFLECTOR", + "src_ip": sip, + "src_udp_port": sport, + "dst_ip": dip, + "dst_udp_port": dport + } + self.config_db.create_entry("TWAMP_SESSION", name, twamp_light_entry) + + def start_twamp_light_sender(self, name): + twamp_light_entry = {"admin_state": "enabled"} + self.config_db.create_entry("TWAMP_SESSION", name, twamp_light_entry) + + def stop_twamp_light_sender(self, name): + twamp_light_entry = {"admin_state": "disabled"} + self.config_db.create_entry("TWAMP_SESSION", name, twamp_light_entry) + + def remove_twamp_light_session(self, name): + self.config_db.delete_entry("TWAMP_SESSION", name) + + def get_twamp_light_session_status(self, name): + return self.get_twamp_light_session_state(name)["status"] + + def get_twamp_light_session_state(self, name): + tbl = swsscommon.Table(self.sdb, "TWAMP_SESSION_TABLE") + (status, fvs) = tbl.get(name) + assert status == True + assert len(fvs) > 0 + return { fv[0]: fv[1] for fv in fvs } + + def verify_session_status(self, name, status="active", expected=1): + self.state_db.wait_for_n_keys("TWAMP_SESSION_TABLE", expected) + if expected: + self.state_db.wait_for_field_match("TWAMP_SESSION_TABLE", name, {"status": status}) + + def verify_no_session(self): + self.config_db.wait_for_n_keys("TWAMP_SESSION", 0) + self.state_db.wait_for_n_keys("TWAMP_SESSION_TABLE", 0) + + def verify_session_asic_db(self, dvs, name, asic_table=None, expected=1): + session_oids = self.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_TWAMP_SESSION", expected) + session_oid = session_oids[0] + dvs.asic_db.wait_for_field_match("ASIC_STATE:SAI_OBJECT_TYPE_TWAMP_SESSION", session_oid, asic_table) + + def verify_session_counter_db(self, dvs, name, counter_table=None, expected=1, expected_item=1): + fvs = dvs.counters_db.get_entry("COUNTERS_TWAMP_SESSION_NAME_MAP", "") + fvs = dict(fvs) + total_key = self.counters_db.db_connection.keys("COUNTERS:{}".format(fvs[name])) + assert len(total_key) == expected, "TWAMP Light counter entries are not available in counter db" + dvs.counters_db.wait_for_field_match("COUNTERS", fvs[name], counter_table) + item_keys = self.counters_db.db_connection.keys("COUNTERS:{}:INDEX:*".format(fvs[name])) + assert len(item_keys) == expected_item, "TWAMP Light counter entries are not available in counter db" + diff --git a/tests/mock_tests/Makefile.am b/tests/mock_tests/Makefile.am index b00d4af1f4..b5afd53793 100644 --- a/tests/mock_tests/Makefile.am +++ b/tests/mock_tests/Makefile.am @@ -58,6 +58,7 @@ tests_SOURCES = aclorch_ut.cpp \ test_failure_handling.cpp \ warmrestarthelper_ut.cpp \ neighorch_ut.cpp \ + twamporch_ut.cpp \ $(top_srcdir)/warmrestart/warmRestartHelper.cpp \ $(top_srcdir)/lib/gearboxutils.cpp \ $(top_srcdir)/lib/subintf.cpp \ @@ -131,7 +132,8 @@ tests_SOURCES = aclorch_ut.cpp \ $(top_srcdir)/cfgmgr/buffermgrdyn.cpp \ $(top_srcdir)/warmrestart/warmRestartAssist.cpp \ $(top_srcdir)/orchagent/dash/pbutils.cpp \ - $(top_srcdir)/cfgmgr/coppmgr.cpp + $(top_srcdir)/cfgmgr/coppmgr.cpp \ + $(top_srcdir)/orchagent/twamporch.cpp tests_SOURCES += $(FLEX_CTR_DIR)/flex_counter_manager.cpp $(FLEX_CTR_DIR)/flex_counter_stat_manager.cpp $(FLEX_CTR_DIR)/flow_counter_handler.cpp $(FLEX_CTR_DIR)/flowcounterrouteorch.cpp tests_SOURCES += $(DEBUG_CTR_DIR)/debug_counter.cpp $(DEBUG_CTR_DIR)/drop_counter.cpp diff --git a/tests/mock_tests/mock_orchagent_main.h b/tests/mock_tests/mock_orchagent_main.h index 93c1588b9b..850bcb7ed2 100644 --- a/tests/mock_tests/mock_orchagent_main.h +++ b/tests/mock_tests/mock_orchagent_main.h @@ -27,6 +27,7 @@ #include "muxorch.h" #include "nhgorch.h" #include "copporch.h" +#include "twamporch.h" #include "directory.h" extern int gBatchSize; @@ -86,3 +87,4 @@ extern sai_mpls_api_t* sai_mpls_api; extern sai_counter_api_t* sai_counter_api; extern sai_samplepacket_api_t *sai_samplepacket_api; extern sai_fdb_api_t* sai_fdb_api; +extern sai_twamp_api_t* sai_twamp_api; diff --git a/tests/mock_tests/portal.h b/tests/mock_tests/portal.h index df73f65cc0..31fa4ac4b7 100644 --- a/tests/mock_tests/portal.h +++ b/tests/mock_tests/portal.h @@ -7,6 +7,7 @@ #include "crmorch.h" #include "copporch.h" #include "sfloworch.h" +#include "twamporch.h" #include "directory.h" #undef protected @@ -106,6 +107,19 @@ struct Portal } }; + struct TwampOrchInternal + { + static bool getTwampSessionStatus(TwampOrch &obj, const string &name, string& status) + { + return obj.getSessionStatus(name, status); + } + + static TwampStatsTable getTwampSessionStatistics(TwampOrch &obj) + { + return obj.m_twampStatistics; + } + }; + struct DirectoryInternal { template diff --git a/tests/mock_tests/twamporch_ut.cpp b/tests/mock_tests/twamporch_ut.cpp new file mode 100644 index 0000000000..721950e74a --- /dev/null +++ b/tests/mock_tests/twamporch_ut.cpp @@ -0,0 +1,975 @@ +#define private public // make Directory::m_values available to clean it. +#include "directory.h" +#undef private +#define protected public +#include "orch.h" +#undef protected +#include "ut_helper.h" +#include "mock_orchagent_main.h" +#include "mock_table.h" +#include "notifier.h" + +extern string gMySwitchType; + +extern sai_object_id_t gSwitchId; + +extern redisReply *mockReply; + + +namespace twamporch_test +{ + using namespace std; + + int create_twamp_session_count; + int set_twamp_session_count; + int remove_twamp_session_count; + + sai_twamp_api_t ut_sai_twamp_api; + sai_twamp_api_t *pold_sai_twamp_api; + sai_switch_api_t ut_sai_switch_api; + sai_switch_api_t *pold_sai_switch_api; + + sai_create_twamp_session_fn old_create_twamp_session; + sai_remove_twamp_session_fn old_remove_twamp_session; + sai_set_twamp_session_attribute_fn old_set_twamp_session_attribute; + + sai_status_t _ut_stub_sai_create_twamp_session( + _Out_ sai_object_id_t *twamp_session_id, + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list) + { + *twamp_session_id = (sai_object_id_t)(0x1); + create_twamp_session_count++; + return SAI_STATUS_SUCCESS; + } + + sai_status_t _ut_stub_sai_remove_twamp_session( + _In_ sai_object_id_t twamp_session_id) + { + remove_twamp_session_count++; + return SAI_STATUS_SUCCESS; + } + + sai_status_t _ut_stub_sai_set_twamp_session_attribute( + _In_ sai_object_id_t twamp_session_id, + _In_ const sai_attribute_t *attr) + { + set_twamp_session_count++; + if (attr->id == SAI_TWAMP_SESSION_ATTR_SESSION_ENABLE_TRANSMIT) + { + return SAI_STATUS_SUCCESS; + } + return old_set_twamp_session_attribute(twamp_session_id, attr); + } + + sai_status_t _ut_stub_sai_get_switch_attribute( + _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list) + { + if (attr_count == 1) + { + if (attr_list[0].id == SAI_SWITCH_ATTR_MAX_TWAMP_SESSION) + { + attr_list[0].value.u32 = 128; + return SAI_STATUS_SUCCESS; + } + } + return pold_sai_switch_api->get_switch_attribute(switch_id, attr_count, attr_list); + } + + sai_status_t _ut_stub_sai_set_switch_attribute( + _In_ sai_object_id_t switch_id, + _In_ const sai_attribute_t *attr) + { + if (attr[0].id == SAI_SWITCH_ATTR_TWAMP_SESSION_EVENT_NOTIFY) + { + return SAI_STATUS_SUCCESS; + } + return pold_sai_switch_api->set_switch_attribute(switch_id, attr); + } + + void _hook_sai_twamp_api() + { + ut_sai_twamp_api = *sai_twamp_api; + pold_sai_twamp_api = sai_twamp_api; + ut_sai_twamp_api.create_twamp_session = _ut_stub_sai_create_twamp_session; + ut_sai_twamp_api.remove_twamp_session = _ut_stub_sai_remove_twamp_session; + ut_sai_twamp_api.set_twamp_session_attribute = _ut_stub_sai_set_twamp_session_attribute; + sai_twamp_api = &ut_sai_twamp_api; + } + + void _unhook_sai_twamp_api() + { + sai_twamp_api = pold_sai_twamp_api; + } + + void _hook_sai_switch_api() + { + ut_sai_switch_api = *sai_switch_api; + pold_sai_switch_api = sai_switch_api; + ut_sai_switch_api.get_switch_attribute = _ut_stub_sai_get_switch_attribute; + ut_sai_switch_api.set_switch_attribute = _ut_stub_sai_set_switch_attribute; + sai_switch_api = &ut_sai_switch_api; + } + + void _unhook_sai_switch_api() + { + sai_switch_api = pold_sai_switch_api; + } + + class MockTwampOrch final + { + public: + MockTwampOrch() + { + this->confDb = std::make_shared("CONFIG_DB", 0); + TableConnector confDbTwampTable(this->confDb.get(), CFG_TWAMP_SESSION_TABLE_NAME); + TableConnector stateDbTwampTable(this->confDb.get(), STATE_TWAMP_SESSION_TABLE_NAME); + this->twampOrch = std::make_shared(confDbTwampTable, stateDbTwampTable, gSwitchOrch, gPortsOrch, gVrfOrch); + } + ~MockTwampOrch() = default; + + void doTwampTableTask(const std::deque &entries) + { + auto consumer = dynamic_cast((this->twampOrch.get())->getExecutor(CFG_TWAMP_SESSION_TABLE_NAME)); + consumer->addToSync(entries); + static_cast(this->twampOrch.get())->doTask(*consumer); + } + + void doTwampNotificationTask() + { + auto exec = static_cast((this->twampOrch.get())->getExecutor("TWAMP_NOTIFICATIONS")); + auto consumer = exec->getNotificationConsumer(); + consumer->readData(); + static_cast(this->twampOrch.get())->doTask(*consumer); + } + + TwampOrch& get() + { + return *twampOrch; + } + + private: + std::shared_ptr confDb; + std::shared_ptr twampOrch; + }; + + class TwampOrchTest : public ::testing::Test + { + public: + TwampOrchTest() + { + this->initDb(); + } + virtual ~TwampOrchTest() = default; + + void SetUp() override + { + this->initSaiApi(); + this->initSwitch(); + this->initOrch(); + this->initPorts(); + _hook_sai_twamp_api(); + _hook_sai_switch_api(); + } + + void TearDown() override + { + this->deinitOrch(); + this->deinitSwitch(); + this->deinitSaiApi(); + _unhook_sai_twamp_api(); + _unhook_sai_switch_api(); + } + + private: + void initSaiApi() + { + std::map profileMap = { + { "SAI_VS_SWITCH_TYPE", "SAI_VS_SWITCH_TYPE_BCM56850" }, + { "KV_DEVICE_MAC_ADDRESS", "20:03:04:05:06:00" } + }; + auto status = ut_helper::initSaiApi(profileMap); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + } + + void deinitSaiApi() + { + auto status = ut_helper::uninitSaiApi(); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + } + + void initSwitch() + { + sai_status_t status; + sai_attribute_t attr; + + // Create switch + attr.id = SAI_SWITCH_ATTR_INIT_SWITCH; + attr.value.booldata = true; + + status = sai_switch_api->create_switch(&gSwitchId, 1, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + // Get switch source MAC address + attr.id = SAI_SWITCH_ATTR_SRC_MAC_ADDRESS; + + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + gMacAddress = attr.value.mac; + + // Get switch default virtual router ID + attr.id = SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID; + + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + gVirtualRouterId = attr.value.oid; + } + + void deinitSwitch() + { + // Remove switch + auto status = sai_switch_api->remove_switch(gSwitchId); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + gSwitchId = SAI_NULL_OBJECT_ID; + gVirtualRouterId = SAI_NULL_OBJECT_ID; + } + + void initOrch() + { + // + // SwitchOrch + // + TableConnector state_switch_table(this->stateDb.get(), "SWITCH_CAPABILITY"); + TableConnector app_switch_table(this->appDb.get(), APP_SWITCH_TABLE_NAME); + TableConnector conf_asic_sensors(this->configDb.get(), CFG_ASIC_SENSORS_TABLE_NAME); + + std::vector switchTableList = { + conf_asic_sensors, + app_switch_table + }; + + ASSERT_EQ(gSwitchOrch, nullptr); + gSwitchOrch = new SwitchOrch(this->appDb.get(), switchTableList, state_switch_table); + gDirectory.set(gSwitchOrch); + resourcesList.push_back(gSwitchOrch); + + // + // PortsOrch + // + const int portsorch_base_pri = 40; + + vector ports_tables = { + { APP_PORT_TABLE_NAME, portsorch_base_pri + 5 }, + { APP_VLAN_TABLE_NAME, portsorch_base_pri + 2 }, + { APP_VLAN_MEMBER_TABLE_NAME, portsorch_base_pri }, + { APP_LAG_TABLE_NAME, portsorch_base_pri + 4 }, + { APP_LAG_MEMBER_TABLE_NAME, portsorch_base_pri } + }; + + ASSERT_EQ(gPortsOrch, nullptr); + gPortsOrch = new PortsOrch(this->appDb.get(), this->stateDb.get(), ports_tables, this->chassisAppDb.get()); + gDirectory.set(gPortsOrch); + resourcesList.push_back(gPortsOrch); + + // + // VrfOrch + // + ASSERT_EQ(gVrfOrch, nullptr); + gVrfOrch = new VRFOrch(this->appDb.get(), APP_VRF_TABLE_NAME, this->stateDb.get(), STATE_VRF_OBJECT_TABLE_NAME); + resourcesList.push_back(gVrfOrch); + + + // + // BufferOrch + // + std::vector bufferTableList = { + APP_BUFFER_POOL_TABLE_NAME, + APP_BUFFER_PROFILE_TABLE_NAME, + APP_BUFFER_QUEUE_TABLE_NAME, + APP_BUFFER_PG_TABLE_NAME, + APP_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME, + APP_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME + }; + gBufferOrch = new BufferOrch(this->appDb.get(), this->configDb.get(), this->stateDb.get(), bufferTableList); + gDirectory.set(gBufferOrch); + resourcesList.push_back(gBufferOrch); + + // + // FlexCounterOrch + // + std::vector flexCounterTableList = { + CFG_FLEX_COUNTER_TABLE_NAME + }; + + auto flexCounterOrch = new FlexCounterOrch(this->configDb.get(), flexCounterTableList); + gDirectory.set(flexCounterOrch); + resourcesList.push_back(flexCounterOrch); + + // + // CrmOrch + // + ASSERT_EQ(gCrmOrch, nullptr); + gCrmOrch = new CrmOrch(this->configDb.get(), CFG_CRM_TABLE_NAME); + gDirectory.set(gCrmOrch); + resourcesList.push_back(gCrmOrch); + } + + void deinitOrch() + { + std::reverse(resourcesList.begin(), resourcesList.end()); + for (auto &it : resourcesList) + { + delete it; + } + + gSwitchOrch = nullptr; + gPortsOrch = nullptr; + gVrfOrch = nullptr; + gBufferOrch = nullptr; + gCrmOrch = nullptr; + + Portal::DirectoryInternal::clear(gDirectory); + EXPECT_TRUE(Portal::DirectoryInternal::empty(gDirectory)); + } + + void initPorts() + { + auto portTable = Table(this->appDb.get(), APP_PORT_TABLE_NAME); + + // Get SAI default ports to populate DB + auto ports = ut_helper::getInitialSaiPorts(); + + // Populate port table with SAI ports + for (const auto &cit : ports) + { + portTable.set(cit.first, cit.second); + } + + // Set PortConfigDone + portTable.set("PortConfigDone", { { "count", to_string(ports.size()) } }); + gPortsOrch->addExistingData(&portTable); + static_cast(gPortsOrch)->doTask(); + + // Set PortInitDone + portTable.set("PortInitDone", { { "lanes", "0" } }); + gPortsOrch->addExistingData(&portTable); + static_cast(gPortsOrch)->doTask(); + } + + void initDb() + { + this->appDb = std::make_shared("APPL_DB", 0); + this->configDb = std::make_shared("CONFIG_DB", 0); + this->stateDb = std::make_shared("STATE_DB", 0); + this->countersDb = make_shared("COUNTERS_DB", 0); + this->chassisAppDb = make_shared("CHASSIS_APP_DB", 0); + this->asicDb = make_shared("ASIC_DB", 0); + } + + shared_ptr appDb; + shared_ptr configDb; + shared_ptr stateDb; + shared_ptr countersDb; + shared_ptr chassisAppDb; + shared_ptr asicDb; + + std::vector resourcesList; + }; + + TEST_F(TwampOrchTest, TwampOrchTestCreateDeleteSenderPacketCountSingle) + { + string twampSessionName = "TEST_SENDER1"; + + MockTwampOrch twampOrch; + + auto current_create_count = create_twamp_session_count; + auto current_remove_count = remove_twamp_session_count; + auto current_set_count = set_twamp_session_count; + + // Create TWAMP Light session + { + std::deque tableKofvt; + tableKofvt.push_back( + { + twampSessionName, + SET_COMMAND, + { + {"mode", "LIGHT" }, + {"role", "SENDER" }, + {"src_ip", "1.1.1.1" }, + {"src_udp_port", "862" }, + {"dst_ip", "2.2.2.2" }, + {"dst_udp_port", "863" }, + {"packet_count", "1000" }, + {"tx_interval", "10" }, + {"timeout", "10" }, + {"statistics_interval", "20000" }, + {"vrf_name", "default" }, + {"dscp", "0" }, + {"ttl", "10" }, + {"timestamp_format", "ntp" }, + {"padding_size", "100" }, + {"hw_lookup", "true" } + } + } + ); + + twampOrch.doTwampTableTask(tableKofvt); + + string session_status; + ASSERT_TRUE(twampOrch.get().getSessionStatus(twampSessionName, session_status)); + ASSERT_EQ(session_status, "inactive"); + ASSERT_EQ(current_create_count + 1, create_twamp_session_count); + } + + // Start TWAMP Light session + { + std::deque tableKofvt; + tableKofvt.push_back( + { + twampSessionName, + SET_COMMAND, + { + {"admin_state", "enabled"} + } + } + ); + + twampOrch.doTwampTableTask(tableKofvt); + + string session_status; + ASSERT_TRUE(twampOrch.get().getSessionStatus(twampSessionName, session_status)); + ASSERT_EQ(session_status, "active"); + ASSERT_EQ(current_set_count + 1, set_twamp_session_count); + } + + // Process Notification + { + // mock a redis reply for notification + mockReply = (redisReply *)calloc(sizeof(redisReply), 1); + mockReply->type = REDIS_REPLY_ARRAY; + mockReply->elements = 3; // REDIS_PUBLISH_MESSAGE_ELEMNTS + mockReply->element = (redisReply **)calloc(sizeof(redisReply *), mockReply->elements); + mockReply->element[2] = (redisReply *)calloc(sizeof(redisReply), 1); + mockReply->element[2]->type = REDIS_REPLY_STRING; + sai_twamp_session_event_notification_data_t twamp_session_data; + sai_twamp_session_stat_t counters_ids[SAI_TWAMP_SESSION_STAT_DURATION_TS]; + uint64_t counters[SAI_TWAMP_SESSION_STAT_DURATION_TS]; + twamp_session_data.session_state = SAI_TWAMP_SESSION_STATE_INACTIVE; + twamp_session_data.twamp_session_id = (sai_object_id_t)0x1; + twamp_session_data.session_stats.index = 1; + twamp_session_data.session_stats.number_of_counters = 11; + + counters_ids[0] = SAI_TWAMP_SESSION_STAT_RX_PACKETS; + counters_ids[1] = SAI_TWAMP_SESSION_STAT_RX_BYTE; + counters_ids[2] = SAI_TWAMP_SESSION_STAT_TX_PACKETS; + counters_ids[3] = SAI_TWAMP_SESSION_STAT_TX_BYTE; + counters_ids[4] = SAI_TWAMP_SESSION_STAT_DROP_PACKETS; + counters_ids[5] = SAI_TWAMP_SESSION_STAT_MAX_LATENCY; + counters_ids[6] = SAI_TWAMP_SESSION_STAT_MIN_LATENCY; + counters_ids[7] = SAI_TWAMP_SESSION_STAT_AVG_LATENCY; + counters_ids[8] = SAI_TWAMP_SESSION_STAT_MAX_JITTER; + counters_ids[9] = SAI_TWAMP_SESSION_STAT_MIN_JITTER; + counters_ids[10] = SAI_TWAMP_SESSION_STAT_AVG_JITTER; + counters[0] = 1000; + counters[1] = 100000; + counters[2] = 1000; + counters[3] = 100000; + counters[4] = 0; + counters[5] = 1987; + counters[6] = 1983; + counters[7] = 1984; + counters[8] = 2097; + counters[9] = 1896; + counters[10] = 1985; + twamp_session_data.session_stats.counters_ids = counters_ids; + twamp_session_data.session_stats.counters = counters; + + std::string data = sai_serialize_twamp_session_event_ntf(1, &twamp_session_data); + + std::vector notifyValues; + FieldValueTuple opdata("twamp_session_event", data); + notifyValues.push_back(opdata); + std::string msg = swss::JSon::buildJson(notifyValues); + mockReply->element[2]->str = (char*)calloc(1, msg.length() + 1); + memcpy(mockReply->element[2]->str, msg.c_str(), msg.length()); + + // trigger the notification + twampOrch.doTwampNotificationTask(); + mockReply = nullptr; + + TwampStatsTable twampStatistics = Portal::TwampOrchInternal::getTwampSessionStatistics(twampOrch.get()); + ASSERT_TRUE(twampStatistics.find(twampSessionName) != twampStatistics.end()); + ASSERT_EQ(twampStatistics[twampSessionName].rx_packets, 1000); + ASSERT_EQ(twampStatistics[twampSessionName].rx_bytes, 100000); + ASSERT_EQ(twampStatistics[twampSessionName].tx_packets, 1000); + ASSERT_EQ(twampStatistics[twampSessionName].tx_bytes, 100000); + ASSERT_EQ(twampStatistics[twampSessionName].drop_packets, 0); + ASSERT_EQ(twampStatistics[twampSessionName].max_latency, 1987); + ASSERT_EQ(twampStatistics[twampSessionName].min_latency, 1983); + ASSERT_EQ(twampStatistics[twampSessionName].avg_latency, 1984); + ASSERT_EQ(twampStatistics[twampSessionName].max_jitter, 2097); + ASSERT_EQ(twampStatistics[twampSessionName].min_jitter, 1896); + ASSERT_EQ(twampStatistics[twampSessionName].avg_jitter, 1985); + } + + // Delete TWAMP Light session + { + std::deque tableKofvt; + tableKofvt.push_back( + { + twampSessionName, + DEL_COMMAND, + { {} } + } + ); + + twampOrch.doTwampTableTask(tableKofvt); + + string session_status; + ASSERT_FALSE(twampOrch.get().getSessionStatus(twampSessionName, session_status)); + ASSERT_EQ(current_remove_count + 1, remove_twamp_session_count); + } + + // Make sure both create and set has been called + ASSERT_EQ(current_create_count + 1, create_twamp_session_count); + ASSERT_EQ(current_remove_count + 1, remove_twamp_session_count); + ASSERT_EQ(current_set_count + 1, set_twamp_session_count); + } + + TEST_F(TwampOrchTest, TwampOrchTestCreateDeleteSenderPacketCountMulti) + { + string twampSessionName = "TEST_SENDER1"; + + MockTwampOrch twampOrch; + + auto current_create_count = create_twamp_session_count; + auto current_remove_count = remove_twamp_session_count; + auto current_set_count = set_twamp_session_count; + + // Create TWAMP Light session + { + std::deque tableKofvt; + tableKofvt.push_back( + { + twampSessionName, + SET_COMMAND, + { + {"mode", "LIGHT" }, + {"role", "SENDER" }, + {"src_ip", "1.1.1.1" }, + {"src_udp_port", "1862" }, + {"dst_ip", "2.2.2.2" }, + {"dst_udp_port", "1863" }, + {"packet_count", "1000" }, + {"tx_interval", "10" }, + {"timeout", "10" }, + {"statistics_interval", "11000" } + } + } + ); + + twampOrch.doTwampTableTask(tableKofvt); + + string session_status; + ASSERT_TRUE(twampOrch.get().getSessionStatus(twampSessionName, session_status)); + ASSERT_EQ(session_status, "inactive"); + ASSERT_EQ(current_create_count + 1, create_twamp_session_count); + } + + // Start TWAMP Light session + { + std::deque tableKofvt; + tableKofvt.push_back( + { + twampSessionName, + SET_COMMAND, + { + {"admin_state", "enabled"} + } + } + ); + + twampOrch.doTwampTableTask(tableKofvt); + + string session_status; + ASSERT_TRUE(twampOrch.get().getSessionStatus(twampSessionName, session_status)); + ASSERT_EQ(session_status, "active"); + ASSERT_EQ(current_set_count + 1, set_twamp_session_count); + } + + // Process Notification + { + sai_twamp_session_event_notification_data_t twamp_session_data; + sai_twamp_session_stat_t counters_ids[SAI_TWAMP_SESSION_STAT_DURATION_TS]; + uint64_t counters[SAI_TWAMP_SESSION_STAT_DURATION_TS]; + uint64_t latency_total = 0; + uint64_t jitter_total = 0; + twamp_session_data.twamp_session_id = (sai_object_id_t)0x1; + twamp_session_data.session_stats.number_of_counters = 11; + counters_ids[0] = SAI_TWAMP_SESSION_STAT_RX_PACKETS; + counters_ids[1] = SAI_TWAMP_SESSION_STAT_RX_BYTE; + counters_ids[2] = SAI_TWAMP_SESSION_STAT_TX_PACKETS; + counters_ids[3] = SAI_TWAMP_SESSION_STAT_TX_BYTE; + counters_ids[4] = SAI_TWAMP_SESSION_STAT_DROP_PACKETS; + counters_ids[5] = SAI_TWAMP_SESSION_STAT_MAX_LATENCY; + counters_ids[6] = SAI_TWAMP_SESSION_STAT_MIN_LATENCY; + counters_ids[7] = SAI_TWAMP_SESSION_STAT_AVG_LATENCY; + counters_ids[8] = SAI_TWAMP_SESSION_STAT_MAX_JITTER; + counters_ids[9] = SAI_TWAMP_SESSION_STAT_MIN_JITTER; + counters_ids[10] = SAI_TWAMP_SESSION_STAT_AVG_JITTER; + twamp_session_data.session_stats.counters_ids = counters_ids; + twamp_session_data.session_stats.counters = counters; + for (uint8_t i = 1; i <= 10; i++) + { + // mock a redis reply for notification + mockReply = (redisReply *)calloc(sizeof(redisReply), 1); + mockReply->type = REDIS_REPLY_ARRAY; + mockReply->elements = 3; // REDIS_PUBLISH_MESSAGE_ELEMNTS + mockReply->element = (redisReply **)calloc(sizeof(redisReply *), mockReply->elements); + mockReply->element[2] = (redisReply *)calloc(sizeof(redisReply), 1); + mockReply->element[2]->type = REDIS_REPLY_STRING; + + twamp_session_data.session_state = (i<10) ? SAI_TWAMP_SESSION_STATE_ACTIVE : SAI_TWAMP_SESSION_STATE_INACTIVE; + twamp_session_data.session_stats.index = i; + counters[0] = 100; + counters[1] = 10000; + counters[2] = 100; + counters[3] = 10000; + counters[4] = 0; + counters[5] = 1000+i; + counters[6] = 1000+i; + counters[7] = 1000+i; + counters[8] = 1100+i; + counters[9] = 1100+i; + counters[10] = 1100+i; + latency_total += counters[7]; + jitter_total += counters[10]; + + std::string data = sai_serialize_twamp_session_event_ntf(1, &twamp_session_data); + + std::vector notifyValues; + FieldValueTuple opdata("twamp_session_event", data); + notifyValues.push_back(opdata); + std::string msg = swss::JSon::buildJson(notifyValues); + mockReply->element[2]->str = (char*)calloc(1, msg.length() + 1); + memcpy(mockReply->element[2]->str, msg.c_str(), msg.length()); + + // trigger the notification + twampOrch.doTwampNotificationTask(); + mockReply = nullptr; + + string session_status; + ASSERT_TRUE(twampOrch.get().getSessionStatus(twampSessionName, session_status)); + if (i<10) + { + ASSERT_EQ(session_status, "active"); + } + else + { + ASSERT_EQ(session_status, "inactive"); + } + + TwampStatsTable twampStatistics = Portal::TwampOrchInternal::getTwampSessionStatistics(twampOrch.get()); + ASSERT_TRUE(twampStatistics.find(twampSessionName) != twampStatistics.end()); + ASSERT_EQ(twampStatistics[twampSessionName].rx_packets, 100*i); + ASSERT_EQ(twampStatistics[twampSessionName].rx_bytes, 10000*i); + ASSERT_EQ(twampStatistics[twampSessionName].tx_packets, 100*i); + ASSERT_EQ(twampStatistics[twampSessionName].tx_bytes, 10000*i); + ASSERT_EQ(twampStatistics[twampSessionName].drop_packets, 0); + ASSERT_EQ(twampStatistics[twampSessionName].max_latency, 1000+i); + ASSERT_EQ(twampStatistics[twampSessionName].min_latency, 1000+1); + ASSERT_EQ(twampStatistics[twampSessionName].avg_latency, latency_total/i); + ASSERT_EQ(twampStatistics[twampSessionName].max_jitter, 1100+i); + ASSERT_EQ(twampStatistics[twampSessionName].min_jitter, 1100+1); + ASSERT_EQ(twampStatistics[twampSessionName].avg_jitter, jitter_total/i); + } + } + + // Delete TWAMP Light session + { + std::deque tableKofvt; + tableKofvt.push_back( + { + twampSessionName, + DEL_COMMAND, + { {} } + } + ); + + twampOrch.doTwampTableTask(tableKofvt); + + string session_status; + ASSERT_FALSE(twampOrch.get().getSessionStatus(twampSessionName, session_status)); + ASSERT_EQ(current_remove_count + 1, remove_twamp_session_count); + } + + // Make sure both create and set has been called + ASSERT_EQ(current_create_count + 1, create_twamp_session_count); + ASSERT_EQ(current_remove_count + 1, remove_twamp_session_count); + ASSERT_EQ(current_set_count + 1, set_twamp_session_count); + } + + TEST_F(TwampOrchTest, TwampOrchTestCreateDeleteSenderContinuousSingle) + { + string twampSessionName = "TEST_SENDER1"; + + MockTwampOrch twampOrch; + + auto current_create_count = create_twamp_session_count; + auto current_remove_count = remove_twamp_session_count; + auto current_set_count = set_twamp_session_count; + + // Create TWAMP Light session + { + std::deque tableKofvt; + tableKofvt.push_back( + { + twampSessionName, + SET_COMMAND, + { + {"mode", "LIGHT" }, + {"role", "SENDER" }, + {"src_ip", "1.1.1.1" }, + {"src_udp_port", "862" }, + {"dst_ip", "2.2.2.2" }, + {"dst_udp_port", "863" }, + {"monitor_time", "60" }, + {"tx_interval", "100" }, + {"timeout", "10" }, + {"statistics_interval", "60000" }, + {"vrf_name", "default" }, + {"dscp", "0" }, + {"ttl", "10" }, + {"timestamp_format", "ntp" }, + {"padding_size", "100" }, + {"hw_lookup", "true" } + } + } + ); + + twampOrch.doTwampTableTask(tableKofvt); + + string session_status; + ASSERT_TRUE(twampOrch.get().getSessionStatus(twampSessionName, session_status)); + ASSERT_EQ(session_status, "inactive"); + ASSERT_EQ(current_create_count + 1, create_twamp_session_count); + } + + // Start TWAMP Light session + { + std::deque tableKofvt; + tableKofvt.push_back( + { + twampSessionName, + SET_COMMAND, + { + {"admin_state", "enabled"} + } + } + ); + + twampOrch.doTwampTableTask(tableKofvt); + + string session_status; + ASSERT_TRUE(twampOrch.get().getSessionStatus(twampSessionName, session_status)); + ASSERT_EQ(session_status, "active"); + ASSERT_EQ(current_set_count + 1, set_twamp_session_count); + } + + // Delete TWAMP Light session + { + std::deque tableKofvt; + tableKofvt.push_back( + { + twampSessionName, + DEL_COMMAND, + { {} } + } + ); + + twampOrch.doTwampTableTask(tableKofvt); + + string session_status; + ASSERT_FALSE(twampOrch.get().getSessionStatus(twampSessionName, session_status)); + ASSERT_EQ(current_remove_count + 1, remove_twamp_session_count); + } + + // Make sure both create and set has been called + ASSERT_EQ(current_create_count + 1, create_twamp_session_count); + ASSERT_EQ(current_remove_count + 1, remove_twamp_session_count); + ASSERT_EQ(current_set_count + 1, set_twamp_session_count); + } + + TEST_F(TwampOrchTest, TwampOrchTestCreateDeleteSenderContinuousMulti) + { + string twampSessionName = "TEST_SENDER1"; + + MockTwampOrch twampOrch; + + auto current_create_count = create_twamp_session_count; + auto current_remove_count = remove_twamp_session_count; + auto current_set_count = set_twamp_session_count; + + // Create TWAMP Light session + { + std::deque tableKofvt; + tableKofvt.push_back( + { + twampSessionName, + SET_COMMAND, + { + {"mode", "LIGHT" }, + {"role", "SENDER" }, + {"src_ip", "1.1.1.1" }, + {"src_udp_port", "1862" }, + {"dst_ip", "2.2.2.2" }, + {"dst_udp_port", "1863" }, + {"monitor_time", "0" }, + {"tx_interval", "100" }, + {"timeout", "10" }, + {"statistics_interval", "20000" }, + } + } + ); + + twampOrch.doTwampTableTask(tableKofvt); + + string session_status; + ASSERT_TRUE(twampOrch.get().getSessionStatus(twampSessionName, session_status)); + ASSERT_EQ(session_status, "inactive"); + ASSERT_EQ(current_create_count + 1, create_twamp_session_count); + } + + // Start TWAMP Light session + { + std::deque tableKofvt; + tableKofvt.push_back( + { + twampSessionName, + SET_COMMAND, + { + {"admin_state", "enabled"} + } + } + ); + + twampOrch.doTwampTableTask(tableKofvt); + + string session_status; + ASSERT_TRUE(twampOrch.get().getSessionStatus(twampSessionName, session_status)); + ASSERT_EQ(session_status, "active"); + ASSERT_EQ(current_set_count + 1, set_twamp_session_count); + } + + // Stop TWAMP Light session + { + std::deque tableKofvt; + tableKofvt.push_back( + { + twampSessionName, + SET_COMMAND, + { + {"admin_state", "disabled"} + } + } + ); + + twampOrch.doTwampTableTask(tableKofvt); + + string session_status; + ASSERT_TRUE(twampOrch.get().getSessionStatus(twampSessionName, session_status)); + ASSERT_EQ(session_status, "inactive"); + ASSERT_EQ(current_set_count + 2, set_twamp_session_count); + } + + // Delete TWAMP Light session + { + std::deque tableKofvt; + tableKofvt.push_back( + { + twampSessionName, + DEL_COMMAND, + { {} } + } + ); + + twampOrch.doTwampTableTask(tableKofvt); + + string session_status; + ASSERT_FALSE(twampOrch.get().getSessionStatus(twampSessionName, session_status)); + ASSERT_EQ(current_remove_count + 1, remove_twamp_session_count); + } + + // Make sure both create and set has been called + ASSERT_EQ(current_create_count + 1, create_twamp_session_count); + ASSERT_EQ(current_remove_count + 1, remove_twamp_session_count); + ASSERT_EQ(current_set_count + 2, set_twamp_session_count); + } + + TEST_F(TwampOrchTest, TwampOrchTestCreateDeleteReflector) + { + string twampSessionName = "TEST_SENDER1"; + + MockTwampOrch twampOrch; + + auto current_create_count = create_twamp_session_count; + auto current_remove_count = remove_twamp_session_count; + auto current_set_count = set_twamp_session_count; + + // Create TWAMP Light session + { + std::deque tableKofvt; + tableKofvt.push_back( + { + twampSessionName, + SET_COMMAND, + { + {"mode", "LIGHT"}, + {"role", "REFLECTOR"}, + {"src_ip", "1.1.1.1"}, + {"src_udp_port", "862"}, + {"dst_ip", "2.2.2.2"}, + {"dst_udp_port", "863"} + } + } + ); + + twampOrch.doTwampTableTask(tableKofvt); + + string session_status; + ASSERT_TRUE(twampOrch.get().getSessionStatus(twampSessionName, session_status)); + ASSERT_EQ(session_status, "active"); + ASSERT_EQ(current_create_count + 1, create_twamp_session_count); + } + + // Delete TWAMP Light session + { + std::deque tableKofvt; + tableKofvt.push_back( + { + twampSessionName, + DEL_COMMAND, + { {} } + } + ); + + twampOrch.doTwampTableTask(tableKofvt); + + string session_status; + ASSERT_FALSE(twampOrch.get().getSessionStatus(twampSessionName, session_status)); + ASSERT_EQ(current_remove_count + 1, remove_twamp_session_count); + } + + // Make sure both create and set has been called + ASSERT_EQ(current_create_count + 1, create_twamp_session_count); + ASSERT_EQ(current_remove_count + 1, remove_twamp_session_count); + ASSERT_EQ(current_set_count, set_twamp_session_count); + } +} \ No newline at end of file diff --git a/tests/mock_tests/ut_saihelper.cpp b/tests/mock_tests/ut_saihelper.cpp index 8b6b35b6f7..c9bed67691 100644 --- a/tests/mock_tests/ut_saihelper.cpp +++ b/tests/mock_tests/ut_saihelper.cpp @@ -89,6 +89,7 @@ namespace ut_helper sai_api_query(SAI_API_MPLS, (void**)&sai_mpls_api); sai_api_query(SAI_API_COUNTER, (void**)&sai_counter_api); sai_api_query(SAI_API_FDB, (void**)&sai_fdb_api); + sai_api_query(SAI_API_TWAMP, (void**)&sai_twamp_api); return SAI_STATUS_SUCCESS; } @@ -118,6 +119,7 @@ namespace ut_helper sai_buffer_api = nullptr; sai_queue_api = nullptr; sai_counter_api = nullptr; + sai_twamp_api = nullptr; return SAI_STATUS_SUCCESS; } diff --git a/tests/test_twamp.py b/tests/test_twamp.py new file mode 100644 index 0000000000..d2d8edb8f0 --- /dev/null +++ b/tests/test_twamp.py @@ -0,0 +1,182 @@ +# This test suite covers the functionality of twamp light feature in SwSS +import pytest +import time + +@pytest.mark.usefixtures("testlog") +@pytest.mark.usefixtures('dvs_twamp_manager') +class TestTwampLight(object): + + def check_syslog(self, dvs, marker, log, expected_cnt): + (ec, out) = dvs.runcmd(['sh', '-c', "awk \'/%s/,ENDFILE {print;}\' /var/log/syslog | grep \'%s\' | wc -l" % (marker, log)]) + assert out.strip() == str(expected_cnt) + + def test_SenderPacketCountSingle(self, dvs, testlog): + """ + This test covers the TWAMP Light session creation and removal operations + Operation flow: + 1. Create twamp-light session-sender using once packet-count + The session remains inactive + 2. Start twamp-light session + The session becomes active + 3. Remove twamp-light session + """ + + session = "TEST_SENDER1" + src_ip = "1.1.1.1" + src_udp_port = "862" + dst_ip = "2.2.2.2" + dst_udp_port = "863" + packet_count = "1000" + tx_interval = "10" + timeout = "10" + stats_interval = "20000" + + marker = dvs.add_log_marker() + + # create twamp-light session + self.dvs_twamp.create_twamp_light_session_sender_packet_count(session, src_ip, src_udp_port, dst_ip, dst_udp_port, packet_count, tx_interval, timeout) + + # start twamp-light session + self.dvs_twamp.start_twamp_light_sender(session) + + # wait for sending TWAMP-test done + time.sleep(12) + + # remove twamp-light session + self.dvs_twamp.remove_twamp_light_session(session) + self.dvs_twamp.verify_no_session() + + def test_SenderPacketCountMulti(self, dvs, testlog): + """ + This test covers the TWAMP Light Sender session creation and removal operations + Operation flow: + 1. Create twamp-light session-sender using multi packet-count + The session remains inactive + 2. Start twamp-light session + The session becomes active + 3. Remove twamp-light session + """ + + session = "TEST_SENDER1" + src_ip = "1.2.3.4" + src_udp_port = "862" + dst_ip = "5.6.7.8" + dst_udp_port = "863" + packet_count = "1000" + tx_interval = "10" + timeout = "10" + stats_interval = "11000" + + marker = dvs.add_log_marker() + + # create twamp-light session + self.dvs_twamp.create_twamp_light_session_sender_packet_count(session, src_ip, src_udp_port, dst_ip, dst_udp_port, packet_count, tx_interval, timeout, stats_interval) + + # start twamp-light session + self.dvs_twamp.start_twamp_light_sender(session) + + # wait for sending TWAMP-test done + time.sleep(120) + + # remove twamp-light session + self.dvs_twamp.remove_twamp_light_session(session) + self.dvs_twamp.verify_no_session() + + def test_SenderContinuousSingle(self, dvs, testlog): + """ + This test covers the TWAMP Light Sender session creation and removal operations + Operation flow: + 1. Create twamp-light session-sender using once continuous + The session remains inactive + 2. Start twamp-light session + The session becomes active + 3. Remove twamp-light session + """ + + session = "TEST_SENDER2" + src_ip = "11.11.11.11" + src_udp_port = "862" + dst_ip = "12.12.12.12" + dst_udp_port = "863" + monitor_time = "60" + tx_interval = "100" + timeout = "10" + stats_interval = "60000" + + marker = dvs.add_log_marker() + + # create twamp-light session + self.dvs_twamp.create_twamp_light_session_sender_continuous(session, src_ip, src_udp_port, dst_ip, dst_udp_port, monitor_time, tx_interval, timeout) + + # start twamp-light session + self.dvs_twamp.start_twamp_light_sender(session) + # wait for sending TWAMP-test done + time.sleep(60) + + # remove twamp-light session + self.dvs_twamp.remove_twamp_light_session(session) + self.dvs_twamp.verify_no_session() + + def test_SenderContinuousMulti(self, dvs, testlog): + """ + This test covers the continuous TWAMP Light Sender session creation and removal operations + Operation flow: + 1. Create twamp-light session-sender using multi continuous + The session remains inactive + 2. Start twamp-light session + The session becomes active + 3. Remove twamp-light session + """ + + session = "TEST_SENDER2" + src_ip = "11.12.13.14" + src_udp_port = "862" + dst_ip = "15.16.17.18" + dst_udp_port = "863" + monitor_time = "60" + tx_interval = "100" + timeout = "10" + stats_interval = "20000" + + marker = dvs.add_log_marker() + + # create twamp-light session + self.dvs_twamp.create_twamp_light_session_sender_continuous(session, src_ip, src_udp_port, dst_ip, dst_udp_port, monitor_time, tx_interval, timeout, stats_interval) + + # start twamp-light session + self.dvs_twamp.start_twamp_light_sender(session) + + # wait for sending TWAMP-test done + time.sleep(60) + + # remove twamp-light session + self.dvs_twamp.remove_twamp_light_session(session) + self.dvs_twamp.verify_no_session() + + def test_Reflector(self, dvs, testlog): + """ + This test covers the TWAMP Light Reflector session creation and removal operations + Operation flow: + 1. Create twamp-light session-reflector + 2. Remove twamp-light session + """ + + session = "TEST_REFLECTOR1" + src_ip = "22.1.1.1" + src_udp_port = "862" + dst_ip = "22.1.1.2" + dst_udp_port = "863" + + marker = dvs.add_log_marker() + + # create twamp-light session + self.dvs_twamp.create_twamp_light_session_reflector(session, src_ip, src_udp_port, dst_ip, dst_udp_port) + + # remove twamp-light session + self.dvs_twamp.remove_twamp_light_session(session) + self.dvs_twamp.verify_no_session() + +# Add Dummy always-pass test at end as workaroud +# for issue when Flaky fail on final test it invokes module tear-down before retrying +def test_nonflaky_dummy(): + pass From dc9eae87f19e8361255a831a6f561c1d860242db Mon Sep 17 00:00:00 2001 From: mint570 <70396898+mint570@users.noreply.github.com> Date: Mon, 1 Apr 2024 13:51:15 -0700 Subject: [PATCH 05/34] Clang format change. (#3080) What I did This PR has no real code change. It is purely clang formatting. It only applies to the P4Orch codes. Commands that I run: find orchagent/p4orch -name *.h -o -name .cpp | xargs clang-format -i -style="{BasedOnStyle: Microsoft, DerivePointerAlignment: false}" find orchagent -name response_publisher -o -name return_code.h | xargs clang-format -i -style="{BasedOnStyle: Microsoft, DerivePointerAlignment: false}" --- orchagent/p4orch/acl_rule_manager.cpp | 5 +- orchagent/p4orch/acl_rule_manager.h | 3 +- orchagent/p4orch/acl_table_manager.cpp | 5 +- orchagent/p4orch/acl_table_manager.h | 3 +- orchagent/p4orch/acl_util.cpp | 2 +- orchagent/p4orch/acl_util.h | 2 +- orchagent/p4orch/ext_tables_manager.cpp | 373 ++++++++---------- orchagent/p4orch/ext_tables_manager.h | 24 +- orchagent/p4orch/gre_tunnel_manager.cpp | 5 +- orchagent/p4orch/gre_tunnel_manager.h | 3 +- orchagent/p4orch/l3_admit_manager.cpp | 5 +- orchagent/p4orch/l3_admit_manager.h | 3 +- orchagent/p4orch/mirror_session_manager.cpp | 9 +- orchagent/p4orch/mirror_session_manager.h | 3 +- orchagent/p4orch/neighbor_manager.cpp | 12 +- orchagent/p4orch/neighbor_manager.h | 3 +- orchagent/p4orch/next_hop_manager.cpp | 9 +- orchagent/p4orch/next_hop_manager.h | 3 +- orchagent/p4orch/object_manager_interface.h | 3 +- orchagent/p4orch/p4orch.cpp | 8 +- orchagent/p4orch/p4orch.h | 24 +- orchagent/p4orch/p4orch_util.cpp | 6 +- orchagent/p4orch/p4orch_util.h | 51 ++- orchagent/p4orch/route_manager.cpp | 5 +- orchagent/p4orch/route_manager.h | 3 +- orchagent/p4orch/router_interface_manager.cpp | 12 +- orchagent/p4orch/router_interface_manager.h | 3 +- .../p4orch/tables_definition_manager.cpp | 122 +++--- orchagent/p4orch/tables_definition_manager.h | 15 +- orchagent/p4orch/tests/acl_manager_test.cpp | 2 +- .../p4orch/tests/fake_flexcounterorch.cpp | 10 +- orchagent/p4orch/tests/fake_portorch.cpp | 14 +- .../p4orch/tests/gre_tunnel_manager_test.cpp | 2 +- .../p4orch/tests/l3_admit_manager_test.cpp | 2 +- .../tests/mirror_session_manager_test.cpp | 2 +- .../p4orch/tests/neighbor_manager_test.cpp | 2 +- .../p4orch/tests/next_hop_manager_test.cpp | 2 +- orchagent/p4orch/tests/route_manager_test.cpp | 2 +- orchagent/p4orch/tests/test_main.cpp | 3 +- orchagent/p4orch/tests/wcmp_manager_test.cpp | 2 +- orchagent/p4orch/wcmp_manager.cpp | 9 +- orchagent/p4orch/wcmp_manager.h | 3 +- orchagent/response_publisher.cpp | 9 +- orchagent/response_publisher.h | 6 +- 44 files changed, 377 insertions(+), 417 deletions(-) diff --git a/orchagent/p4orch/acl_rule_manager.cpp b/orchagent/p4orch/acl_rule_manager.cpp index 40f20ba051..7989bfa9e6 100644 --- a/orchagent/p4orch/acl_rule_manager.cpp +++ b/orchagent/p4orch/acl_rule_manager.cpp @@ -9,7 +9,6 @@ #include "crmorch.h" #include "dbconnector.h" #include "intfsorch.h" -#include #include "logger.h" #include "orch.h" #include "p4orch.h" @@ -18,6 +17,7 @@ #include "sai_serialize.h" #include "table.h" #include "tokenize.h" +#include extern "C" { #include "sai.h" @@ -165,7 +165,8 @@ std::vector getMeterSaiAttrs(const P4AclMeter &p4_acl_meter) } // namespace -ReturnCode AclRuleManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) +ReturnCode AclRuleManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) { return StatusCode::SWSS_RC_UNIMPLEMENTED; } diff --git a/orchagent/p4orch/acl_rule_manager.h b/orchagent/p4orch/acl_rule_manager.h index 230f226f98..1e65ef7c8d 100644 --- a/orchagent/p4orch/acl_rule_manager.h +++ b/orchagent/p4orch/acl_rule_manager.h @@ -44,7 +44,8 @@ class AclRuleManager : public ObjectManagerInterface void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; void drain() override; std::string verifyState(const std::string &key, const std::vector &tuple) override; - ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; // Update counters stats for every rule in each ACL table in COUNTERS_DB, if // counters are enabled in rules. diff --git a/orchagent/p4orch/acl_table_manager.cpp b/orchagent/p4orch/acl_table_manager.cpp index 416120fa5d..abfedbda0c 100644 --- a/orchagent/p4orch/acl_table_manager.cpp +++ b/orchagent/p4orch/acl_table_manager.cpp @@ -7,7 +7,6 @@ #include "SaiAttributeList.h" #include "crmorch.h" #include "dbconnector.h" -#include #include "logger.h" #include "orch.h" #include "p4orch.h" @@ -16,6 +15,7 @@ #include "switchorch.h" #include "table.h" #include "tokenize.h" +#include extern "C" { #include "sai.h" @@ -205,7 +205,8 @@ ReturnCodeOr> AclTableManager::getUdfSaiAttrs(const return udf_attrs; } -ReturnCode AclTableManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) +ReturnCode AclTableManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) { return StatusCode::SWSS_RC_UNIMPLEMENTED; } diff --git a/orchagent/p4orch/acl_table_manager.h b/orchagent/p4orch/acl_table_manager.h index 5ebaf459e9..68cc1c9920 100644 --- a/orchagent/p4orch/acl_table_manager.h +++ b/orchagent/p4orch/acl_table_manager.h @@ -34,7 +34,8 @@ class AclTableManager : public ObjectManagerInterface void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; void drain() override; std::string verifyState(const std::string &key, const std::vector &tuple) override; - ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; // Get ACL table definition by table name in cache. Return nullptr if not // found. diff --git a/orchagent/p4orch/acl_util.cpp b/orchagent/p4orch/acl_util.cpp index 0ef81a07e3..ad943e6ee9 100644 --- a/orchagent/p4orch/acl_util.cpp +++ b/orchagent/p4orch/acl_util.cpp @@ -1,11 +1,11 @@ #include "p4orch/acl_util.h" #include "converter.h" -#include #include "logger.h" #include "sai_serialize.h" #include "table.h" #include "tokenize.h" +#include namespace p4orch { diff --git a/orchagent/p4orch/acl_util.h b/orchagent/p4orch/acl_util.h index 8810843fd6..37522fd164 100644 --- a/orchagent/p4orch/acl_util.h +++ b/orchagent/p4orch/acl_util.h @@ -5,9 +5,9 @@ #include #include -#include #include "p4orch/p4orch_util.h" #include "return_code.h" +#include extern "C" { #include "sai.h" diff --git a/orchagent/p4orch/ext_tables_manager.cpp b/orchagent/p4orch/ext_tables_manager.cpp index 8b5ded6d7f..09bf7ccbe4 100644 --- a/orchagent/p4orch/ext_tables_manager.cpp +++ b/orchagent/p4orch/ext_tables_manager.cpp @@ -1,22 +1,22 @@ #include "p4orch/ext_tables_manager.h" +#include #include #include #include #include #include -#include +#include "crmorch.h" #include "directory.h" -#include #include "logger.h" -#include "tokenize.h" #include "orch.h" -#include "crmorch.h" #include "p4orch/p4orch.h" #include "p4orch/p4orch_util.h" +#include "tokenize.h" +#include -extern sai_counter_api_t* sai_counter_api; +extern sai_counter_api_t *sai_counter_api; extern sai_generic_programmable_api_t *sai_generic_programmable_api; extern Directory gDirectory; @@ -43,10 +43,10 @@ std::string getCrossRefTableName(const std::string table_name) auto it = FixedTablesMap.find(table_name); if (it != FixedTablesMap.end()) { - return(it->second); + return (it->second); } - return(table_name); + return (table_name); } ReturnCode ExtTablesManager::validateActionParamsCrossRef(P4ExtTableAppDbEntry &app_db_entry, ActionInfo *action) @@ -55,8 +55,7 @@ ReturnCode ExtTablesManager::validateActionParamsCrossRef(P4ExtTableAppDbEntry & std::unordered_map cross_ref_key_j; ReturnCode status; - for (auto param_defn_it = action->params.begin(); - param_defn_it != action->params.end(); param_defn_it++) + for (auto param_defn_it = action->params.begin(); param_defn_it != action->params.end(); param_defn_it++) { ActionParamInfo action_param_defn = param_defn_it->second; if (action_param_defn.table_reference_map.empty()) @@ -71,24 +70,24 @@ ReturnCode ExtTablesManager::validateActionParamsCrossRef(P4ExtTableAppDbEntry & { SWSS_LOG_ERROR("Required param not specified for action %s\n", action_name.c_str()); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Required param not specified for action %s " << action_name.c_str(); + << "Required param not specified for action %s " << action_name.c_str(); } for (auto cross_ref_it = action_param_defn.table_reference_map.begin(); - cross_ref_it != action_param_defn.table_reference_map.end(); cross_ref_it++) + cross_ref_it != action_param_defn.table_reference_map.end(); cross_ref_it++) { - cross_ref_key_j[cross_ref_it->first].push_back(nlohmann::json::object_t::value_type(prependMatchField(cross_ref_it->second), app_db_param_it->second)); + cross_ref_key_j[cross_ref_it->first].push_back( + nlohmann::json::object_t::value_type(prependMatchField(cross_ref_it->second), app_db_param_it->second)); } } - for (auto it = cross_ref_key_j.begin(); it != cross_ref_key_j.end(); it++) { const std::string table_name = getCrossRefTableName(it->first); const std::string table_key = it->second.dump(); std::string key; sai_object_type_t object_type; - sai_object_id_t oid; + sai_object_id_t oid; DepObject dep_object = {}; if (gP4Orch->m_p4TableToManagerMap.find(table_name) != gP4Orch->m_p4TableToManagerMap.end()) @@ -98,10 +97,10 @@ ReturnCode ExtTablesManager::validateActionParamsCrossRef(P4ExtTableAppDbEntry & { SWSS_LOG_ERROR("Cross-table reference validation failed from fixed-table %s", table_name.c_str()); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Cross-table reference valdiation failed from fixed-table"; + << "Cross-table reference valdiation failed from fixed-table"; } } - else + else { if (getTableInfo(table_name)) { @@ -109,16 +108,18 @@ ReturnCode ExtTablesManager::validateActionParamsCrossRef(P4ExtTableAppDbEntry & status = getSaiObject(ext_table_key, object_type, key); if (!status.ok()) { - SWSS_LOG_ERROR("Cross-table reference validation failed from extension-table %s", table_name.c_str()); + SWSS_LOG_ERROR("Cross-table reference validation failed from extension-table %s", + table_name.c_str()); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Cross-table reference valdiation failed from extension table"; + << "Cross-table reference valdiation failed from extension table"; } } else { - SWSS_LOG_ERROR("Cross-table reference validation failed due to non-existent table %s", table_name.c_str()); + SWSS_LOG_ERROR("Cross-table reference validation failed due to non-existent table %s", + table_name.c_str()); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Cross-table reference valdiation failed due to non-existent table"; + << "Cross-table reference valdiation failed due to non-existent table"; } } @@ -126,19 +127,19 @@ ReturnCode ExtTablesManager::validateActionParamsCrossRef(P4ExtTableAppDbEntry & { SWSS_LOG_ERROR("Cross-table reference validation failed, no OID found from table %s", table_name.c_str()); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Cross-table reference valdiation failed, no OID found"; + << "Cross-table reference valdiation failed, no OID found"; } if (oid == SAI_NULL_OBJECT_ID) { - SWSS_LOG_ERROR("Cross-table reference validation failed, null OID expected from table %s", table_name.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Cross-table reference valdiation failed, null OID"; + SWSS_LOG_ERROR("Cross-table reference validation failed, null OID expected from table %s", + table_name.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Cross-table reference valdiation failed, null OID"; } - dep_object.sai_object = object_type; - dep_object.key = key; - dep_object.oid = oid; + dep_object.sai_object = object_type; + dep_object.key = key; + dep_object.oid = oid; app_db_entry.action_dep_objects[action_name] = dep_object; } @@ -157,7 +158,7 @@ ReturnCode ExtTablesManager::validateP4ExtTableAppDbEntry(P4ExtTableAppDbEntry & { SWSS_LOG_ERROR("Not a valid extension table %s", app_db_entry.table_name.c_str()); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Not a valid extension table " << app_db_entry.table_name.c_str(); + << "Not a valid extension table " << app_db_entry.table_name.c_str(); } if (table->action_ref_tables.empty()) @@ -167,15 +168,15 @@ ReturnCode ExtTablesManager::validateP4ExtTableAppDbEntry(P4ExtTableAppDbEntry & ActionInfo *action; for (auto app_db_action_it = app_db_entry.action_params.begin(); - app_db_action_it != app_db_entry.action_params.end(); app_db_action_it++) + app_db_action_it != app_db_entry.action_params.end(); app_db_action_it++) { auto action_name = app_db_action_it->first; action = getTableActionInfo(table, action_name); if (action == nullptr) { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Not a valid action " << action_name.c_str() - << " in extension table " << app_db_entry.table_name.c_str(); + << "Not a valid action " << action_name.c_str() << " in extension table " + << app_db_entry.table_name.c_str(); } if (!action->refers_to) @@ -186,25 +187,23 @@ ReturnCode ExtTablesManager::validateP4ExtTableAppDbEntry(P4ExtTableAppDbEntry & status = validateActionParamsCrossRef(app_db_entry, action); if (!status.ok()) { - return status; + return status; } } return ReturnCode(); } - ReturnCodeOr ExtTablesManager::deserializeP4ExtTableEntry( - const std::string &table_name, - const std::string &key, const std::vector &attributes) + const std::string &table_name, const std::string &key, const std::vector &attributes) { - std::string action_name; + std::string action_name; SWSS_LOG_ENTER(); P4ExtTableAppDbEntry app_db_entry_or = {}; app_db_entry_or.table_name = table_name; - app_db_entry_or.table_key = key; + app_db_entry_or.table_key = key; action_name = ""; for (const auto &it : attributes) @@ -223,7 +222,7 @@ ReturnCodeOr ExtTablesManager::deserializeP4ExtTableEntry( { SWSS_LOG_ERROR("Unknown extension entry field"); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown extension entry field " << QuotedVar(field); + << "Unknown extension entry field " << QuotedVar(field); } const auto &prefix = tokenized_fields[0]; @@ -244,11 +243,10 @@ ReturnCodeOr ExtTablesManager::deserializeP4ExtTableEntry( return app_db_entry_or; } - ReturnCode ExtTablesManager::prepareP4SaiExtAPIParams(const P4ExtTableAppDbEntry &app_db_entry, std::string &ext_table_entry_attr) { - nlohmann::json sai_j, sai_metadata_j, sai_array_j = {}, sai_entry_j; + nlohmann::json sai_j, sai_metadata_j, sai_array_j = {}, sai_entry_j; SWSS_LOG_ENTER(); @@ -260,37 +258,37 @@ ReturnCode ExtTablesManager::prepareP4SaiExtAPIParams(const P4ExtTableAppDbEntry { SWSS_LOG_ERROR("extension entry for invalid table %s", app_db_entry.table_name.c_str()); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "extension entry for invalid table " << app_db_entry.table_name.c_str(); + << "extension entry for invalid table " << app_db_entry.table_name.c_str(); } nlohmann::json j = nlohmann::json::parse(app_db_entry.table_key); for (auto it = j.begin(); it != j.end(); ++it) { - std::string match, value, prefix; - std::size_t pos; + std::string match, value, prefix; + std::size_t pos; match = it.key(); value = it.value(); - prefix = p4orch::kMatchPrefix; + prefix = p4orch::kMatchPrefix; pos = match.rfind(prefix); if (pos != std::string::npos) { match.erase(0, prefix.length()); } - else + else { SWSS_LOG_ERROR("Failed to encode match fields for sai call"); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Failed to encode match fields for sai call"; } - prefix = p4orch::kFieldDelimiter; + prefix = p4orch::kFieldDelimiter; pos = match.rfind(prefix); if (pos != std::string::npos) { match.erase(0, prefix.length()); } - else + else { SWSS_LOG_ERROR("Failed to encode match fields for sai call"); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Failed to encode match fields for sai call"; @@ -301,7 +299,7 @@ ReturnCode ExtTablesManager::prepareP4SaiExtAPIParams(const P4ExtTableAppDbEntry { SWSS_LOG_ERROR("extension entry for invalid match field %s", match.c_str()); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "extension entry for invalid match field " << match.c_str(); + << "extension entry for invalid match field " << match.c_str(); } sai_metadata_j = nlohmann::json::object({}); @@ -315,7 +313,7 @@ ReturnCode ExtTablesManager::prepareP4SaiExtAPIParams(const P4ExtTableAppDbEntry } for (auto app_db_action_it = app_db_entry.action_params.begin(); - app_db_action_it != app_db_entry.action_params.end(); app_db_action_it++) + app_db_action_it != app_db_entry.action_params.end(); app_db_action_it++) { sai_j = nlohmann::json::object({}); auto action_dep_object_it = app_db_entry.action_dep_objects.find(app_db_action_it->first); @@ -323,9 +321,9 @@ ReturnCode ExtTablesManager::prepareP4SaiExtAPIParams(const P4ExtTableAppDbEntry { auto action_defn_it = table->action_fields.find(app_db_action_it->first); for (auto app_db_param_it = app_db_action_it->second.begin(); - app_db_param_it != app_db_action_it->second.end(); app_db_param_it++) + app_db_param_it != app_db_action_it->second.end(); app_db_param_it++) { - nlohmann::json params_j = nlohmann::json::object({}); + nlohmann::json params_j = nlohmann::json::object({}); if (action_defn_it != table->action_fields.end()) { auto param_defn_it = action_defn_it->second.params.find(app_db_param_it->first); @@ -396,9 +394,8 @@ bool createGenericCounter(sai_object_id_t &counter_id) return true; } - ReturnCode ExtTablesManager::createP4ExtTableEntry(const P4ExtTableAppDbEntry &app_db_entry, - P4ExtTableEntry &ext_table_entry) + P4ExtTableEntry &ext_table_entry) { ReturnCode status; sai_object_type_t object_type; @@ -428,22 +425,20 @@ ReturnCode ExtTablesManager::createP4ExtTableEntry(const P4ExtTableAppDbEntry &a generic_programmable_attr.value.json.json.list = (int8_t *)const_cast(ext_table_entry_attr.c_str()); generic_programmable_attrs.push_back(generic_programmable_attr); - auto *table = getTableInfo(app_db_entry.table_name); if (!table) { SWSS_LOG_ERROR("extension entry for invalid table %s", app_db_entry.table_name.c_str()); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "extension entry for invalid table " << app_db_entry.table_name.c_str(); + << "extension entry for invalid table " << app_db_entry.table_name.c_str(); } if (table->counter_bytes_enabled || table->counter_packets_enabled) { if (!createGenericCounter(counter_id)) { - SWSS_LOG_WARN("Failed to create counter for table %s, key %s\n", - app_db_entry.table_name.c_str(), - app_db_entry.table_key.c_str()); + SWSS_LOG_WARN("Failed to create counter for table %s, key %s\n", app_db_entry.table_name.c_str(), + app_db_entry.table_key.c_str()); } else { @@ -457,33 +452,29 @@ ReturnCode ExtTablesManager::createP4ExtTableEntry(const P4ExtTableAppDbEntry &a sai_object_id_t sai_generic_programmable_oid = SAI_NULL_OBJECT_ID; sai_status_t sai_status = sai_generic_programmable_api->create_generic_programmable( - &sai_generic_programmable_oid, gSwitchId, - (uint32_t)generic_programmable_attrs.size(), - generic_programmable_attrs.data()); + &sai_generic_programmable_oid, gSwitchId, (uint32_t)generic_programmable_attrs.size(), + generic_programmable_attrs.data()); if (sai_status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("create sai api call failed for extension entry table %s, entry %s", - app_db_entry.table_name.c_str(), app_db_entry.table_key.c_str()); + app_db_entry.table_name.c_str(), app_db_entry.table_key.c_str()); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "create sai api call failed for extension entry table " - << app_db_entry.table_name.c_str() - << " , entry " << app_db_entry.table_key.c_str(); + << "create sai api call failed for extension entry table " << app_db_entry.table_name.c_str() + << " , entry " << app_db_entry.table_key.c_str(); } std::string crm_table_name = "EXT_" + app_db_entry.table_name; boost::algorithm::to_upper(crm_table_name); gCrmOrch->incCrmExtTableUsedCounter(CrmResourceType::CRM_EXT_TABLE, crm_table_name); - ext_table_entry.sai_entry_oid = sai_generic_programmable_oid; for (auto action_dep_object_it = app_db_entry.action_dep_objects.begin(); - action_dep_object_it != app_db_entry.action_dep_objects.end(); action_dep_object_it++) + action_dep_object_it != app_db_entry.action_dep_objects.end(); action_dep_object_it++) { auto action_dep_object = action_dep_object_it->second; m_p4OidMapper->increaseRefCount(action_dep_object.sai_object, action_dep_object.key); ext_table_entry.action_dep_objects[action_dep_object_it->first] = action_dep_object; } - auto ext_table_key = KeyGenerator::generateExtTableKey(app_db_entry.table_name, app_db_entry.table_key); status = getSaiObject(ext_table_key, object_type, key); if (!status.ok()) @@ -497,9 +488,8 @@ ReturnCode ExtTablesManager::createP4ExtTableEntry(const P4ExtTableAppDbEntry &a return ReturnCode(); } - ReturnCode ExtTablesManager::updateP4ExtTableEntry(const P4ExtTableAppDbEntry &app_db_entry, - P4ExtTableEntry *ext_table_entry) + P4ExtTableEntry *ext_table_entry) { ReturnCode status; std::string ext_table_entry_attr; @@ -510,11 +500,10 @@ ReturnCode ExtTablesManager::updateP4ExtTableEntry(const P4ExtTableAppDbEntry &a if (ext_table_entry->sai_entry_oid == SAI_NULL_OBJECT_ID) { SWSS_LOG_ERROR("update sai api call for NULL extension entry table %s, entry %s", - app_db_entry.table_name.c_str(), ext_table_entry->table_key.c_str()); + app_db_entry.table_name.c_str(), ext_table_entry->table_key.c_str()); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "update sai api call for NULL extension entry table " - << app_db_entry.table_name.c_str() - << " , entry " << ext_table_entry->table_key.c_str(); + << "update sai api call for NULL extension entry table " << app_db_entry.table_name.c_str() + << " , entry " << ext_table_entry->table_key.c_str(); } status = prepareP4SaiExtAPIParams(app_db_entry, ext_table_entry_attr); @@ -531,24 +520,21 @@ ReturnCode ExtTablesManager::updateP4ExtTableEntry(const P4ExtTableAppDbEntry &a generic_programmable_attr.value.json.json.list = (int8_t *)const_cast(ext_table_entry_attr.c_str()); sai_status_t sai_status = sai_generic_programmable_api->set_generic_programmable_attribute( - ext_table_entry->sai_entry_oid, - &generic_programmable_attr); + ext_table_entry->sai_entry_oid, &generic_programmable_attr); if (sai_status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("update sai api call failed for extension entry table %s, entry %s", - app_db_entry.table_name.c_str(), ext_table_entry->table_key.c_str()); + app_db_entry.table_name.c_str(), ext_table_entry->table_key.c_str()); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "update sai api call failed for extension entry table " - << app_db_entry.table_name.c_str() - << " , entry " << ext_table_entry->table_key.c_str(); + << "update sai api call failed for extension entry table " << app_db_entry.table_name.c_str() + << " , entry " << ext_table_entry->table_key.c_str(); } - old_action_dep_objects = ext_table_entry->action_dep_objects; ext_table_entry->action_dep_objects.clear(); for (auto action_dep_object_it = app_db_entry.action_dep_objects.begin(); - action_dep_object_it != app_db_entry.action_dep_objects.end(); action_dep_object_it++) + action_dep_object_it != app_db_entry.action_dep_objects.end(); action_dep_object_it++) { auto action_dep_object = action_dep_object_it->second; m_p4OidMapper->increaseRefCount(action_dep_object.sai_object, action_dep_object.key); @@ -556,7 +542,7 @@ ReturnCode ExtTablesManager::updateP4ExtTableEntry(const P4ExtTableAppDbEntry &a } for (auto old_action_dep_object_it = old_action_dep_objects.begin(); - old_action_dep_object_it != old_action_dep_objects.end(); old_action_dep_object_it++) + old_action_dep_object_it != old_action_dep_objects.end(); old_action_dep_object_it++) { auto old_action_dep_object = old_action_dep_object_it->second; m_p4OidMapper->decreaseRefCount(old_action_dep_object.sai_object, old_action_dep_object.key); @@ -565,8 +551,7 @@ ReturnCode ExtTablesManager::updateP4ExtTableEntry(const P4ExtTableAppDbEntry &a return ReturnCode(); } -ReturnCode ExtTablesManager::removeP4ExtTableEntry(const std::string &table_name, - const std::string &table_key) +ReturnCode ExtTablesManager::removeP4ExtTableEntry(const std::string &table_name, const std::string &table_key) { ReturnCode status; sai_object_type_t object_type; @@ -578,36 +563,31 @@ ReturnCode ExtTablesManager::removeP4ExtTableEntry(const std::string &table_name if (!ext_table_entry) { LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "extension entry with key " << QuotedVar(table_key) - << " does not exist for table " << QuotedVar(table_name)); + << "extension entry with key " << QuotedVar(table_key) << " does not exist for table " + << QuotedVar(table_name)); } if (ext_table_entry->sai_entry_oid == SAI_NULL_OBJECT_ID) { - SWSS_LOG_ERROR("remove sai api call for NULL extension entry table %s, entry %s", - table_name.c_str(), table_key.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "remove sai api call for NULL extension entry table " - << table_name.c_str() << " , entry " << table_key.c_str(); + SWSS_LOG_ERROR("remove sai api call for NULL extension entry table %s, entry %s", table_name.c_str(), + table_key.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "remove sai api call for NULL extension entry table " + << table_name.c_str() << " , entry " << table_key.c_str(); } - SWSS_LOG_ERROR("table: %s, key: %s", ext_table_entry->table_name.c_str(), - ext_table_entry->table_key.c_str()); - sai_status_t sai_status = sai_generic_programmable_api->remove_generic_programmable( - ext_table_entry->sai_entry_oid); + SWSS_LOG_ERROR("table: %s, key: %s", ext_table_entry->table_name.c_str(), ext_table_entry->table_key.c_str()); + sai_status_t sai_status = sai_generic_programmable_api->remove_generic_programmable(ext_table_entry->sai_entry_oid); if (sai_status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("remove sai api call failed for extension entry table %s, entry %s", - table_name.c_str(), table_key.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "remove sai api call failed for extension entry table " - << table_name.c_str() << " , entry " << table_key.c_str(); + SWSS_LOG_ERROR("remove sai api call failed for extension entry table %s, entry %s", table_name.c_str(), + table_key.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "remove sai api call failed for extension entry table " + << table_name.c_str() << " , entry " << table_key.c_str(); } std::string crm_table_name = "EXT_" + table_name; boost::algorithm::to_upper(crm_table_name); gCrmOrch->decCrmExtTableUsedCounter(CrmResourceType::CRM_EXT_TABLE, crm_table_name); - auto ext_table_key = KeyGenerator::generateExtTableKey(table_name, table_key); status = getSaiObject(ext_table_key, object_type, key); if (!status.ok()) @@ -630,7 +610,7 @@ ReturnCode ExtTablesManager::removeP4ExtTableEntry(const std::string &table_name m_p4OidMapper->eraseOID(object_type, key); for (auto action_dep_object_it = ext_table_entry->action_dep_objects.begin(); - action_dep_object_it != ext_table_entry->action_dep_objects.end(); action_dep_object_it++) + action_dep_object_it != ext_table_entry->action_dep_objects.end(); action_dep_object_it++) { auto action_dep_object = action_dep_object_it->second; m_p4OidMapper->decreaseRefCount(action_dep_object.sai_object, action_dep_object.key); @@ -647,7 +627,6 @@ ReturnCode ExtTablesManager::removeP4ExtTableEntry(const std::string &table_name return ReturnCode(); } - ReturnCode ExtTablesManager::processAddRequest(const P4ExtTableAppDbEntry &app_db_entry) { SWSS_LOG_ENTER(); @@ -662,15 +641,14 @@ ReturnCode ExtTablesManager::processAddRequest(const P4ExtTableAppDbEntry &app_d } ReturnCode ExtTablesManager::processUpdateRequest(const P4ExtTableAppDbEntry &app_db_entry, - P4ExtTableEntry *ext_table_entry) + P4ExtTableEntry *ext_table_entry) { SWSS_LOG_ENTER(); auto status = updateP4ExtTableEntry(app_db_entry, ext_table_entry); if (!status.ok()) { - SWSS_LOG_ERROR("Failed to update extension entry with key %s", - app_db_entry.table_key.c_str()); + SWSS_LOG_ERROR("Failed to update extension entry with key %s", app_db_entry.table_key.c_str()); } return ReturnCode(); } @@ -682,14 +660,13 @@ ReturnCode ExtTablesManager::processDeleteRequest(const P4ExtTableAppDbEntry &ap auto status = removeP4ExtTableEntry(app_db_entry.table_name, app_db_entry.table_key); if (!status.ok()) { - SWSS_LOG_ERROR("Failed to remove extension entry with key %s", - app_db_entry.table_key.c_str()); + SWSS_LOG_ERROR("Failed to remove extension entry with key %s", app_db_entry.table_key.c_str()); } return ReturnCode(); } - -ReturnCode ExtTablesManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) +ReturnCode ExtTablesManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) { object_type = SAI_OBJECT_TYPE_GENERIC_PROGRAMMABLE; object_key = json_key; @@ -707,97 +684,99 @@ void ExtTablesManager::drain() SWSS_LOG_ENTER(); std::string table_prefix = "EXT_"; - if (gP4Orch->tablesinfo) { - for (auto table_it = gP4Orch->tablesinfo->m_tablePrecedenceMap.begin(); - table_it != gP4Orch->tablesinfo->m_tablePrecedenceMap.end(); ++table_it) - { - auto table_name = table_prefix + table_it->second; - boost::algorithm::to_upper(table_name); - auto it_m = m_entriesTables.find(table_name); - if (it_m == m_entriesTables.end()) - { - continue; - } - - for (const auto &key_op_fvs_tuple : it_m->second) + if (gP4Orch->tablesinfo) + { + for (auto table_it = gP4Orch->tablesinfo->m_tablePrecedenceMap.begin(); + table_it != gP4Orch->tablesinfo->m_tablePrecedenceMap.end(); ++table_it) { - std::string table_name; - std::string table_key; - - parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &table_key); - const std::vector &attributes = kfvFieldsValues(key_op_fvs_tuple); - - if (table_name.rfind(table_prefix, 0) == std::string::npos) + auto table_name = table_prefix + table_it->second; + boost::algorithm::to_upper(table_name); + auto it_m = m_entriesTables.find(table_name); + if (it_m == m_entriesTables.end()) { - SWSS_LOG_ERROR("Table %s is without prefix %s", table_name.c_str(), table_prefix.c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), - StatusCode::SWSS_RC_INVALID_PARAM, /*replace=*/true); continue; } - table_name = table_name.substr(table_prefix.length()); - boost::algorithm::to_lower(table_name); - ReturnCode status; - auto app_db_entry_or = deserializeP4ExtTableEntry(table_name, table_key, attributes); - if (!app_db_entry_or.ok()) + for (const auto &key_op_fvs_tuple : it_m->second) { - status = app_db_entry_or.status(); - SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", - QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), - status, /*replace=*/true); - continue; - } + std::string table_name; + std::string table_key; - auto &app_db_entry = *app_db_entry_or; - status = validateP4ExtTableAppDbEntry(app_db_entry); - if (!status.ok()) - { - SWSS_LOG_ERROR("Validation failed for extension APP DB entry with key %s: %s", - QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), - status, /*replace=*/true); - continue; - } + parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &table_key); + const std::vector &attributes = kfvFieldsValues(key_op_fvs_tuple); - const std::string &operation = kfvOp(key_op_fvs_tuple); - if (operation == SET_COMMAND) - { - auto *ext_table_entry = getP4ExtTableEntry(app_db_entry.table_name, app_db_entry.table_key); - if (ext_table_entry == nullptr) + if (table_name.rfind(table_prefix, 0) == std::string::npos) + { + SWSS_LOG_ERROR("Table %s is without prefix %s", table_name.c_str(), table_prefix.c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), + kfvFieldsValues(key_op_fvs_tuple), StatusCode::SWSS_RC_INVALID_PARAM, + /*replace=*/true); + continue; + } + table_name = table_name.substr(table_prefix.length()); + boost::algorithm::to_lower(table_name); + + ReturnCode status; + auto app_db_entry_or = deserializeP4ExtTableEntry(table_name, table_key, attributes); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", + QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), + kfvFieldsValues(key_op_fvs_tuple), status, /*replace=*/true); + continue; + } + + auto &app_db_entry = *app_db_entry_or; + status = validateP4ExtTableAppDbEntry(app_db_entry); + if (!status.ok()) + { + SWSS_LOG_ERROR("Validation failed for extension APP DB entry with key %s: %s", + QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), + kfvFieldsValues(key_op_fvs_tuple), status, /*replace=*/true); + continue; + } + + const std::string &operation = kfvOp(key_op_fvs_tuple); + if (operation == SET_COMMAND) + { + auto *ext_table_entry = getP4ExtTableEntry(app_db_entry.table_name, app_db_entry.table_key); + if (ext_table_entry == nullptr) + { + // Create extension entry + app_db_entry.db_key = kfvKey(key_op_fvs_tuple); + status = processAddRequest(app_db_entry); + } + else + { + // Modify existing extension entry + status = processUpdateRequest(app_db_entry, ext_table_entry); + } + } + else if (operation == DEL_COMMAND) { - // Create extension entry - app_db_entry.db_key = kfvKey(key_op_fvs_tuple); - status = processAddRequest(app_db_entry); + // Delete extension entry + status = processDeleteRequest(app_db_entry); } else { - // Modify existing extension entry - status = processUpdateRequest(app_db_entry, ext_table_entry); + status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unknown operation type " << QuotedVar(operation); + SWSS_LOG_ERROR("%s", status.message().c_str()); } + if (!status.ok()) + { + SWSS_LOG_ERROR("Processing failed for extension APP_DB entry with key %s: %s", + QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), status.message().c_str()); + } + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, /*replace=*/true); } - else if (operation == DEL_COMMAND) - { - // Delete extension entry - status = processDeleteRequest(app_db_entry); - } - else - { - status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown operation type " << QuotedVar(operation); - SWSS_LOG_ERROR("%s", status.message().c_str()); - } - if (!status.ok()) - { - SWSS_LOG_ERROR("Processing failed for extension APP_DB entry with key %s: %s", - QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), status.message().c_str()); - } - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), - status, /*replace=*/true); - } - it_m->second.clear(); - } + it_m->second.clear(); + } } // Now report error for all remaining un-processed entries @@ -813,7 +792,6 @@ void ExtTablesManager::drain() } } - void ExtTablesManager::doExtCounterStatsTask() { SWSS_LOG_ENTER(); @@ -823,12 +801,12 @@ void ExtTablesManager::doExtCounterStatsTask() return; } - sai_stat_id_t stat_ids[] = { SAI_COUNTER_STAT_PACKETS, SAI_COUNTER_STAT_BYTES }; + sai_stat_id_t stat_ids[] = {SAI_COUNTER_STAT_PACKETS, SAI_COUNTER_STAT_BYTES}; uint64_t stats[2]; std::vector counter_stats_values; for (auto table_it = gP4Orch->tablesinfo->m_tableInfoMap.begin(); - table_it != gP4Orch->tablesinfo->m_tableInfoMap.end(); ++table_it) + table_it != gP4Orch->tablesinfo->m_tableInfoMap.end(); ++table_it) { if (!table_it->second.counter_bytes_enabled && !table_it->second.counter_packets_enabled) { @@ -842,8 +820,8 @@ void ExtTablesManager::doExtCounterStatsTask() continue; } - for (auto ext_table_entry_it = ext_table_it->second.begin(); - ext_table_entry_it != ext_table_it->second.end(); ++ext_table_entry_it) + for (auto ext_table_entry_it = ext_table_it->second.begin(); ext_table_entry_it != ext_table_it->second.end(); + ++ext_table_entry_it) { auto *ext_table_entry = &ext_table_entry_it->second; if (ext_table_entry->sai_counter_oid == SAI_NULL_OBJECT_ID) @@ -852,18 +830,16 @@ void ExtTablesManager::doExtCounterStatsTask() } sai_status_t sai_status = - sai_counter_api->get_counter_stats(ext_table_entry->sai_counter_oid, 2, stat_ids, stats); + sai_counter_api->get_counter_stats(ext_table_entry->sai_counter_oid, 2, stat_ids, stats); if (sai_status != SAI_STATUS_SUCCESS) { SWSS_LOG_WARN("Failed to set counters stats for extension entry %s:%s in COUNTERS_DB: ", - table_name.c_str(), ext_table_entry->table_key.c_str()); + table_name.c_str(), ext_table_entry->table_key.c_str()); continue; } - counter_stats_values.push_back( - swss::FieldValueTuple{P4_COUNTER_STATS_PACKETS, std::to_string(stats[0])}); - counter_stats_values.push_back( - swss::FieldValueTuple{P4_COUNTER_STATS_BYTES, std::to_string(stats[1])}); + counter_stats_values.push_back(swss::FieldValueTuple{P4_COUNTER_STATS_PACKETS, std::to_string(stats[0])}); + counter_stats_values.push_back(swss::FieldValueTuple{P4_COUNTER_STATS_BYTES, std::to_string(stats[1])}); // Set field value tuples for counters stats in COUNTERS_DB m_countersTable->set(ext_table_entry->db_key, counter_stats_values); @@ -878,4 +854,3 @@ std::string ExtTablesManager::verifyState(const std::string &key, const std::vec return result; } - diff --git a/orchagent/p4orch/ext_tables_manager.h b/orchagent/p4orch/ext_tables_manager.h index cb61d5f308..e45a2566ca 100644 --- a/orchagent/p4orch/ext_tables_manager.h +++ b/orchagent/p4orch/ext_tables_manager.h @@ -6,7 +6,6 @@ #include #include "macaddress.h" -#include #include "orch.h" #include "p4orch/object_manager_interface.h" #include "p4orch/p4oidmapper.h" @@ -15,6 +14,7 @@ #include "response_publisher_interface.h" #include "return_code.h" #include "vrforch.h" +#include extern "C" { #include "sai.h" @@ -29,9 +29,9 @@ struct P4ExtTableEntry sai_object_id_t sai_counter_oid = SAI_NULL_OBJECT_ID; std::unordered_map action_dep_objects; - P4ExtTableEntry() {}; + P4ExtTableEntry(){}; P4ExtTableEntry(const std::string &db_key, const std::string &table_name, const std::string &table_key) - : db_key(db_key), table_name(table_name), table_key(table_key) + : db_key(db_key), table_name(table_name), table_key(table_key) { } }; @@ -44,10 +44,9 @@ class ExtTablesManager : public ObjectManagerInterface { public: ExtTablesManager(P4OidMapper *p4oidMapper, VRFOrch *vrfOrch, ResponsePublisherInterface *publisher) - : m_vrfOrch(vrfOrch), - m_countersDb(std::make_unique("COUNTERS_DB", 0)), - m_countersTable(std::make_unique( - m_countersDb.get(), std::string(COUNTERS_TABLE) + DEFAULT_KEY_SEPARATOR + APP_P4RT_TABLE_NAME)) + : m_vrfOrch(vrfOrch), m_countersDb(std::make_unique("COUNTERS_DB", 0)), + m_countersTable(std::make_unique( + m_countersDb.get(), std::string(COUNTERS_TABLE) + DEFAULT_KEY_SEPARATOR + APP_P4RT_TABLE_NAME)) { SWSS_LOG_ENTER(); @@ -61,21 +60,20 @@ class ExtTablesManager : public ObjectManagerInterface void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; void drain() override; std::string verifyState(const std::string &key, const std::vector &tuple) override; - ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; // For every extension entry, update counters stats in COUNTERS_DB, if // counters are enabled for those entries void doExtCounterStatsTask(); private: - ReturnCodeOr deserializeP4ExtTableEntry( - const std::string &table_name, - const std::string &key, const std::vector &attributes); + ReturnCodeOr deserializeP4ExtTableEntry(const std::string &table_name, const std::string &key, + const std::vector &attributes); ReturnCode validateActionParamsCrossRef(P4ExtTableAppDbEntry &app_db_entry, ActionInfo *action); ReturnCode validateP4ExtTableAppDbEntry(P4ExtTableAppDbEntry &app_db_entry); P4ExtTableEntry *getP4ExtTableEntry(const std::string &table_name, const std::string &table_key); - ReturnCode prepareP4SaiExtAPIParams(const P4ExtTableAppDbEntry &app_db_entry, - std::string &ext_table_entry_attr); + ReturnCode prepareP4SaiExtAPIParams(const P4ExtTableAppDbEntry &app_db_entry, std::string &ext_table_entry_attr); ReturnCode createP4ExtTableEntry(const P4ExtTableAppDbEntry &app_db_entry, P4ExtTableEntry &ext_table_entry); ReturnCode updateP4ExtTableEntry(const P4ExtTableAppDbEntry &app_db_entry, P4ExtTableEntry *ext_table_entry); ReturnCode removeP4ExtTableEntry(const std::string &table_name, const std::string &table_key); diff --git a/orchagent/p4orch/gre_tunnel_manager.cpp b/orchagent/p4orch/gre_tunnel_manager.cpp index 9f4cc7f7b6..a46dc0fd38 100644 --- a/orchagent/p4orch/gre_tunnel_manager.cpp +++ b/orchagent/p4orch/gre_tunnel_manager.cpp @@ -9,12 +9,12 @@ #include "crmorch.h" #include "dbconnector.h" #include "ipaddress.h" -#include #include "logger.h" #include "p4orch/p4orch_util.h" #include "sai_serialize.h" #include "swssnet.h" #include "table.h" +#include extern "C" { #include "sai.h" @@ -98,7 +98,8 @@ P4GreTunnelEntry::P4GreTunnelEntry(const std::string &tunnel_id, const std::stri tunnel_key = KeyGenerator::generateTunnelKey(tunnel_id); } -ReturnCode GreTunnelManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) +ReturnCode GreTunnelManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) { return StatusCode::SWSS_RC_UNIMPLEMENTED; } diff --git a/orchagent/p4orch/gre_tunnel_manager.h b/orchagent/p4orch/gre_tunnel_manager.h index d5cb32e9bf..2eee9b18c4 100644 --- a/orchagent/p4orch/gre_tunnel_manager.h +++ b/orchagent/p4orch/gre_tunnel_manager.h @@ -72,7 +72,8 @@ class GreTunnelManager : public ObjectManagerInterface void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; void drain() override; std::string verifyState(const std::string &key, const std::vector &tuple) override; - ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; ReturnCodeOr getConstGreTunnelEntry(const std::string &gre_tunnel_key); diff --git a/orchagent/p4orch/l3_admit_manager.cpp b/orchagent/p4orch/l3_admit_manager.cpp index d319c54a73..2440dd2a0c 100644 --- a/orchagent/p4orch/l3_admit_manager.cpp +++ b/orchagent/p4orch/l3_admit_manager.cpp @@ -7,7 +7,6 @@ #include "SaiAttributeList.h" #include "dbconnector.h" -#include #include "logger.h" #include "p4orch/p4orch_util.h" #include "portsorch.h" @@ -15,6 +14,7 @@ #include "sai_serialize.h" #include "table.h" #include "tokenize.h" +#include extern "C" { #include "sai.h" @@ -64,7 +64,8 @@ ReturnCodeOr> getSaiAttrs(const P4L3AdmitEntry &l3_ } // namespace -ReturnCode L3AdmitManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) +ReturnCode L3AdmitManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) { return StatusCode::SWSS_RC_UNIMPLEMENTED; } diff --git a/orchagent/p4orch/l3_admit_manager.h b/orchagent/p4orch/l3_admit_manager.h index d378775c4f..5f0af69b71 100644 --- a/orchagent/p4orch/l3_admit_manager.h +++ b/orchagent/p4orch/l3_admit_manager.h @@ -63,7 +63,8 @@ class L3AdmitManager : public ObjectManagerInterface void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; void drain() override; std::string verifyState(const std::string &key, const std::vector &tuple) override; - ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; private: // Gets the internal cached next hop entry by its key. diff --git a/orchagent/p4orch/mirror_session_manager.cpp b/orchagent/p4orch/mirror_session_manager.cpp index 3554344fb3..440257ea1d 100644 --- a/orchagent/p4orch/mirror_session_manager.cpp +++ b/orchagent/p4orch/mirror_session_manager.cpp @@ -4,13 +4,13 @@ #include "SaiAttributeList.h" #include "dbconnector.h" -#include #include "p4orch/p4orch_util.h" #include "portsorch.h" #include "sai_serialize.h" #include "swss/logger.h" #include "swssnet.h" #include "table.h" +#include using ::p4orch::kTableKeyDelimiter; @@ -21,13 +21,14 @@ extern sai_object_id_t gSwitchId; namespace p4orch { -ReturnCode MirrorSessionManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) +ReturnCode MirrorSessionManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) { - std::string value; + std::string value; try { - nlohmann::json j = nlohmann::json::parse(json_key); + nlohmann::json j = nlohmann::json::parse(json_key); if (j.find(prependMatchField(p4orch::kMirrorSessionId)) != j.end()) { value = j.at(prependMatchField(p4orch::kMirrorSessionId)).get(); diff --git a/orchagent/p4orch/mirror_session_manager.h b/orchagent/p4orch/mirror_session_manager.h index 5f1c26e10a..7c2bf3b3b1 100644 --- a/orchagent/p4orch/mirror_session_manager.h +++ b/orchagent/p4orch/mirror_session_manager.h @@ -87,7 +87,8 @@ class MirrorSessionManager : public ObjectManagerInterface std::string verifyState(const std::string &key, const std::vector &tuple) override; - ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; private: ReturnCodeOr deserializeP4MirrorSessionAppDbEntry( diff --git a/orchagent/p4orch/neighbor_manager.cpp b/orchagent/p4orch/neighbor_manager.cpp index 7eab967183..75075a13a6 100644 --- a/orchagent/p4orch/neighbor_manager.cpp +++ b/orchagent/p4orch/neighbor_manager.cpp @@ -7,13 +7,13 @@ #include "SaiAttributeList.h" #include "crmorch.h" #include "dbconnector.h" -#include #include "logger.h" #include "orch.h" #include "p4orch/p4orch_util.h" #include "sai_serialize.h" #include "swssnet.h" #include "table.h" +#include extern "C" { #include "sai.h" @@ -324,14 +324,15 @@ ReturnCode NeighborManager::processDeleteRequest(const std::string &neighbor_key return status; } -ReturnCode NeighborManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) +ReturnCode NeighborManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) { - std::string router_intf_id, neighbor_id; + std::string router_intf_id, neighbor_id; swss::IpAddress neighbor; try { - nlohmann::json j = nlohmann::json::parse(json_key); + nlohmann::json j = nlohmann::json::parse(json_key); if (j.find(prependMatchField(p4orch::kRouterInterfaceId)) != j.end()) { router_intf_id = j.at(prependMatchField(p4orch::kRouterInterfaceId)).get(); @@ -350,7 +351,8 @@ ReturnCode NeighborManager::getSaiObject(const std::string &json_key, sai_object } else { - SWSS_LOG_ERROR("%s match parameter absent: required for dependent object query", p4orch::kRouterInterfaceId); + SWSS_LOG_ERROR("%s match parameter absent: required for dependent object query", + p4orch::kRouterInterfaceId); } } catch (std::exception &ex) diff --git a/orchagent/p4orch/neighbor_manager.h b/orchagent/p4orch/neighbor_manager.h index 0022d3a8cc..229dcc41d1 100644 --- a/orchagent/p4orch/neighbor_manager.h +++ b/orchagent/p4orch/neighbor_manager.h @@ -52,7 +52,8 @@ class NeighborManager : public ObjectManagerInterface void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; void drain() override; std::string verifyState(const std::string &key, const std::vector &tuple) override; - ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; private: ReturnCodeOr deserializeNeighborEntry(const std::string &key, diff --git a/orchagent/p4orch/next_hop_manager.cpp b/orchagent/p4orch/next_hop_manager.cpp index 1614a266f6..b5586ae233 100644 --- a/orchagent/p4orch/next_hop_manager.cpp +++ b/orchagent/p4orch/next_hop_manager.cpp @@ -8,13 +8,13 @@ #include "crmorch.h" #include "dbconnector.h" #include "ipaddress.h" -#include #include "logger.h" #include "p4orch/p4orch.h" #include "p4orch/p4orch_util.h" #include "sai_serialize.h" #include "swssnet.h" #include "table.h" +#include extern "C" { #include "sai.h" @@ -147,13 +147,14 @@ ReturnCodeOr> NextHopManager::getSaiAttrs(const P4N return next_hop_attrs; } -ReturnCode NextHopManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) +ReturnCode NextHopManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) { - std::string value; + std::string value; try { - nlohmann::json j = nlohmann::json::parse(json_key); + nlohmann::json j = nlohmann::json::parse(json_key); if (j.find(prependMatchField(p4orch::kNexthopId)) != j.end()) { value = j.at(prependMatchField(p4orch::kNexthopId)).get(); diff --git a/orchagent/p4orch/next_hop_manager.h b/orchagent/p4orch/next_hop_manager.h index 7bacdad534..aac6f5e444 100644 --- a/orchagent/p4orch/next_hop_manager.h +++ b/orchagent/p4orch/next_hop_manager.h @@ -60,7 +60,8 @@ class NextHopManager : public ObjectManagerInterface void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; void drain() override; std::string verifyState(const std::string &key, const std::vector &tuple) override; - ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; private: // Gets the internal cached next hop entry by its key. diff --git a/orchagent/p4orch/object_manager_interface.h b/orchagent/p4orch/object_manager_interface.h index 966288a156..1d44990edc 100644 --- a/orchagent/p4orch/object_manager_interface.h +++ b/orchagent/p4orch/object_manager_interface.h @@ -18,5 +18,6 @@ class ObjectManagerInterface // For sai extension objects depending on a sai object // return sai object id for a given table with a given key - virtual ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) = 0; + virtual ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) = 0; }; diff --git a/orchagent/p4orch/p4orch.cpp b/orchagent/p4orch/p4orch.cpp index eca0918171..f1e6bd4702 100644 --- a/orchagent/p4orch/p4orch.cpp +++ b/orchagent/p4orch/p4orch.cpp @@ -8,17 +8,17 @@ #include "copporch.h" #include "logger.h" #include "orch.h" -#include "p4orch/p4orch_util.h" -#include "p4orch/tables_definition_manager.h" #include "p4orch/acl_rule_manager.h" #include "p4orch/acl_table_manager.h" +#include "p4orch/ext_tables_manager.h" #include "p4orch/gre_tunnel_manager.h" #include "p4orch/l3_admit_manager.h" #include "p4orch/neighbor_manager.h" #include "p4orch/next_hop_manager.h" +#include "p4orch/p4orch_util.h" #include "p4orch/route_manager.h" #include "p4orch/router_interface_manager.h" -#include "p4orch/ext_tables_manager.h" +#include "p4orch/tables_definition_manager.h" #include "portsorch.h" #include "return_code.h" #include "sai_serialize.h" @@ -142,7 +142,7 @@ void P4Orch::doTask(Consumer &consumer) else { auto status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to find P4Orch Manager for " << table_name << " P4RT DB table"; + << "Failed to find P4Orch Manager for " << table_name << " P4RT DB table"; SWSS_LOG_ERROR("%s", status.message().c_str()); m_publisher.publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), status); diff --git a/orchagent/p4orch/p4orch.h b/orchagent/p4orch/p4orch.h index 9385346d20..cc02052830 100644 --- a/orchagent/p4orch/p4orch.h +++ b/orchagent/p4orch/p4orch.h @@ -10,9 +10,9 @@ #include "notificationconsumer.h" #include "notifier.h" #include "orch.h" -#include "p4orch/tables_definition_manager.h" #include "p4orch/acl_rule_manager.h" #include "p4orch/acl_table_manager.h" +#include "p4orch/ext_tables_manager.h" #include "p4orch/gre_tunnel_manager.h" #include "p4orch/l3_admit_manager.h" #include "p4orch/mirror_session_manager.h" @@ -22,22 +22,21 @@ #include "p4orch/p4oidmapper.h" #include "p4orch/route_manager.h" #include "p4orch/router_interface_manager.h" +#include "p4orch/tables_definition_manager.h" #include "p4orch/wcmp_manager.h" -#include "p4orch/ext_tables_manager.h" #include "response_publisher.h" #include "vrforch.h" static const std::map FixedTablesMap = { - {"router_interface_table", APP_P4RT_ROUTER_INTERFACE_TABLE_NAME }, - {"neighbor_table", APP_P4RT_NEIGHBOR_TABLE_NAME}, - {"nexthop_table", APP_P4RT_NEXTHOP_TABLE_NAME}, - {"wcmp_group_table", APP_P4RT_WCMP_GROUP_TABLE_NAME}, - {"ipv4_table", APP_P4RT_IPV4_TABLE_NAME}, - {"ipv6_table", APP_P4RT_IPV6_TABLE_NAME}, - {"mirror_session_table", APP_P4RT_MIRROR_SESSION_TABLE_NAME}, - {"l3_admit_table", APP_P4RT_L3_ADMIT_TABLE_NAME}, - {"tunnel_table", APP_P4RT_TUNNEL_TABLE_NAME} -}; + {"router_interface_table", APP_P4RT_ROUTER_INTERFACE_TABLE_NAME}, + {"neighbor_table", APP_P4RT_NEIGHBOR_TABLE_NAME}, + {"nexthop_table", APP_P4RT_NEXTHOP_TABLE_NAME}, + {"wcmp_group_table", APP_P4RT_WCMP_GROUP_TABLE_NAME}, + {"ipv4_table", APP_P4RT_IPV4_TABLE_NAME}, + {"ipv6_table", APP_P4RT_IPV6_TABLE_NAME}, + {"mirror_session_table", APP_P4RT_MIRROR_SESSION_TABLE_NAME}, + {"l3_admit_table", APP_P4RT_L3_ADMIT_TABLE_NAME}, + {"tunnel_table", APP_P4RT_TUNNEL_TABLE_NAME}}; class P4Orch : public Orch { @@ -55,7 +54,6 @@ class P4Orch : public Orch // m_p4TableToManagerMap: P4 APP DB table name, P4 Object Manager std::unordered_map m_p4TableToManagerMap; - private: void doTask(Consumer &consumer); diff --git a/orchagent/p4orch/p4orch_util.cpp b/orchagent/p4orch/p4orch_util.cpp index b2ea0a762b..ceb46b4b01 100644 --- a/orchagent/p4orch/p4orch_util.cpp +++ b/orchagent/p4orch/p4orch_util.cpp @@ -1,5 +1,5 @@ -#include "p4orch/p4orch.h" #include "p4orch/p4orch_util.h" +#include "p4orch/p4orch.h" #include "schema.h" @@ -116,9 +116,7 @@ ActionInfo *getTableActionInfo(TableInfo *table, const std::string &action_name) std::string KeyGenerator::generateTablesInfoKey(const std::string &context) { - std::map fv_map = { - {"context", context} - }; + std::map fv_map = {{"context", context}}; return generateKey(fv_map); } diff --git a/orchagent/p4orch/p4orch_util.h b/orchagent/p4orch/p4orch_util.h index f95a9fd8eb..9cfcf53a82 100644 --- a/orchagent/p4orch/p4orch_util.h +++ b/orchagent/p4orch/p4orch_util.h @@ -5,8 +5,8 @@ #include #include #include -#include #include +#include #include "ipaddress.h" #include "ipprefix.h" @@ -16,7 +16,6 @@ extern "C" { #include "saitypes.h" } - namespace p4orch { @@ -110,48 +109,48 @@ std::string prependParamField(const std::string &str); struct ActionParamInfo { - std::string name; - std::string fieldtype; - std::string datatype; - std::unordered_map table_reference_map; + std::string name; + std::string fieldtype; + std::string datatype; + std::unordered_map table_reference_map; }; struct ActionInfo { - std::string name; + std::string name; std::unordered_map params; - bool refers_to; + bool refers_to; }; struct TableMatchInfo { - std::string name; - std::string fieldtype; - std::string datatype; - std::unordered_map table_reference_map; + std::string name; + std::string fieldtype; + std::string datatype; + std::unordered_map table_reference_map; }; /** - * Dervied table definition + * Dervied table definition * This is a derived state out of table definition provided by P4RT-APP */ struct TableInfo { - std::string name; - int id; - int precedence; - std::unordered_map match_fields; - std::unordered_map action_fields; - bool counter_bytes_enabled; - bool counter_packets_enabled; - std::vector action_ref_tables; - // list of tables across all actions, of current table, refer to + std::string name; + int id; + int precedence; + std::unordered_map match_fields; + std::unordered_map action_fields; + bool counter_bytes_enabled; + bool counter_packets_enabled; + std::vector action_ref_tables; + // list of tables across all actions, of current table, refer to }; /** * table-name to table-definition map */ -typedef std::unordered_map TableInfoMap; +typedef std::unordered_map TableInfoMap; struct TablesInfoAppDbEntry { @@ -159,7 +158,6 @@ struct TablesInfoAppDbEntry std::string info; }; - struct P4RouterInterfaceAppDbEntry { std::string router_interface_id; @@ -296,8 +294,8 @@ struct P4AclRuleAppDbEntry struct DepObject { sai_object_type_t sai_object; - std::string key; - sai_object_id_t oid; + std::string key; + sai_object_id_t oid; }; struct P4ExtTableAppDbEntry @@ -309,7 +307,6 @@ struct P4ExtTableAppDbEntry std::unordered_map action_dep_objects; }; - TableInfo *getTableInfo(const std::string &table_name); ActionInfo *getTableActionInfo(TableInfo *table, const std::string &action_name); diff --git a/orchagent/p4orch/route_manager.cpp b/orchagent/p4orch/route_manager.cpp index bc8f3bbcd8..1e69de5d17 100644 --- a/orchagent/p4orch/route_manager.cpp +++ b/orchagent/p4orch/route_manager.cpp @@ -11,12 +11,12 @@ #include "converter.h" #include "crmorch.h" #include "dbconnector.h" -#include #include "logger.h" #include "p4orch/p4orch_util.h" #include "sai_serialize.h" #include "swssnet.h" #include "table.h" +#include using ::p4orch::kTableKeyDelimiter; @@ -837,7 +837,8 @@ std::vector RouteManager::deleteRouteEntries(const std::vector &tuple) override; - ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; private: // Applies route entry updates from src to dest. The merged result will be diff --git a/orchagent/p4orch/router_interface_manager.cpp b/orchagent/p4orch/router_interface_manager.cpp index e174b5ec7e..8074cc49ec 100644 --- a/orchagent/p4orch/router_interface_manager.cpp +++ b/orchagent/p4orch/router_interface_manager.cpp @@ -10,7 +10,6 @@ #include "SaiAttributeList.h" #include "dbconnector.h" #include "directory.h" -#include #include "logger.h" #include "orch.h" #include "p4orch/p4orch_util.h" @@ -18,6 +17,7 @@ #include "sai_serialize.h" #include "table.h" #include "vrforch.h" +#include using ::p4orch::kTableKeyDelimiter; @@ -337,13 +337,14 @@ ReturnCode RouterInterfaceManager::processDeleteRequest(const std::string &route return status; } -ReturnCode RouterInterfaceManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) +ReturnCode RouterInterfaceManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) { - std::string value; + std::string value; try { - nlohmann::json j = nlohmann::json::parse(json_key); + nlohmann::json j = nlohmann::json::parse(json_key); if (j.find(prependMatchField(p4orch::kRouterInterfaceId)) != j.end()) { value = j.at(prependMatchField(p4orch::kRouterInterfaceId)).get(); @@ -353,7 +354,8 @@ ReturnCode RouterInterfaceManager::getSaiObject(const std::string &json_key, sai } else { - SWSS_LOG_ERROR("%s match parameter absent: required for dependent object query", p4orch::kRouterInterfaceId); + SWSS_LOG_ERROR("%s match parameter absent: required for dependent object query", + p4orch::kRouterInterfaceId); } } catch (std::exception &ex) diff --git a/orchagent/p4orch/router_interface_manager.h b/orchagent/p4orch/router_interface_manager.h index 427400e9c0..f33f443979 100644 --- a/orchagent/p4orch/router_interface_manager.h +++ b/orchagent/p4orch/router_interface_manager.h @@ -52,7 +52,8 @@ class RouterInterfaceManager : public ObjectManagerInterface void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; void drain() override; std::string verifyState(const std::string &key, const std::vector &tuple) override; - ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; private: ReturnCodeOr deserializeRouterIntfEntry( diff --git a/orchagent/p4orch/tables_definition_manager.cpp b/orchagent/p4orch/tables_definition_manager.cpp index c0fab4265a..7790458cfc 100644 --- a/orchagent/p4orch/tables_definition_manager.cpp +++ b/orchagent/p4orch/tables_definition_manager.cpp @@ -7,30 +7,23 @@ #include #include "directory.h" -#include #include "logger.h" -#include "tokenize.h" #include "orch.h" #include "p4orch/p4orch.h" #include "p4orch/p4orch_util.h" +#include "tokenize.h" +#include extern "C" { #include "saitypes.h" } - extern Directory gDirectory; extern P4Orch *gP4Orch; -const std::map format_datatype_map = -{ - {"MAC", "SAI_ATTR_VALUE_TYPE_MAC"}, - {"IPV4", "SAI_ATTR_VALUE_TYPE_IPV4"}, - {"IPV6", "SAI_ATTR_VALUE_TYPE_IPV6"} -}; +const std::map format_datatype_map = { + {"MAC", "SAI_ATTR_VALUE_TYPE_MAC"}, {"IPV4", "SAI_ATTR_VALUE_TYPE_IPV4"}, {"IPV6", "SAI_ATTR_VALUE_TYPE_IPV6"}}; - -std::string -BitwidthToDatatype (int bitwidth) +std::string BitwidthToDatatype(int bitwidth) { std::string datatype = "SAI_ATTR_VALUE_TYPE_CHARDATA"; @@ -58,8 +51,7 @@ BitwidthToDatatype (int bitwidth) return datatype; } -std::string -parseBitwidthToDatatype (const nlohmann::json &json) +std::string parseBitwidthToDatatype(const nlohmann::json &json) { int bitwidth; std::string datatype = "SAI_ATTR_VALUE_TYPE_CHARDATA"; @@ -73,8 +65,7 @@ parseBitwidthToDatatype (const nlohmann::json &json) return datatype; } -std::string -parseFormatToDatatype (const nlohmann::json &json, std::string datatype) +std::string parseFormatToDatatype(const nlohmann::json &json, std::string datatype) { std::string format; @@ -92,8 +83,7 @@ parseFormatToDatatype (const nlohmann::json &json, std::string datatype) return datatype; } -ReturnCode -parseTableMatchReferences (const nlohmann::json &match_json, TableMatchInfo &match) +ReturnCode parseTableMatchReferences(const nlohmann::json &match_json, TableMatchInfo &match) { std::string table, field; @@ -110,7 +100,7 @@ parseTableMatchReferences (const nlohmann::json &match_json, TableMatchInfo &mat catch (std::exception &ex) { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "can not parse tables from app-db supplied table definition info"; + << "can not parse tables from app-db supplied table definition info"; } } } @@ -118,8 +108,7 @@ parseTableMatchReferences (const nlohmann::json &match_json, TableMatchInfo &mat return ReturnCode(); } -ReturnCode -parseActionParamReferences (const nlohmann::json ¶m_json, ActionParamInfo ¶m) +ReturnCode parseActionParamReferences(const nlohmann::json ¶m_json, ActionParamInfo ¶m) { std::string table, field; @@ -136,7 +125,7 @@ parseActionParamReferences (const nlohmann::json ¶m_json, ActionParamInfo &p catch (std::exception &ex) { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "can not parse tables from app-db supplied table definition info"; + << "can not parse tables from app-db supplied table definition info"; } } } @@ -144,8 +133,7 @@ parseActionParamReferences (const nlohmann::json ¶m_json, ActionParamInfo &p return ReturnCode(); } -ReturnCode -parseTableActionParams (const nlohmann::json &action_json, ActionInfo &action) +ReturnCode parseTableActionParams(const nlohmann::json &action_json, ActionInfo &action) { action.refers_to = false; if (action_json.find(p4orch::kActionParams) != action_json.end()) @@ -175,7 +163,7 @@ parseTableActionParams (const nlohmann::json &action_json, ActionInfo &action) catch (std::exception &ex) { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "can not parse tables from app-db supplied table definition info"; + << "can not parse tables from app-db supplied table definition info"; } } } @@ -183,8 +171,7 @@ parseTableActionParams (const nlohmann::json &action_json, ActionInfo &action) return ReturnCode(); } -ReturnCode -parseTableCounter (const nlohmann::json &table_json, TableInfo &table) +ReturnCode parseTableCounter(const nlohmann::json &table_json, TableInfo &table) { if (table_json.find(p4orch::kCounterUnit) != table_json.end()) { @@ -207,8 +194,7 @@ parseTableCounter (const nlohmann::json &table_json, TableInfo &table) return ReturnCode(); } -ReturnCode -parseTablesInfo (const nlohmann::json &info_json, TablesInfo &info_entry) +ReturnCode parseTablesInfo(const nlohmann::json &info_json, TablesInfo &info_entry) { ReturnCode status; int table_id; @@ -216,8 +202,7 @@ parseTablesInfo (const nlohmann::json &info_json, TablesInfo &info_entry) if (info_json.find(p4orch::kTables) == info_json.end()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "no tables in app-db supplied table definition info"; + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "no tables in app-db supplied table definition info"; } for (const auto &table_json : info_json[p4orch::kTables]) @@ -230,18 +215,17 @@ parseTablesInfo (const nlohmann::json &info_json, TablesInfo &info_entry) catch (std::exception &ex) { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "can not parse tables from app-db supplied table definition info"; + << "can not parse tables from app-db supplied table definition info"; } - - TableInfo table = {}; + TableInfo table = {}; table.name = table_name; - table.id = table_id; + table.id = table_id; try { for (const auto &match_json : table_json[p4orch::kmatchFields]) { - TableMatchInfo match = {}; + TableMatchInfo match = {}; std::string match_name; match_name = match_json.at(p4orch::kName).get(); @@ -254,7 +238,7 @@ parseTablesInfo (const nlohmann::json &info_json, TablesInfo &info_entry) for (const auto &action_json : table_json[p4orch::kActions]) { - ActionInfo action = {}; + ActionInfo action = {}; std::string action_name; action_name = action_json.at(p4orch::kAlias).get(); @@ -266,20 +250,18 @@ parseTablesInfo (const nlohmann::json &info_json, TablesInfo &info_entry) * If any parameter of action refers to another table, add that one in the * cross-reference list of current table */ - for (auto param_it = action.params.begin(); - param_it != action.params.end(); param_it++) + for (auto param_it = action.params.begin(); param_it != action.params.end(); param_it++) { ActionParamInfo action_param = param_it->second; for (auto ref_it = action_param.table_reference_map.begin(); - ref_it != action_param.table_reference_map.end(); ref_it++) + ref_it != action_param.table_reference_map.end(); ref_it++) { - if (std::find(table.action_ref_tables.begin(), - table.action_ref_tables.end(), - ref_it->first) == table.action_ref_tables.end()) + if (std::find(table.action_ref_tables.begin(), table.action_ref_tables.end(), ref_it->first) == + table.action_ref_tables.end()) { table.action_ref_tables.push_back(ref_it->first); } - } + } } } @@ -288,10 +270,9 @@ parseTablesInfo (const nlohmann::json &info_json, TablesInfo &info_entry) catch (std::exception &ex) { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "can not parse table " << QuotedVar(table_name.c_str()) << "match fields"; + << "can not parse table " << QuotedVar(table_name.c_str()) << "match fields"; } - info_entry.m_tableIdNameMap[std::to_string(table_id)] = table_name; info_entry.m_tableInfoMap[table_name] = table; } @@ -299,7 +280,6 @@ parseTablesInfo (const nlohmann::json &info_json, TablesInfo &info_entry) return ReturnCode(); } - ReturnCodeOr TablesDefnManager::deserializeTablesInfoEntry( const std::string &key, const std::vector &attributes) { @@ -327,7 +307,7 @@ ReturnCodeOr TablesDefnManager::deserializeTablesInfoEntry else { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unexpected field " << QuotedVar(field) << " in table entry"; + << "Unexpected field " << QuotedVar(field) << " in table entry"; } } @@ -416,14 +396,13 @@ ReturnCode TablesDefnManager::processDeleteRequest(const std::string &context_ke return ReturnCode(); } -ReturnCode TablesDefnManager::getSaiObject(const std::string &json_key, - sai_object_type_t &object_type, std::string &object_key) +ReturnCode TablesDefnManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) { return StatusCode::SWSS_RC_INVALID_PARAM; } -std::unordered_map> -createGraph (std::vector> preReq) +std::unordered_map> createGraph(std::vector> preReq) { std::unordered_map> graph; @@ -443,8 +422,7 @@ createGraph (std::vector> preReq) return graph; } -std::unordered_map -computeIndegree (std::unordered_map> &graph) +std::unordered_map computeIndegree(std::unordered_map> &graph) { std::unordered_map degrees; @@ -467,19 +445,16 @@ computeIndegree (std::unordered_map> &graph) return degrees; } - -std::vector -findTablePrecedence (int tables, std::vector> preReq, TablesInfo *tables_info) +std::vector findTablePrecedence(int tables, std::vector> preReq, TablesInfo *tables_info) { std::unordered_map> graph = createGraph(preReq); std::unordered_map degrees = computeIndegree(graph); std::vector visited; std::vector toposort; - std::queue zeros; + std::queue zeros; // initialize queue with tables having no dependencies - for (auto table_it = tables_info->m_tableInfoMap.begin(); - table_it != tables_info->m_tableInfoMap.end(); table_it++) + for (auto table_it = tables_info->m_tableInfoMap.begin(); table_it != tables_info->m_tableInfoMap.end(); table_it++) { TableInfo table_info = table_it->second; if (degrees.find(table_info.id) == degrees.end()) @@ -530,21 +505,19 @@ findTablePrecedence (int tables, std::vector> preReq, Tables return toposort; } - -void -buildTablePrecedence (TablesInfo *tables_info) +void buildTablePrecedence(TablesInfo *tables_info) { std::vector> preReq; std::vector orderedTables; int tables = 0; - if (!tables_info) { + if (!tables_info) + { return; } // build dependencies - for (auto table_it = tables_info->m_tableInfoMap.begin(); - table_it != tables_info->m_tableInfoMap.end(); table_it++) + for (auto table_it = tables_info->m_tableInfoMap.begin(); table_it != tables_info->m_tableInfoMap.end(); table_it++) { TableInfo table_info = table_it->second; tables++; @@ -552,18 +525,18 @@ buildTablePrecedence (TablesInfo *tables_info) for (std::size_t i = 0; i < table_info.action_ref_tables.size(); i++) { /** - * For now processing precedence order is only amongst extension tables - * Skip fixed tables, include them in precedence calculations when fixed - * and extension tables processing precedence may be interleaved - */ + * For now processing precedence order is only amongst extension tables + * Skip fixed tables, include them in precedence calculations when fixed + * and extension tables processing precedence may be interleaved + */ if (FixedTablesMap.find(table_info.action_ref_tables[i]) != FixedTablesMap.end()) { continue; } TableInfo ref_table_info = tables_info->m_tableInfoMap[table_info.action_ref_tables[i]]; - if (std::find(preReq.begin(), preReq.end(), - std::make_pair(table_info.id, ref_table_info.id)) == preReq.end()) + if (std::find(preReq.begin(), preReq.end(), std::make_pair(table_info.id, ref_table_info.id)) == + preReq.end()) { preReq.push_back(std::make_pair(table_info.id, ref_table_info.id)); } @@ -596,7 +569,6 @@ buildTablePrecedence (TablesInfo *tables_info) return; } - void TablesDefnManager::enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) { m_entries.push_back(entry); @@ -672,8 +644,8 @@ void TablesDefnManager::drain() { buildTablePrecedence(gP4Orch->tablesinfo); } - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), - status, /*replace=*/true); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), status, + /*replace=*/true); } m_entries.clear(); } diff --git a/orchagent/p4orch/tables_definition_manager.h b/orchagent/p4orch/tables_definition_manager.h index 088b832bcd..ffe8b62857 100644 --- a/orchagent/p4orch/tables_definition_manager.h +++ b/orchagent/p4orch/tables_definition_manager.h @@ -6,13 +6,13 @@ #include #include "macaddress.h" -#include #include "orch.h" #include "p4orch/object_manager_interface.h" #include "p4orch/p4oidmapper.h" #include "p4orch/p4orch_util.h" #include "response_publisher_interface.h" #include "return_code.h" +#include extern "C" { #include "sai.h" @@ -23,13 +23,13 @@ extern "C" */ struct TablesInfo { - std::string context; - nlohmann::json info; + std::string context; + nlohmann::json info; std::unordered_map m_tableIdNameMap; std::unordered_map m_tableInfoMap; std::map m_tablePrecedenceMap; - TablesInfo() {}; + TablesInfo(){}; TablesInfo(const std::string &context_key, const nlohmann::json &info_value) : context(context_key), info(info_value) { @@ -59,11 +59,12 @@ class TablesDefnManager : public ObjectManagerInterface void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; void drain() override; std::string verifyState(const std::string &key, const std::vector &tuple) override; - ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; private: - ReturnCodeOr deserializeTablesInfoEntry( - const std::string &key, const std::vector &attributes); + ReturnCodeOr deserializeTablesInfoEntry(const std::string &key, + const std::vector &attributes); TablesInfo *getTablesInfoEntry(const std::string &context_key); ReturnCode createTablesInfo(const std::string &context_key, TablesInfo &tablesinfo_entry); ReturnCode removeTablesInfo(const std::string &context_key); diff --git a/orchagent/p4orch/tests/acl_manager_test.cpp b/orchagent/p4orch/tests/acl_manager_test.cpp index 5827fd1a13..515cab853f 100644 --- a/orchagent/p4orch/tests/acl_manager_test.cpp +++ b/orchagent/p4orch/tests/acl_manager_test.cpp @@ -9,7 +9,6 @@ #include "acl_table_manager.h" #include "acl_util.h" #include "acltable.h" -#include #include "mock_sai_acl.h" #include "mock_sai_hostif.h" #include "mock_sai_policer.h" @@ -22,6 +21,7 @@ #include "table.h" #include "tokenize.h" #include "vrforch.h" +#include using ::p4orch::kTableKeyDelimiter; diff --git a/orchagent/p4orch/tests/fake_flexcounterorch.cpp b/orchagent/p4orch/tests/fake_flexcounterorch.cpp index 39f742e14c..91d6be3d14 100644 --- a/orchagent/p4orch/tests/fake_flexcounterorch.cpp +++ b/orchagent/p4orch/tests/fake_flexcounterorch.cpp @@ -1,12 +1,10 @@ #include "copporch.h" #include "flexcounterorch.h" -FlexCounterOrch::FlexCounterOrch(swss::DBConnector *db, std::vector &tableNames) : - Orch(db, tableNames), - m_flexCounterConfigTable(db, CFG_FLEX_COUNTER_TABLE_NAME), - m_bufferQueueConfigTable(db, CFG_BUFFER_QUEUE_TABLE_NAME), - m_bufferPgConfigTable(db, CFG_BUFFER_PG_TABLE_NAME), - m_deviceMetadataConfigTable(db, CFG_DEVICE_METADATA_TABLE_NAME) +FlexCounterOrch::FlexCounterOrch(swss::DBConnector *db, std::vector &tableNames) + : Orch(db, tableNames), m_flexCounterConfigTable(db, CFG_FLEX_COUNTER_TABLE_NAME), + m_bufferQueueConfigTable(db, CFG_BUFFER_QUEUE_TABLE_NAME), m_bufferPgConfigTable(db, CFG_BUFFER_PG_TABLE_NAME), + m_deviceMetadataConfigTable(db, CFG_DEVICE_METADATA_TABLE_NAME) { } diff --git a/orchagent/p4orch/tests/fake_portorch.cpp b/orchagent/p4orch/tests/fake_portorch.cpp index b8a2f56fde..a34a30eb4b 100644 --- a/orchagent/p4orch/tests/fake_portorch.cpp +++ b/orchagent/p4orch/tests/fake_portorch.cpp @@ -185,7 +185,7 @@ void PortsOrch::generateQueueMap(std::map queues { } -void PortsOrch::generateQueueMapPerPort(const Port& port, FlexCounterQueueStates& queuesState, bool voq) +void PortsOrch::generateQueueMapPerPort(const Port &port, FlexCounterQueueStates &queuesState, bool voq) { } @@ -201,15 +201,15 @@ void PortsOrch::generatePriorityGroupMap(std::map p { } -void PortsOrch::generatePriorityGroupMapPerPort(const Port& port, FlexCounterPgStates& pgsState) +void PortsOrch::generatePriorityGroupMapPerPort(const Port &port, FlexCounterPgStates &pgsState) { } -void PortsOrch::createPortBufferPgCounters(const Port& port, string pgs) +void PortsOrch::createPortBufferPgCounters(const Port &port, string pgs) { } -void PortsOrch::removePortBufferPgCounters(const Port& port, string pgs) +void PortsOrch::removePortBufferPgCounters(const Port &port, string pgs) { } @@ -591,7 +591,8 @@ bool PortsOrch::setGearboxPortsAttr(const Port &port, sai_port_attr_t id, void * return true; } -bool PortsOrch::setGearboxPortAttr(const Port &port, dest_port_type_t port_type, sai_port_attr_t id, void *value, bool override_fec) +bool PortsOrch::setGearboxPortAttr(const Port &port, dest_port_type_t port_type, sai_port_attr_t id, void *value, + bool override_fec) { return true; } @@ -621,7 +622,8 @@ task_process_status PortsOrch::setPortInterfaceType(Port &port, sai_port_interfa return task_success; } -task_process_status PortsOrch::setPortAdvInterfaceTypes(Port &port, std::set &interface_types) +task_process_status PortsOrch::setPortAdvInterfaceTypes(Port &port, + std::set &interface_types) { return task_success; } diff --git a/orchagent/p4orch/tests/gre_tunnel_manager_test.cpp b/orchagent/p4orch/tests/gre_tunnel_manager_test.cpp index 2ba915d9c0..f546e09ef7 100644 --- a/orchagent/p4orch/tests/gre_tunnel_manager_test.cpp +++ b/orchagent/p4orch/tests/gre_tunnel_manager_test.cpp @@ -8,7 +8,6 @@ #include #include "ipaddress.h" -#include #include "mock_response_publisher.h" #include "mock_sai_router_interface.h" #include "mock_sai_serialize.h" @@ -18,6 +17,7 @@ #include "p4orch_util.h" #include "return_code.h" #include "swssnet.h" +#include extern "C" { #include "sai.h" diff --git a/orchagent/p4orch/tests/l3_admit_manager_test.cpp b/orchagent/p4orch/tests/l3_admit_manager_test.cpp index 33f88d1839..8b246050c9 100644 --- a/orchagent/p4orch/tests/l3_admit_manager_test.cpp +++ b/orchagent/p4orch/tests/l3_admit_manager_test.cpp @@ -7,13 +7,13 @@ #include #include -#include #include "mock_response_publisher.h" #include "mock_sai_my_mac.h" #include "p4oidmapper.h" #include "p4orch/p4orch_util.h" #include "p4orch_util.h" #include "return_code.h" +#include extern "C" { #include "sai.h" diff --git a/orchagent/p4orch/tests/mirror_session_manager_test.cpp b/orchagent/p4orch/tests/mirror_session_manager_test.cpp index e137681930..503060e231 100644 --- a/orchagent/p4orch/tests/mirror_session_manager_test.cpp +++ b/orchagent/p4orch/tests/mirror_session_manager_test.cpp @@ -6,7 +6,6 @@ #include #include -#include #include "mock_response_publisher.h" #include "mock_sai_mirror.h" #include "p4oidmapper.h" @@ -15,6 +14,7 @@ #include "swss/ipaddress.h" #include "swss/macaddress.h" #include "swssnet.h" +#include extern "C" { #include "sai.h" diff --git a/orchagent/p4orch/tests/neighbor_manager_test.cpp b/orchagent/p4orch/tests/neighbor_manager_test.cpp index f335c8295f..8dd62615c8 100644 --- a/orchagent/p4orch/tests/neighbor_manager_test.cpp +++ b/orchagent/p4orch/tests/neighbor_manager_test.cpp @@ -6,13 +6,13 @@ #include #include -#include #include "mock_response_publisher.h" #include "mock_sai_neighbor.h" #include "p4orch.h" #include "p4orch/p4orch_util.h" #include "return_code.h" #include "swssnet.h" +#include using ::p4orch::kTableKeyDelimiter; diff --git a/orchagent/p4orch/tests/next_hop_manager_test.cpp b/orchagent/p4orch/tests/next_hop_manager_test.cpp index 620474f1a1..cc01c82920 100644 --- a/orchagent/p4orch/tests/next_hop_manager_test.cpp +++ b/orchagent/p4orch/tests/next_hop_manager_test.cpp @@ -8,7 +8,6 @@ #include #include "ipaddress.h" -#include #include "mock_response_publisher.h" #include "mock_sai_hostif.h" #include "mock_sai_next_hop.h" @@ -18,6 +17,7 @@ #include "p4orch.h" #include "return_code.h" #include "swssnet.h" +#include extern "C" { #include "sai.h" diff --git a/orchagent/p4orch/tests/route_manager_test.cpp b/orchagent/p4orch/tests/route_manager_test.cpp index bd03f357cf..67b4b4f7c9 100644 --- a/orchagent/p4orch/tests/route_manager_test.cpp +++ b/orchagent/p4orch/tests/route_manager_test.cpp @@ -9,7 +9,6 @@ #include #include "ipprefix.h" -#include #include "mock_response_publisher.h" #include "mock_sai_route.h" #include "p4orch.h" @@ -17,6 +16,7 @@ #include "return_code.h" #include "swssnet.h" #include "vrforch.h" +#include using ::p4orch::kTableKeyDelimiter; diff --git a/orchagent/p4orch/tests/test_main.cpp b/orchagent/p4orch/tests/test_main.cpp index 787e0622f4..0170588a42 100644 --- a/orchagent/p4orch/tests/test_main.cpp +++ b/orchagent/p4orch/tests/test_main.cpp @@ -99,7 +99,6 @@ bool parseHandleSaiStatusFailure(task_process_status status) return true; } - namespace { @@ -173,7 +172,7 @@ void AddVrf() } // namespace int main(int argc, char *argv[]) -{ +{ gBatchSize = DEFAULT_BATCH_SIZE; testing::InitGoogleTest(&argc, argv); diff --git a/orchagent/p4orch/tests/wcmp_manager_test.cpp b/orchagent/p4orch/tests/wcmp_manager_test.cpp index c3aaeb6217..29897d5d06 100644 --- a/orchagent/p4orch/tests/wcmp_manager_test.cpp +++ b/orchagent/p4orch/tests/wcmp_manager_test.cpp @@ -5,7 +5,6 @@ #include -#include #include "mock_response_publisher.h" #include "mock_sai_acl.h" #include "mock_sai_hostif.h" @@ -18,6 +17,7 @@ #include "p4orch_util.h" #include "return_code.h" #include "sai_serialize.h" +#include extern "C" { #include "sai.h" diff --git a/orchagent/p4orch/wcmp_manager.cpp b/orchagent/p4orch/wcmp_manager.cpp index 67d87f1373..d81ce1d44e 100644 --- a/orchagent/p4orch/wcmp_manager.cpp +++ b/orchagent/p4orch/wcmp_manager.cpp @@ -7,12 +7,12 @@ #include "SaiAttributeList.h" #include "crmorch.h" #include "dbconnector.h" -#include #include "logger.h" #include "p4orch/p4orch_util.h" #include "portsorch.h" #include "sai_serialize.h" #include "table.h" +#include extern "C" { #include "sai.h" @@ -734,13 +734,14 @@ void WcmpManager::updatePortOperStatusMap(const std::string &port, const sai_por port_oper_status_map[port] = status; } -ReturnCode WcmpManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) +ReturnCode WcmpManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) { - std::string value; + std::string value; try { - nlohmann::json j = nlohmann::json::parse(json_key); + nlohmann::json j = nlohmann::json::parse(json_key); if (j.find(prependMatchField(p4orch::kWcmpGroupId)) != j.end()) { value = j.at(prependMatchField(p4orch::kWcmpGroupId)).get(); diff --git a/orchagent/p4orch/wcmp_manager.h b/orchagent/p4orch/wcmp_manager.h index 64fd4283e4..7d533bf28f 100644 --- a/orchagent/p4orch/wcmp_manager.h +++ b/orchagent/p4orch/wcmp_manager.h @@ -72,7 +72,8 @@ class WcmpManager : public ObjectManagerInterface void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; void drain() override; std::string verifyState(const std::string &key, const std::vector &tuple) override; - ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, std::string &object_key) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; // Prunes next hop members egressing through the given port. void pruneNextHops(const std::string &port); diff --git a/orchagent/response_publisher.cpp b/orchagent/response_publisher.cpp index 031f1aefef..d5b94a586d 100644 --- a/orchagent/response_publisher.cpp +++ b/orchagent/response_publisher.cpp @@ -50,7 +50,7 @@ void RecordResponse(const std::string &response_channel, const std::string &key, { if (!swss::Recorder::Instance().respub.isRecord()) { - return; + return; } std::string s = response_channel + ":" + key + "|" + status; @@ -64,10 +64,9 @@ void RecordResponse(const std::string &response_channel, const std::string &key, } // namespace -ResponsePublisher::ResponsePublisher(bool buffered) : - m_db(std::make_unique("APPL_STATE_DB", 0)), - m_pipe(std::make_unique(m_db.get())), - m_buffered(buffered) +ResponsePublisher::ResponsePublisher(bool buffered) + : m_db(std::make_unique("APPL_STATE_DB", 0)), + m_pipe(std::make_unique(m_db.get())), m_buffered(buffered) { } diff --git a/orchagent/response_publisher.h b/orchagent/response_publisher.h index ff7bd291e4..985532e827 100644 --- a/orchagent/response_publisher.h +++ b/orchagent/response_publisher.h @@ -7,9 +7,9 @@ #include "dbconnector.h" #include "notificationproducer.h" +#include "recorder.h" #include "response_publisher_interface.h" #include "table.h" -#include "recorder.h" // This class performs two tasks when publish is called: // 1. Sends a notification into the redis channel. @@ -46,14 +46,14 @@ class ResponsePublisher : public ResponsePublisherInterface /** * @brief Flush pending responses - */ + */ void flush(); /** * @brief Set buffering mode * * @param buffered Flag whether responses are buffered - */ + */ void setBuffered(bool buffered); private: From 465399e9daba2ea437a9f095649f2e5b6a4c1241 Mon Sep 17 00:00:00 2001 From: Deepak Singhal <115033986+deepak-singhal0408@users.noreply.github.com> Date: Tue, 2 Apr 2024 08:53:44 -0700 Subject: [PATCH 06/34] T2-VOQ-VS: Fix iBGP bringup issue (#3053) * Fix iBGP bringup issue T2-vswitch * On T2-VOQ chassis Emulation with multi-asic linecards, iBGP sessions dont come up. Related Issue: sonic-net/sonic-buildimage#18129 --- orchagent/neighorch.cpp | 37 ++++------------------------------- tests/test_virtual_chassis.py | 14 +++++-------- 2 files changed, 9 insertions(+), 42 deletions(-) diff --git a/orchagent/neighorch.cpp b/orchagent/neighorch.cpp index 4008fb81fb..a2bdebbc62 100644 --- a/orchagent/neighorch.cpp +++ b/orchagent/neighorch.cpp @@ -1385,7 +1385,7 @@ void NeighOrch::doVoqSystemNeighTask(Consumer &consumer) continue; } - MacAddress mac_address; + MacAddress mac_address, original_mac_address; uint32_t encap_index = 0; for (auto i = kfvFieldsValues(t).begin(); i != kfvFieldsValues(t).end(); i++) @@ -1465,42 +1465,13 @@ void NeighOrch::doVoqSystemNeighTask(Consumer &consumer) //kernel programming. if(ibif.m_type != Port::VLAN) { + original_mac_address = mac_address; mac_address = gMacAddress; - - // For VS platforms, the mac of the static neigh should not be same as asic's own mac. - // This is because host originated packets will have same mac for both src and dst which - // will result in host NOT sending packet out. To address this problem which is specific - // to port type inband interfaces, set the mac to the neighbor's owner asic's mac. Since - // the owner asic's mac is not readily avaiable here, the owner asic mac is derived from - // the switch id and lower 5 bytes of asic mac which is assumed to be same for all asics - // in the VS system. - // Therefore to make VOQ chassis systems work in VS platform based setups like the setups - // using KVMs, it is required that all asics have same base mac in the format given below - // :<6th byte = switch_id> - string platform = getenv("ASIC_VENDOR") ? getenv("ASIC_VENDOR") : ""; - + // For VS platform, use the original MAC address if (platform == VS_PLATFORM_SUBSTRING) { - int8_t sw_id = -1; - uint8_t egress_asic_mac[ETHER_ADDR_LEN]; - - gMacAddress.getMac(egress_asic_mac); - - if (p.m_type == Port::LAG) - { - sw_id = (int8_t) p.m_system_lag_info.switch_id; - } - else if (p.m_type == Port::PHY || p.m_type == Port::SYSTEM) - { - sw_id = (int8_t) p.m_system_port_info.switch_id; - } - - if(sw_id != -1) - { - egress_asic_mac[5] = sw_id; - mac_address = MacAddress(egress_asic_mac); - } + mac_address = original_mac_address; } } vector fvVector; diff --git a/tests/test_virtual_chassis.py b/tests/test_virtual_chassis.py index c92ed88c40..5401f6870f 100644 --- a/tests/test_virtual_chassis.py +++ b/tests/test_virtual_chassis.py @@ -5,6 +5,8 @@ import pytest import buffer_model +DVS_ENV = ["ASIC_VENDOR=vs"] + class TestVirtualChassis(object): def set_lag_id_boundaries(self, vct): @@ -138,7 +140,6 @@ def test_voq_switch(self, vct): spcfg = ast.literal_eval(value) assert spcfg['count'] == sp_count, "Number of systems ports configured is invalid" - @pytest.mark.skip(reason="Failing. Under investigation") def test_chassis_app_db_sync(self, vct): """Test chassis app db syncing. @@ -159,7 +160,6 @@ def test_chassis_app_db_sync(self, vct): keys = chassis_app_db.get_keys("SYSTEM_INTERFACE") assert len(keys), "No chassis app db syncing is done" - @pytest.mark.skip(reason="Failing. Under investigation") def test_chassis_system_interface(self, vct): """Test RIF record creation in ASIC_DB for remote interfaces. @@ -216,7 +216,6 @@ def test_chassis_system_interface(self, vct): # Remote system ports's switch id should not match local switch id assert spcfginfo["attached_switch_id"] != lc_switch_id, "RIF system port with wrong switch_id" - @pytest.mark.skip(reason="Failing. Under investigation") def test_chassis_system_neigh(self, vct): """Test neigh record create/delete and syncing to chassis app db. @@ -312,8 +311,8 @@ def chassis_system_neigh_create(): test_sysneigh = "" for sysnk in sysneighkeys: sysnk_tok = sysnk.split("|") - assert len(sysnk_tok) == 3, "Invalid system neigh key in chassis app db" - if sysnk_tok[2] == test_neigh_ip: + assert len(sysnk_tok) == 4, "Invalid system neigh key in chassis app db" + if sysnk_tok[3] == test_neigh_ip: test_sysneigh = sysnk break @@ -372,7 +371,7 @@ def chassis_system_neigh_create(): # Check for kernel entries _, output = dvs.runcmd("ip neigh show") - assert f"{test_neigh_ip} dev {inband_port}" in output, "Kernel neigh not found for remote neighbor" + assert f"{test_neigh_ip} dev {inband_port} lladdr {mac_address}" in output, "Kernel neigh not found for remote neighbor" _, output = dvs.runcmd("ip route show") assert f"{test_neigh_ip} dev {inband_port} scope link" in output, "Kernel route not found for remote neighbor" @@ -487,7 +486,6 @@ def chassis_system_neigh_create(): # Cleanup inband if configuration self.del_inbandif_port(vct, inband_port) - @pytest.mark.skip(reason="Failing. Under investigation") def test_chassis_system_lag(self, vct): """Test PortChannel in VOQ based chassis systems. @@ -624,7 +622,6 @@ def test_chassis_system_lag(self, vct): break - @pytest.mark.skip(reason="Failing. Under investigation") def test_chassis_system_lag_id_allocator_table_full(self, vct): """Test lag id allocator table full. @@ -702,7 +699,6 @@ def test_chassis_system_lag_id_allocator_table_full(self, vct): break - @pytest.mark.skip(reason="Failing. Under investigation") def test_chassis_system_lag_id_allocator_del_id(self, vct): """Test lag id allocator's release id and re-use id processing. From 2a586154504bc3924e0cec21ee63d0ac9df0a4d6 Mon Sep 17 00:00:00 2001 From: KISHORE KUNAL <64033340+kishorekunal01@users.noreply.github.com> Date: Wed, 3 Apr 2024 16:42:14 -0700 Subject: [PATCH 07/34] [Fdbsyncd] Adding extern_learn flag with fdb entry so Kernel doesn't age out (#2985) * Adding extern_learn flag with fdb entry so that Kernel doesn't age out the MAC * [Fdbsyncd] Adding extern_learn flag with fdb entry so Kernel doesn't age out What I did extern_learn flag is added while programming the fdb entry into the Kernel. This will make sure that kernel doesn't age out the fdb entry. (#15004) How I did it A flag extern_learn will be passed while programing the fdb entry. (#15004) How to verify it Tested MAC add/del to the Kernel from the local FDB entry. (#15004) Signed-off-by: kishore.kunal@broadcom.com --------- Signed-off-by: kishore.kunal@broadcom.com Co-authored-by: Sudharsan Dhamal Gopalarathnam --- fdbsyncd/fdbsync.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fdbsyncd/fdbsync.cpp b/fdbsyncd/fdbsync.cpp index 0d71f721dc..3c1fae145a 100644 --- a/fdbsyncd/fdbsync.cpp +++ b/fdbsyncd/fdbsync.cpp @@ -324,7 +324,7 @@ void FdbSync::updateLocalMac (struct m_fdb_info *info) if (fdb_type == FDB_TYPE_DYNAMIC) { - type = "dynamic"; + type = "dynamic extern_learn"; } else { @@ -384,7 +384,7 @@ void FdbSync::addLocalMac(string key, string op) if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) { - type = "dynamic"; + type = "dynamic extern_learn"; } else { @@ -432,7 +432,7 @@ void FdbSync::updateMclagRemoteMac (struct m_fdb_info *info) if (fdb_type == FDB_TYPE_DYNAMIC) { - type = "dynamic"; + type = "dynamic extern_learn"; } else { @@ -511,7 +511,7 @@ void FdbSync::macRefreshStateDB(int vlan, string kmac) if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) { - type = "dynamic"; + type = "dynamic extern_learn"; } else { From 4af61167c17b44838242edcb7f20e8ec92e91d1c Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Fri, 5 Apr 2024 09:04:32 -0700 Subject: [PATCH 08/34] Fix oper FEC retrieval after warmboot (#3100) Updating oper FEC status in state_db after warm-reboot as part of refresh port status call --- orchagent/portsorch.cpp | 12 +++++++++++ tests/mock_tests/portsorch_ut.cpp | 33 +++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 67265af5f6..1ffb559ec5 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -7779,6 +7779,18 @@ void PortsOrch::refreshPortStatus() { updateDbPortOperSpeed(port, 0); } + sai_port_fec_mode_t fec_mode; + string fec_str = "N/A"; + if (oper_fec_sup && getPortOperFec(port, fec_mode)) + { + if (!m_portHlpr.fecToStr(fec_str, fec_mode)) + { + SWSS_LOG_ERROR("Error unknown fec mode %d while querying port %s fec mode", + static_cast(fec_mode), port.m_alias.c_str()); + fec_str = "N/A"; + } + } + updateDbPortOperFec(port,fec_str); } } } diff --git a/tests/mock_tests/portsorch_ut.cpp b/tests/mock_tests/portsorch_ut.cpp index 5b775d8d31..e7a89a10a4 100644 --- a/tests/mock_tests/portsorch_ut.cpp +++ b/tests/mock_tests/portsorch_ut.cpp @@ -68,6 +68,11 @@ namespace portsorch_test attr_list[0].value.s32 = _sai_port_fec_mode; status = SAI_STATUS_SUCCESS; } + else if (attr_count== 1 && attr_list[0].id == SAI_PORT_ATTR_OPER_STATUS) + { + attr_list[0].value.u32 = (uint32_t)SAI_PORT_OPER_STATUS_UP; + status = SAI_STATUS_SUCCESS; + } else { status = pold_sai_port_api->get_port_attribute(port_id, attr_count, attr_list); @@ -1261,6 +1266,7 @@ namespace portsorch_test { _hook_sai_port_api(); Table portTable = Table(m_app_db.get(), APP_PORT_TABLE_NAME); + Table statePortTable = Table(m_state_db.get(), STATE_PORT_TABLE_NAME); std::deque entries; not_support_fetching_fec = false; @@ -1310,6 +1316,33 @@ namespace portsorch_test ASSERT_EQ(fec_mode, SAI_PORT_FEC_MODE_RS); + gPortsOrch->refreshPortStatus(); + std::vector values; + statePortTable.get("Ethernet0", values); + bool fec_found = false; + for (auto &valueTuple : values) + { + if (fvField(valueTuple) == "fec") + { + fec_found = true; + ASSERT_TRUE(fvValue(valueTuple) == "rs"); + } + } + ASSERT_TRUE(fec_found == true); + + /*Mock an invalid fec mode with high value*/ + _sai_port_fec_mode = 100; + gPortsOrch->refreshPortStatus(); + statePortTable.get("Ethernet0", values); + fec_found = false; + for (auto &valueTuple : values) + { + if (fvField(valueTuple) == "fec") + { + fec_found = true; + ASSERT_TRUE(fvValue(valueTuple) == "N/A"); + } + } mock_port_fec_modes = old_mock_port_fec_modes; _unhook_sai_port_api(); } From cbc263a1d2f234d2b196c4bc571ae4baa36fe963 Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Fri, 5 Apr 2024 16:55:39 -0700 Subject: [PATCH 09/34] [EVPN]Fix fpmsyncd crash when EVPN type5 is received with bgp fib suppression enabled (#3101) * [EVPN]Fix fpmsyncd crash when EVPN type5 is received with bgp fib suppression enabled --- fpmsyncd/routesync.cpp | 8 ++- fpmsyncd/routesync.h | 2 +- tests/mock_tests/fake_producerstatetable.cpp | 7 +- tests/mock_tests/fpmsyncd/test_routesync.cpp | 70 ++++++++++++++++++-- 4 files changed, 79 insertions(+), 8 deletions(-) diff --git a/fpmsyncd/routesync.cpp b/fpmsyncd/routesync.cpp index caf6210084..0f6ee41188 100644 --- a/fpmsyncd/routesync.cpp +++ b/fpmsyncd/routesync.cpp @@ -465,6 +465,7 @@ void RouteSync::onEvpnRouteMsg(struct nlmsghdr *h, int len) inet_ntop(rtm->rtm_family, dstaddr, buf, MAX_ADDR_SIZE), dst_len); } + auto proto_str = getProtocolString(rtm->rtm_protocol); SWSS_LOG_INFO("Receive route message dest ip prefix: %s Op:%s", destipprefix, nlmsg_type == RTM_NEWROUTE ? "add":"del"); @@ -550,17 +551,20 @@ void RouteSync::onEvpnRouteMsg(struct nlmsghdr *h, int len) FieldValueTuple intf("ifname", intf_list); FieldValueTuple vni("vni_label", vni_list); FieldValueTuple mac("router_mac", mac_list); + FieldValueTuple proto("protocol", proto_str); fvVector.push_back(nh); fvVector.push_back(intf); fvVector.push_back(vni); fvVector.push_back(mac); + fvVector.push_back(proto); if (!warmRestartInProgress) { m_routeTable.set(destipprefix, fvVector); - SWSS_LOG_DEBUG("RouteTable set msg: %s vtep:%s vni:%s mac:%s intf:%s", - destipprefix, nexthops.c_str(), vni_list.c_str(), mac_list.c_str(), intf_list.c_str()); + SWSS_LOG_DEBUG("RouteTable set msg: %s vtep:%s vni:%s mac:%s intf:%s protocol:%s", + destipprefix, nexthops.c_str(), vni_list.c_str(), mac_list.c_str(), intf_list.c_str(), + proto_str.c_str()); } /* diff --git a/fpmsyncd/routesync.h b/fpmsyncd/routesync.h index fd18b9d25a..eb07eb8f15 100644 --- a/fpmsyncd/routesync.h +++ b/fpmsyncd/routesync.h @@ -115,7 +115,7 @@ class RouteSync : public NetMsg string& mac_list, string& intf_list, string rmac, string vlan_id); - bool getEvpnNextHop(struct nlmsghdr *h, int received_bytes, struct rtattr *tb[], + virtual bool getEvpnNextHop(struct nlmsghdr *h, int received_bytes, struct rtattr *tb[], string& nexthops, string& vni_list, string& mac_list, string& intf_list); diff --git a/tests/mock_tests/fake_producerstatetable.cpp b/tests/mock_tests/fake_producerstatetable.cpp index 6221556f63..33fab17ecf 100644 --- a/tests/mock_tests/fake_producerstatetable.cpp +++ b/tests/mock_tests/fake_producerstatetable.cpp @@ -4,8 +4,13 @@ using namespace std; namespace swss { + ProducerStateTable::ProducerStateTable(RedisPipeline *pipeline, const string &tableName, bool buffered) - : TableBase(tableName, SonicDBConfig::getSeparator(pipeline->getDBConnector())), TableName_KeySet(tableName) {} + : TableBase(tableName, SonicDBConfig::getSeparator(pipeline->getDBConnector())), TableName_KeySet(tableName), m_buffered(buffered) + , m_pipeowned(false) + , m_tempViewActive(false) + , m_pipe(pipeline) {} ProducerStateTable::~ProducerStateTable() {} + } diff --git a/tests/mock_tests/fpmsyncd/test_routesync.cpp b/tests/mock_tests/fpmsyncd/test_routesync.cpp index debfa16d21..a8de78859f 100644 --- a/tests/mock_tests/fpmsyncd/test_routesync.cpp +++ b/tests/mock_tests/fpmsyncd/test_routesync.cpp @@ -1,12 +1,32 @@ -#include "fpmsyncd/routesync.h" +#include "redisutility.h" #include #include +#include "mock_table.h" +#define private public +#include "fpmsyncd/routesync.h" +#undef private using namespace swss; +#define MAX_PAYLOAD 1024 using ::testing::_; +class MockRouteSync : public RouteSync +{ +public: + MockRouteSync(RedisPipeline *m_pipeline) : RouteSync(m_pipeline) + { + } + + ~MockRouteSync() + { + } + MOCK_METHOD(bool, getEvpnNextHop, (nlmsghdr *, int, + rtattr *[], std::string&, + std::string& , std::string&, + std::string&), (override)); +}; class MockFpm : public FpmInterface { public: @@ -42,10 +62,11 @@ class FpmSyncdResponseTest : public ::testing::Test { } - DBConnector m_db{"APPL_DB", 0}; - RedisPipeline m_pipeline{&m_db, 1}; - RouteSync m_routeSync{&m_pipeline}; + shared_ptr m_db = make_shared("APPL_DB", 0); + shared_ptr m_pipeline = make_shared(m_db.get()); + RouteSync m_routeSync{m_pipeline.get()}; MockFpm m_mockFpm{&m_routeSync}; + MockRouteSync m_mockRouteSync{m_pipeline.get()}; }; TEST_F(FpmSyncdResponseTest, RouteResponseFeedbackV4) @@ -170,3 +191,44 @@ TEST_F(FpmSyncdResponseTest, WarmRestart) m_routeSync.onWarmStartEnd(applStateDb); } + +TEST_F(FpmSyncdResponseTest, testEvpn) +{ + struct nlmsghdr *nlh = (struct nlmsghdr *) malloc(NLMSG_SPACE(MAX_PAYLOAD)); + shared_ptr m_app_db; + m_app_db = make_shared("APPL_DB", 0); + Table app_route_table(m_app_db.get(), APP_ROUTE_TABLE_NAME); + + memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD)); + nlh->nlmsg_type = RTM_NEWROUTE; + struct rtmsg rtm; + rtm.rtm_family = AF_INET; + rtm.rtm_protocol = 200; + rtm.rtm_type = RTN_UNICAST; + rtm.rtm_table = 0; + rtm.rtm_dst_len = 32; + nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD); + memcpy(NLMSG_DATA(nlh), &rtm, sizeof(rtm)); + + EXPECT_CALL(m_mockRouteSync, getEvpnNextHop(_, _, _, _, _, _, _)).Times(testing::AtLeast(1)).WillOnce([&]( + struct nlmsghdr *h, int received_bytes, + struct rtattr *tb[], std::string& nexthops, + std::string& vni_list, std::string& mac_list, + std::string& intf_list)-> bool { + vni_list="100"; + mac_list="aa:aa:aa:aa:aa:aa"; + intf_list="Ethernet0"; + nexthops = "1.1.1.1"; + return true; + }); + m_mockRouteSync.onMsgRaw(nlh); + vector keys; + vector fieldValues; + app_route_table.getKeys(keys); + ASSERT_EQ(keys.size(), 1); + + app_route_table.get(keys[0], fieldValues); + auto value = swss::fvsGetValue(fieldValues, "protocol", true); + ASSERT_EQ(value.get(), "0xc8"); + +} From 0f707757832a2eb9bd315d71ed1242548bb2eeb2 Mon Sep 17 00:00:00 2001 From: Stepan Blyshchak <38952541+stepanblyschak@users.noreply.github.com> Date: Mon, 8 Apr 2024 20:12:00 +0300 Subject: [PATCH 10/34] [portsorch] Handle TRANSCEIVER_INFO table on warm boot (#3087) * Add existing data from TRANSCEIVER_INFO table --- orchagent/portsorch.cpp | 1 + tests/mock_tests/Makefile.am | 1 + .../mock_tests/mock_subscriberstatetable.cpp | 30 +++++++++++++++++++ tests/mock_tests/portsorch_ut.cpp | 25 ++++++++++++++-- 4 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 tests/mock_tests/mock_subscriberstatetable.cpp diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 1ffb559ec5..50c23d4aec 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -3391,6 +3391,7 @@ bool PortsOrch::bake() addExistingData(APP_LAG_MEMBER_TABLE_NAME); addExistingData(APP_VLAN_TABLE_NAME); addExistingData(APP_VLAN_MEMBER_TABLE_NAME); + addExistingData(STATE_TRANSCEIVER_INFO_TABLE_NAME); return true; } diff --git a/tests/mock_tests/Makefile.am b/tests/mock_tests/Makefile.am index b5afd53793..96c95b121b 100644 --- a/tests/mock_tests/Makefile.am +++ b/tests/mock_tests/Makefile.am @@ -40,6 +40,7 @@ tests_SOURCES = aclorch_ut.cpp \ mock_orchagent_main.cpp \ mock_dbconnector.cpp \ mock_consumerstatetable.cpp \ + mock_subscriberstatetable.cpp \ common/mock_shell_command.cpp \ mock_table.cpp \ mock_hiredis.cpp \ diff --git a/tests/mock_tests/mock_subscriberstatetable.cpp b/tests/mock_tests/mock_subscriberstatetable.cpp new file mode 100644 index 0000000000..5548191940 --- /dev/null +++ b/tests/mock_tests/mock_subscriberstatetable.cpp @@ -0,0 +1,30 @@ +#include "subscriberstatetable.h" + +namespace swss +{ + SubscriberStateTable::SubscriberStateTable(DBConnector *db, const std::string &tableName, int popBatchSize, int pri) : + ConsumerTableBase(db, tableName, popBatchSize, pri), + m_table(db, tableName) + { + } + + void SubscriberStateTable::pops(std::deque &vkco, const std::string& /*prefix*/) + { + std::vector keys; + m_table.getKeys(keys); + for (const auto &key: keys) + { + KeyOpFieldsValuesTuple kco; + + kfvKey(kco) = key; + kfvOp(kco) = SET_COMMAND; + + if (!m_table.get(key, kfvFieldsValues(kco))) + { + continue; + } + m_table.del(key); + vkco.push_back(kco); + } + } +} diff --git a/tests/mock_tests/portsorch_ut.cpp b/tests/mock_tests/portsorch_ut.cpp index e7a89a10a4..968a578d44 100644 --- a/tests/mock_tests/portsorch_ut.cpp +++ b/tests/mock_tests/portsorch_ut.cpp @@ -504,9 +504,9 @@ namespace portsorch_test } }; - + /* - * Test port flap count + * Test port flap count */ TEST_F(PortsOrchTest, PortFlapCount) { @@ -1506,6 +1506,7 @@ namespace portsorch_test Table pgTable = Table(m_app_db.get(), APP_BUFFER_PG_TABLE_NAME); Table profileTable = Table(m_app_db.get(), APP_BUFFER_PROFILE_TABLE_NAME); Table poolTable = Table(m_app_db.get(), APP_BUFFER_POOL_TABLE_NAME); + Table transceieverInfoTable = Table(m_state_db.get(), STATE_TRANSCEIVER_INFO_TABLE_NAME); // Get SAI default ports to populate DB @@ -1539,6 +1540,7 @@ namespace portsorch_test for (const auto &it : ports) { portTable.set(it.first, it.second); + transceieverInfoTable.set(it.first, {}); } // Set PortConfigDone, PortInitDone @@ -1586,6 +1588,25 @@ namespace portsorch_test gBufferOrch->dumpPendingTasks(ts); ASSERT_TRUE(ts.empty()); + + // Verify port configuration + vector port_list; + port_list.resize(ports.size()); + sai_attribute_t attr; + sai_status_t status; + attr.id = SAI_SWITCH_ATTR_PORT_LIST; + attr.value.objlist.count = static_cast(port_list.size()); + attr.value.objlist.list = port_list.data(); + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + for (uint32_t i = 0; i < port_list.size(); i++) + { + attr.id = SAI_PORT_ATTR_HOST_TX_SIGNAL_ENABLE; + status = sai_port_api->get_port_attribute(port_list[i], 1, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + ASSERT_TRUE(attr.value.booldata); + } } TEST_F(PortsOrchTest, PfcDlrHandlerCallingDlrInitAttribute) From f6dd9caae83f7cc05302645c30cf162822a537a6 Mon Sep 17 00:00:00 2001 From: Vivek Date: Mon, 8 Apr 2024 14:25:08 -0700 Subject: [PATCH 11/34] Introduce a new role for DPU-NPU Interconnect Signed-off-by: Vivek Reddy Karri Co-authored-by: Sudharsan Dhamal Gopalarathnam --- orchagent/port.h | 3 ++- orchagent/port/porthlpr.cpp | 3 ++- orchagent/port/portschema.h | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/orchagent/port.h b/orchagent/port.h index e4a15c17ad..dc8241ce3a 100644 --- a/orchagent/port.h +++ b/orchagent/port.h @@ -97,7 +97,8 @@ class Port Ext, // external Int, // internal Inb, // inband - Rec // recirculation + Rec, // recirculation + Dpc // DPU Connect Port on SmartSwitch }; public: diff --git a/orchagent/port/porthlpr.cpp b/orchagent/port/porthlpr.cpp index f6463b0af5..419cb7ff84 100644 --- a/orchagent/port/porthlpr.cpp +++ b/orchagent/port/porthlpr.cpp @@ -114,7 +114,8 @@ static const std::unordered_map portRoleMap = { PORT_ROLE_EXT, Port::Role::Ext }, { PORT_ROLE_INT, Port::Role::Int }, { PORT_ROLE_INB, Port::Role::Inb }, - { PORT_ROLE_REC, Port::Role::Rec } + { PORT_ROLE_REC, Port::Role::Rec }, + { PORT_ROLE_DPC, Port::Role::Dpc } }; // functions ---------------------------------------------------------------------------------------------------------- diff --git a/orchagent/port/portschema.h b/orchagent/port/portschema.h index 56b2541c37..5c4ad0d542 100644 --- a/orchagent/port/portschema.h +++ b/orchagent/port/portschema.h @@ -51,6 +51,7 @@ #define PORT_ROLE_INT "Int" #define PORT_ROLE_INB "Inb" #define PORT_ROLE_REC "Rec" +#define PORT_ROLE_DPC "Dpc" #define PORT_ALIAS "alias" #define PORT_INDEX "index" From 56ba6de3bfa509d38ca41757c756b3d5071904b3 Mon Sep 17 00:00:00 2001 From: mint570 <70396898+mint570@users.noreply.github.com> Date: Mon, 8 Apr 2024 17:13:14 -0700 Subject: [PATCH 12/34] [p4orch] Clang format change. (#3096) What I did [p4orch] This PR has no real code change. It is purely clang formatting. It does the same as #3080. --- orchagent/p4orch/acl_rule_manager.cpp | 2 +- orchagent/p4orch/acl_table_manager.cpp | 2 +- orchagent/p4orch/acl_util.cpp | 3 +- orchagent/p4orch/acl_util.h | 6 +-- orchagent/p4orch/ext_tables_manager.cpp | 26 ++++++++----- orchagent/p4orch/ext_tables_manager.h | 4 +- orchagent/p4orch/gre_tunnel_manager.cpp | 2 +- orchagent/p4orch/l3_admit_manager.cpp | 2 +- orchagent/p4orch/mirror_session_manager.cpp | 2 +- orchagent/p4orch/neighbor_manager.cpp | 2 +- orchagent/p4orch/next_hop_manager.cpp | 2 +- orchagent/p4orch/p4orch_util.cpp | 2 +- orchagent/p4orch/route_manager.cpp | 2 +- orchagent/p4orch/router_interface_manager.cpp | 2 +- .../p4orch/tables_definition_manager.cpp | 39 ++++++++++++------- orchagent/p4orch/tables_definition_manager.h | 4 +- orchagent/p4orch/tests/acl_manager_test.cpp | 2 +- .../p4orch/tests/gre_tunnel_manager_test.cpp | 2 +- .../p4orch/tests/l3_admit_manager_test.cpp | 2 +- .../tests/mirror_session_manager_test.cpp | 2 +- .../p4orch/tests/neighbor_manager_test.cpp | 2 +- .../p4orch/tests/next_hop_manager_test.cpp | 2 +- orchagent/p4orch/tests/route_manager_test.cpp | 2 +- orchagent/p4orch/tests/wcmp_manager_test.cpp | 2 +- orchagent/p4orch/wcmp_manager.cpp | 2 +- 25 files changed, 70 insertions(+), 50 deletions(-) diff --git a/orchagent/p4orch/acl_rule_manager.cpp b/orchagent/p4orch/acl_rule_manager.cpp index 7989bfa9e6..5131b718ac 100644 --- a/orchagent/p4orch/acl_rule_manager.cpp +++ b/orchagent/p4orch/acl_rule_manager.cpp @@ -1,5 +1,6 @@ #include "p4orch/acl_rule_manager.h" +#include #include #include #include @@ -17,7 +18,6 @@ #include "sai_serialize.h" #include "table.h" #include "tokenize.h" -#include extern "C" { #include "sai.h" diff --git a/orchagent/p4orch/acl_table_manager.cpp b/orchagent/p4orch/acl_table_manager.cpp index abfedbda0c..4a3910992e 100644 --- a/orchagent/p4orch/acl_table_manager.cpp +++ b/orchagent/p4orch/acl_table_manager.cpp @@ -1,5 +1,6 @@ #include "p4orch/acl_table_manager.h" +#include #include #include #include @@ -15,7 +16,6 @@ #include "switchorch.h" #include "table.h" #include "tokenize.h" -#include extern "C" { #include "sai.h" diff --git a/orchagent/p4orch/acl_util.cpp b/orchagent/p4orch/acl_util.cpp index ad943e6ee9..5ab2276b4d 100644 --- a/orchagent/p4orch/acl_util.cpp +++ b/orchagent/p4orch/acl_util.cpp @@ -1,11 +1,12 @@ #include "p4orch/acl_util.h" +#include + #include "converter.h" #include "logger.h" #include "sai_serialize.h" #include "table.h" #include "tokenize.h" -#include namespace p4orch { diff --git a/orchagent/p4orch/acl_util.h b/orchagent/p4orch/acl_util.h index 37522fd164..b4123d0754 100644 --- a/orchagent/p4orch/acl_util.h +++ b/orchagent/p4orch/acl_util.h @@ -1,13 +1,13 @@ #pragma once #include +#include #include #include #include #include "p4orch/p4orch_util.h" #include "return_code.h" -#include extern "C" { #include "sai.h" @@ -243,7 +243,7 @@ struct P4AclTableDefinition P4AclTableDefinition(const std::string &acl_table_name, const sai_acl_stage_t stage, const uint32_t priority, const uint32_t size, const std::string &meter_unit, const std::string &counter_unit) : acl_table_name(acl_table_name), stage(stage), priority(priority), size(size), meter_unit(meter_unit), - counter_unit(counter_unit){}; + counter_unit(counter_unit) {}; }; struct P4UserDefinedTrapHostifTableEntry @@ -251,7 +251,7 @@ struct P4UserDefinedTrapHostifTableEntry sai_object_id_t user_defined_trap; sai_object_id_t hostif_table_entry; P4UserDefinedTrapHostifTableEntry() - : user_defined_trap(SAI_NULL_OBJECT_ID), hostif_table_entry(SAI_NULL_OBJECT_ID){}; + : user_defined_trap(SAI_NULL_OBJECT_ID), hostif_table_entry(SAI_NULL_OBJECT_ID) {}; }; using acl_rule_attr_lookup_t = std::map; diff --git a/orchagent/p4orch/ext_tables_manager.cpp b/orchagent/p4orch/ext_tables_manager.cpp index 09bf7ccbe4..ae091fcd77 100644 --- a/orchagent/p4orch/ext_tables_manager.cpp +++ b/orchagent/p4orch/ext_tables_manager.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -14,7 +15,6 @@ #include "p4orch/p4orch.h" #include "p4orch/p4orch_util.h" #include "tokenize.h" -#include extern sai_counter_api_t *sai_counter_api; extern sai_generic_programmable_api_t *sai_generic_programmable_api; @@ -111,15 +111,18 @@ ReturnCode ExtTablesManager::validateActionParamsCrossRef(P4ExtTableAppDbEntry & SWSS_LOG_ERROR("Cross-table reference validation failed from extension-table %s", table_name.c_str()); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Cross-table reference valdiation failed from extension table"; + << "Cross-table reference valdiation failed from extension " + "table"; } } else { - SWSS_LOG_ERROR("Cross-table reference validation failed due to non-existent table %s", + SWSS_LOG_ERROR("Cross-table reference validation failed due to non-existent table " + "%s", table_name.c_str()); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Cross-table reference valdiation failed due to non-existent table"; + << "Cross-table reference valdiation failed due to non-existent " + "table"; } } @@ -132,7 +135,8 @@ ReturnCode ExtTablesManager::validateActionParamsCrossRef(P4ExtTableAppDbEntry & if (oid == SAI_NULL_OBJECT_ID) { - SWSS_LOG_ERROR("Cross-table reference validation failed, null OID expected from table %s", + SWSS_LOG_ERROR("Cross-table reference validation failed, null OID expected from " + "table %s", table_name.c_str()); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Cross-table reference valdiation failed, null OID"; } @@ -724,7 +728,8 @@ void ExtTablesManager::drain() SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), status.message().c_str()); m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, /*replace=*/true); + kfvFieldsValues(key_op_fvs_tuple), status, + /*replace=*/true); continue; } @@ -735,7 +740,8 @@ void ExtTablesManager::drain() SWSS_LOG_ERROR("Validation failed for extension APP DB entry with key %s: %s", QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), status.message().c_str()); m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, /*replace=*/true); + kfvFieldsValues(key_op_fvs_tuple), status, + /*replace=*/true); continue; } @@ -772,7 +778,8 @@ void ExtTablesManager::drain() QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), status.message().c_str()); } m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), - status, /*replace=*/true); + status, + /*replace=*/true); } it_m->second.clear(); @@ -833,7 +840,8 @@ void ExtTablesManager::doExtCounterStatsTask() sai_counter_api->get_counter_stats(ext_table_entry->sai_counter_oid, 2, stat_ids, stats); if (sai_status != SAI_STATUS_SUCCESS) { - SWSS_LOG_WARN("Failed to set counters stats for extension entry %s:%s in COUNTERS_DB: ", + SWSS_LOG_WARN("Failed to set counters stats for extension entry %s:%s in " + "COUNTERS_DB: ", table_name.c_str(), ext_table_entry->table_key.c_str()); continue; } diff --git a/orchagent/p4orch/ext_tables_manager.h b/orchagent/p4orch/ext_tables_manager.h index e45a2566ca..82256f72ba 100644 --- a/orchagent/p4orch/ext_tables_manager.h +++ b/orchagent/p4orch/ext_tables_manager.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -14,7 +15,6 @@ #include "response_publisher_interface.h" #include "return_code.h" #include "vrforch.h" -#include extern "C" { #include "sai.h" @@ -29,7 +29,7 @@ struct P4ExtTableEntry sai_object_id_t sai_counter_oid = SAI_NULL_OBJECT_ID; std::unordered_map action_dep_objects; - P4ExtTableEntry(){}; + P4ExtTableEntry() {}; P4ExtTableEntry(const std::string &db_key, const std::string &table_name, const std::string &table_key) : db_key(db_key), table_name(table_name), table_key(table_key) { diff --git a/orchagent/p4orch/gre_tunnel_manager.cpp b/orchagent/p4orch/gre_tunnel_manager.cpp index a46dc0fd38..c3bfd7d6d7 100644 --- a/orchagent/p4orch/gre_tunnel_manager.cpp +++ b/orchagent/p4orch/gre_tunnel_manager.cpp @@ -1,6 +1,7 @@ #include "p4orch/gre_tunnel_manager.h" #include +#include #include #include #include @@ -14,7 +15,6 @@ #include "sai_serialize.h" #include "swssnet.h" #include "table.h" -#include extern "C" { #include "sai.h" diff --git a/orchagent/p4orch/l3_admit_manager.cpp b/orchagent/p4orch/l3_admit_manager.cpp index 2440dd2a0c..da5b955dba 100644 --- a/orchagent/p4orch/l3_admit_manager.cpp +++ b/orchagent/p4orch/l3_admit_manager.cpp @@ -1,6 +1,7 @@ #include "p4orch/l3_admit_manager.h" #include +#include #include #include #include @@ -14,7 +15,6 @@ #include "sai_serialize.h" #include "table.h" #include "tokenize.h" -#include extern "C" { #include "sai.h" diff --git a/orchagent/p4orch/mirror_session_manager.cpp b/orchagent/p4orch/mirror_session_manager.cpp index 440257ea1d..e562b87ff5 100644 --- a/orchagent/p4orch/mirror_session_manager.cpp +++ b/orchagent/p4orch/mirror_session_manager.cpp @@ -1,6 +1,7 @@ #include "p4orch/mirror_session_manager.h" #include +#include #include "SaiAttributeList.h" #include "dbconnector.h" @@ -10,7 +11,6 @@ #include "swss/logger.h" #include "swssnet.h" #include "table.h" -#include using ::p4orch::kTableKeyDelimiter; diff --git a/orchagent/p4orch/neighbor_manager.cpp b/orchagent/p4orch/neighbor_manager.cpp index 75075a13a6..f68f22a545 100644 --- a/orchagent/p4orch/neighbor_manager.cpp +++ b/orchagent/p4orch/neighbor_manager.cpp @@ -1,5 +1,6 @@ #include "p4orch/neighbor_manager.h" +#include #include #include #include @@ -13,7 +14,6 @@ #include "sai_serialize.h" #include "swssnet.h" #include "table.h" -#include extern "C" { #include "sai.h" diff --git a/orchagent/p4orch/next_hop_manager.cpp b/orchagent/p4orch/next_hop_manager.cpp index b5586ae233..f55c83534a 100644 --- a/orchagent/p4orch/next_hop_manager.cpp +++ b/orchagent/p4orch/next_hop_manager.cpp @@ -1,5 +1,6 @@ #include "p4orch/next_hop_manager.h" +#include #include #include #include @@ -14,7 +15,6 @@ #include "sai_serialize.h" #include "swssnet.h" #include "table.h" -#include extern "C" { #include "sai.h" diff --git a/orchagent/p4orch/p4orch_util.cpp b/orchagent/p4orch/p4orch_util.cpp index ceb46b4b01..dd0a4171ad 100644 --- a/orchagent/p4orch/p4orch_util.cpp +++ b/orchagent/p4orch/p4orch_util.cpp @@ -1,6 +1,6 @@ #include "p4orch/p4orch_util.h" -#include "p4orch/p4orch.h" +#include "p4orch/p4orch.h" #include "schema.h" using ::p4orch::kTableKeyDelimiter; diff --git a/orchagent/p4orch/route_manager.cpp b/orchagent/p4orch/route_manager.cpp index 1e69de5d17..c50b3bb4b9 100644 --- a/orchagent/p4orch/route_manager.cpp +++ b/orchagent/p4orch/route_manager.cpp @@ -1,6 +1,7 @@ #include "p4orch/route_manager.h" #include +#include #include #include #include @@ -16,7 +17,6 @@ #include "sai_serialize.h" #include "swssnet.h" #include "table.h" -#include using ::p4orch::kTableKeyDelimiter; diff --git a/orchagent/p4orch/router_interface_manager.cpp b/orchagent/p4orch/router_interface_manager.cpp index 8074cc49ec..de32576e68 100644 --- a/orchagent/p4orch/router_interface_manager.cpp +++ b/orchagent/p4orch/router_interface_manager.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -17,7 +18,6 @@ #include "sai_serialize.h" #include "table.h" #include "vrforch.h" -#include using ::p4orch::kTableKeyDelimiter; diff --git a/orchagent/p4orch/tables_definition_manager.cpp b/orchagent/p4orch/tables_definition_manager.cpp index 7790458cfc..1da15028e5 100644 --- a/orchagent/p4orch/tables_definition_manager.cpp +++ b/orchagent/p4orch/tables_definition_manager.cpp @@ -1,6 +1,7 @@ #include "p4orch/tables_definition_manager.h" #include +#include #include #include #include @@ -12,7 +13,6 @@ #include "p4orch/p4orch.h" #include "p4orch/p4orch_util.h" #include "tokenize.h" -#include extern "C" { #include "saitypes.h" @@ -100,7 +100,8 @@ ReturnCode parseTableMatchReferences(const nlohmann::json &match_json, TableMatc catch (std::exception &ex) { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "can not parse tables from app-db supplied table definition info"; + << "can not parse tables from app-db supplied table definition " + "info"; } } } @@ -125,7 +126,8 @@ ReturnCode parseActionParamReferences(const nlohmann::json ¶m_json, ActionPa catch (std::exception &ex) { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "can not parse tables from app-db supplied table definition info"; + << "can not parse tables from app-db supplied table definition " + "info"; } } } @@ -155,7 +157,8 @@ ReturnCode parseTableActionParams(const nlohmann::json &action_json, ActionInfo if (!param.table_reference_map.empty()) { /** - * Helps avoid walk of action parameters if this is set to false at action level + * Helps avoid walk of action parameters if this is set to false at + * action level */ action.refers_to = true; } @@ -163,7 +166,8 @@ ReturnCode parseTableActionParams(const nlohmann::json &action_json, ActionInfo catch (std::exception &ex) { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "can not parse tables from app-db supplied table definition info"; + << "can not parse tables from app-db supplied table definition " + "info"; } } } @@ -215,7 +219,8 @@ ReturnCode parseTablesInfo(const nlohmann::json &info_json, TablesInfo &info_ent catch (std::exception &ex) { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "can not parse tables from app-db supplied table definition info"; + << "can not parse tables from app-db supplied table definition " + "info"; } TableInfo table = {}; @@ -247,8 +252,8 @@ ReturnCode parseTablesInfo(const nlohmann::json &info_json, TablesInfo &info_ent table.action_fields[action_name] = action; /** - * If any parameter of action refers to another table, add that one in the - * cross-reference list of current table + * If any parameter of action refers to another table, add that one in + * the cross-reference list of current table */ for (auto param_it = action.params.begin(); param_it != action.params.end(); param_it++) { @@ -466,7 +471,8 @@ std::vector findTablePrecedence(int tables, std::vector for (int i = 0; i < tables; i++) { - // Err input data like possible cyclic dependencies, could not build precedence order + // Err input data like possible cyclic dependencies, could not build + // precedence order if (zeros.empty()) { SWSS_LOG_ERROR("Filed to build table precedence order"); @@ -546,7 +552,8 @@ void buildTablePrecedence(TablesInfo *tables_info) // find precedence of tables based on dependencies orderedTables = findTablePrecedence(tables, preReq, tables_info); - // update each table with calculated precedence value and build table precedence map + // update each table with calculated precedence value and build table + // precedence map for (std::size_t i = 0; i < orderedTables.size(); i++) { auto table_id = orderedTables[i]; @@ -593,7 +600,8 @@ void TablesDefnManager::drain() SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", QuotedVar(table_name + ":" + key).c_str(), status.message().c_str()); m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), - status, /*replace=*/true); + status, + /*replace=*/true); continue; } auto &app_db_entry = *app_db_entry_or; @@ -601,10 +609,12 @@ void TablesDefnManager::drain() status = validateTablesInfoAppDbEntry(app_db_entry); if (!status.ok()) { - SWSS_LOG_ERROR("Validation failed for tables definition APP DB entry with key %s: %s", + SWSS_LOG_ERROR("Validation failed for tables definition APP DB entry with key %s: " + "%s", QuotedVar(table_name + ":" + key).c_str(), status.message().c_str()); m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), - status, /*replace=*/true); + status, + /*replace=*/true); continue; } @@ -637,7 +647,8 @@ void TablesDefnManager::drain() } if (!status.ok()) { - SWSS_LOG_ERROR("Processing failed for tables definition APP DB entry with key %s: %s", + SWSS_LOG_ERROR("Processing failed for tables definition APP DB entry with key %s: " + "%s", QuotedVar(table_name + ":" + key).c_str(), status.message().c_str()); } else diff --git a/orchagent/p4orch/tables_definition_manager.h b/orchagent/p4orch/tables_definition_manager.h index ffe8b62857..85ca363bf5 100644 --- a/orchagent/p4orch/tables_definition_manager.h +++ b/orchagent/p4orch/tables_definition_manager.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -12,7 +13,6 @@ #include "p4orch/p4orch_util.h" #include "response_publisher_interface.h" #include "return_code.h" -#include extern "C" { #include "sai.h" @@ -29,7 +29,7 @@ struct TablesInfo std::unordered_map m_tableInfoMap; std::map m_tablePrecedenceMap; - TablesInfo(){}; + TablesInfo() {}; TablesInfo(const std::string &context_key, const nlohmann::json &info_value) : context(context_key), info(info_value) { diff --git a/orchagent/p4orch/tests/acl_manager_test.cpp b/orchagent/p4orch/tests/acl_manager_test.cpp index 515cab853f..107dfdfde5 100644 --- a/orchagent/p4orch/tests/acl_manager_test.cpp +++ b/orchagent/p4orch/tests/acl_manager_test.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include "acl_rule_manager.h" @@ -21,7 +22,6 @@ #include "table.h" #include "tokenize.h" #include "vrforch.h" -#include using ::p4orch::kTableKeyDelimiter; diff --git a/orchagent/p4orch/tests/gre_tunnel_manager_test.cpp b/orchagent/p4orch/tests/gre_tunnel_manager_test.cpp index f546e09ef7..da3ae3578b 100644 --- a/orchagent/p4orch/tests/gre_tunnel_manager_test.cpp +++ b/orchagent/p4orch/tests/gre_tunnel_manager_test.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -17,7 +18,6 @@ #include "p4orch_util.h" #include "return_code.h" #include "swssnet.h" -#include extern "C" { #include "sai.h" diff --git a/orchagent/p4orch/tests/l3_admit_manager_test.cpp b/orchagent/p4orch/tests/l3_admit_manager_test.cpp index 8b246050c9..0fa5cb7ac3 100644 --- a/orchagent/p4orch/tests/l3_admit_manager_test.cpp +++ b/orchagent/p4orch/tests/l3_admit_manager_test.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -13,7 +14,6 @@ #include "p4orch/p4orch_util.h" #include "p4orch_util.h" #include "return_code.h" -#include extern "C" { #include "sai.h" diff --git a/orchagent/p4orch/tests/mirror_session_manager_test.cpp b/orchagent/p4orch/tests/mirror_session_manager_test.cpp index 503060e231..1361fc96b3 100644 --- a/orchagent/p4orch/tests/mirror_session_manager_test.cpp +++ b/orchagent/p4orch/tests/mirror_session_manager_test.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -14,7 +15,6 @@ #include "swss/ipaddress.h" #include "swss/macaddress.h" #include "swssnet.h" -#include extern "C" { #include "sai.h" diff --git a/orchagent/p4orch/tests/neighbor_manager_test.cpp b/orchagent/p4orch/tests/neighbor_manager_test.cpp index 8dd62615c8..4db1db873e 100644 --- a/orchagent/p4orch/tests/neighbor_manager_test.cpp +++ b/orchagent/p4orch/tests/neighbor_manager_test.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -12,7 +13,6 @@ #include "p4orch/p4orch_util.h" #include "return_code.h" #include "swssnet.h" -#include using ::p4orch::kTableKeyDelimiter; diff --git a/orchagent/p4orch/tests/next_hop_manager_test.cpp b/orchagent/p4orch/tests/next_hop_manager_test.cpp index cc01c82920..7a2e714bbc 100644 --- a/orchagent/p4orch/tests/next_hop_manager_test.cpp +++ b/orchagent/p4orch/tests/next_hop_manager_test.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -17,7 +18,6 @@ #include "p4orch.h" #include "return_code.h" #include "swssnet.h" -#include extern "C" { #include "sai.h" diff --git a/orchagent/p4orch/tests/route_manager_test.cpp b/orchagent/p4orch/tests/route_manager_test.cpp index 67b4b4f7c9..6229f69c36 100644 --- a/orchagent/p4orch/tests/route_manager_test.cpp +++ b/orchagent/p4orch/tests/route_manager_test.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -16,7 +17,6 @@ #include "return_code.h" #include "swssnet.h" #include "vrforch.h" -#include using ::p4orch::kTableKeyDelimiter; diff --git a/orchagent/p4orch/tests/wcmp_manager_test.cpp b/orchagent/p4orch/tests/wcmp_manager_test.cpp index 29897d5d06..088264bba4 100644 --- a/orchagent/p4orch/tests/wcmp_manager_test.cpp +++ b/orchagent/p4orch/tests/wcmp_manager_test.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include "mock_response_publisher.h" @@ -17,7 +18,6 @@ #include "p4orch_util.h" #include "return_code.h" #include "sai_serialize.h" -#include extern "C" { #include "sai.h" diff --git a/orchagent/p4orch/wcmp_manager.cpp b/orchagent/p4orch/wcmp_manager.cpp index d81ce1d44e..81c373b16f 100644 --- a/orchagent/p4orch/wcmp_manager.cpp +++ b/orchagent/p4orch/wcmp_manager.cpp @@ -1,5 +1,6 @@ #include "p4orch/wcmp_manager.h" +#include #include #include #include @@ -12,7 +13,6 @@ #include "portsorch.h" #include "sai_serialize.h" #include "table.h" -#include extern "C" { #include "sai.h" From 774973d95de07209e8280d4c090620293dc7ff08 Mon Sep 17 00:00:00 2001 From: Yakiv Huryk <62013282+Yakiv-Huryk@users.noreply.github.com> Date: Thu, 11 Apr 2024 00:28:08 +0300 Subject: [PATCH 13/34] [dash] fix ENI admin state update (#3081) * [dash] fix ENI admin state update --- orchagent/dash/dashorch.cpp | 6 ++++-- tests/test_dash_vnet.py | 11 +++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/orchagent/dash/dashorch.cpp b/orchagent/dash/dashorch.cpp index 95dde9f888..d7c7818e5a 100644 --- a/orchagent/dash/dashorch.cpp +++ b/orchagent/dash/dashorch.cpp @@ -277,9 +277,11 @@ bool DashOrch::setEniAdminState(const string& eni, const EniEntry& entry) { SWSS_LOG_ENTER(); + bool eni_enable = entry.metadata.admin_state() == dash::eni::State::STATE_ENABLED; + sai_attribute_t eni_attr; eni_attr.id = SAI_ENI_ATTR_ADMIN_STATE; - eni_attr.value.booldata = entry.metadata.admin_state(); + eni_attr.value.booldata = eni_enable; sai_status_t status = sai_dash_eni_api->set_eni_attribute(eni_entries_[eni].eni_id, &eni_attr); @@ -293,7 +295,7 @@ bool DashOrch::setEniAdminState(const string& eni, const EniEntry& entry) } } eni_entries_[eni].metadata.set_admin_state(entry.metadata.admin_state()); - SWSS_LOG_NOTICE("Set ENI %s admin state to %s", eni.c_str(), entry.metadata.admin_state() ? "UP" : "DOWN"); + SWSS_LOG_NOTICE("Set ENI %s admin state to %s", eni.c_str(), eni_enable ? "UP" : "DOWN"); return true; } diff --git a/tests/test_dash_vnet.py b/tests/test_dash_vnet.py index 031fd7a0ef..ec9c56b2a0 100644 --- a/tests/test_dash_vnet.py +++ b/tests/test_dash_vnet.py @@ -223,6 +223,17 @@ def test_eni(self, dvs): for fv in fvs.items(): if fv[0] == "SAI_ENI_ETHER_ADDRESS_MAP_ENTRY_ATTR_ENI_ID": assert fv[1] == str(self.eni_oid) + + # test admin state update + pb.admin_state = State.STATE_DISABLED + dashobj.create_eni(self.mac_string, {"pb": pb.SerializeToString()}) + time.sleep(3) + enis = dashobj.asic_eni_table.get_keys() + assert len(enis) == 1 + assert enis[0] == self.eni_oid + eni_attrs = dashobj.asic_eni_table[self.eni_oid] + assert eni_attrs["SAI_ENI_ATTR_ADMIN_STATE"] == "false" + return dashobj def test_vnet_map(self, dvs): From 19410232523283d99eaa211979cc1e58b6cb262f Mon Sep 17 00:00:00 2001 From: jfeng-arista <98421150+jfeng-arista@users.noreply.github.com> Date: Thu, 11 Apr 2024 11:24:04 -0700 Subject: [PATCH 14/34] Add force option for fabric port unisolate command (#3089) What I did Add force option to the unisolate link command, so users can make the links not isolate if they want. depends on sonic-net/sonic-buildimage#18447 --- cfgmgr/fabricmgr.h | 2 +- orchagent/fabricportsorch.cpp | 284 +++++++++++++++++++- orchagent/fabricportsorch.h | 11 + orchagent/orchdaemon.cpp | 9 +- tests/test_fabric.py | 8 + tests/virtual_chassis/8/default_config.json | 24 ++ 6 files changed, 330 insertions(+), 8 deletions(-) diff --git a/cfgmgr/fabricmgr.h b/cfgmgr/fabricmgr.h index dbe2fd0d89..1fd399fef9 100644 --- a/cfgmgr/fabricmgr.h +++ b/cfgmgr/fabricmgr.h @@ -21,7 +21,7 @@ class FabricMgr : public Orch Table m_cfgFabricMonitorTable; Table m_cfgFabricPortTable; Table m_appFabricMonitorTable; - Table m_appFabricPortTable; + ProducerStateTable m_appFabricPortTable; void doTask(Consumer &consumer); bool writeConfigToAppDb(const std::string &alias, const std::string &field, const std::string &value); diff --git a/orchagent/fabricportsorch.cpp b/orchagent/fabricportsorch.cpp index b47f61a635..b46fcede09 100644 --- a/orchagent/fabricportsorch.cpp +++ b/orchagent/fabricportsorch.cpp @@ -22,6 +22,8 @@ #define FABRIC_QUEUE_STAT_COUNTER_FLEX_COUNTER_GROUP "FABRIC_QUEUE_STAT_COUNTER" #define FABRIC_QUEUE_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS 100000 #define FABRIC_DEBUG_POLLING_INTERVAL_DEFAULT (60) +#define FABRIC_MONITOR_DATA "FABRIC_MONITOR_DATA" +#define APPL_FABRIC_PORT_PREFIX "Fabric" // constants for link monitoring #define MAX_SKIP_CRCERR_ON_LNKUP_POLLS 20 @@ -84,6 +86,7 @@ FabricPortsOrch::FabricPortsOrch(DBConnector *appl_db, vector(new ProducerTable(m_flex_db.get(), APP_FABRIC_PORT_TABLE_NAME)); m_appl_db = shared_ptr(new DBConnector("APPL_DB", 0)); m_applTable = unique_ptr
(new Table(m_appl_db.get(), APP_FABRIC_MONITOR_PORT_TABLE_NAME)); + m_applMonitorConstTable = unique_ptr
(new Table(m_appl_db.get(), APP_FABRIC_MONITOR_DATA_TABLE_NAME)); m_fabricPortStatEnabled = fabricPortStatEnabled; m_fabricQueueStatEnabled = fabricQueueStatEnabled; @@ -379,9 +382,51 @@ void FabricPortsOrch::updateFabricDebugCounters() int recoveryPollsCfg = RECOVERY_POLLS_CFG; // monPollThreshRecovery int errorRateCrcCellsCfg = ERROR_RATE_CRC_CELLS_CFG; // monErrThreshCrcCells int errorRateRxCellsCfg = ERROR_RATE_RX_CELLS_CFG; // monErrThreshRxCells + string applConstKey = FABRIC_MONITOR_DATA; std::vector constValues; SWSS_LOG_INFO("updateFabricDebugCounters"); + bool setCfgVal = m_applMonitorConstTable->get("FABRIC_MONITOR_DATA", constValues); + if (!setCfgVal) + { + SWSS_LOG_INFO("applConstKey %s default values not set", applConstKey.c_str()); + } + else + { + SWSS_LOG_INFO("applConstKey %s default values get set", applConstKey.c_str()); + } + string configVal = "1"; + for (auto cv : constValues) + { + configVal = fvValue(cv); + if (fvField(cv) == "monErrThreshCrcCells") + { + errorRateCrcCellsCfg = stoi(configVal); + SWSS_LOG_INFO("monErrThreshCrcCells: %s %s", configVal.c_str(), fvField(cv).c_str()); + continue; + } + if (fvField(cv) == "monErrThreshRxCells") + { + errorRateRxCellsCfg = stoi(configVal); + SWSS_LOG_INFO("monErrThreshRxCells: %s %s", configVal.c_str(), fvField(cv).c_str()); + continue; + } + if (fvField(cv) == "monPollThreshIsolation") + { + fecIsolatedPolls = stoi(configVal); + isolationPollsCfg = stoi(configVal); + SWSS_LOG_INFO("monPollThreshIsolation: %s %s", configVal.c_str(), fvField(cv).c_str()); + continue; + } + if (fvField(cv) == "monPollThreshRecovery") + { + fecUnisolatePolls = stoi(configVal); + recoveryPollsCfg = stoi(configVal); + SWSS_LOG_INFO("monPollThreshRecovery: %s", configVal.c_str()); + continue; + } + } + // Get debug countesrs (e.g. # of cells with crc errors, # of cells) for (auto p : m_fabricLanePortMap) { @@ -449,6 +494,8 @@ void FabricPortsOrch::updateFabricDebugCounters() // skipCrcErrorsOnLinkupCount SKIP_CRC_ERR_ON_LNKUP_CNT // skipFecErrorsOnLinkupCount SKIP_FEC_ERR_ON_LNKUP_CNT // removeProblemLinkCount RM_PROBLEM_LNK_CNT -- this is for feature of remove a flaky link permanently + // + // cfgIsolated CONFIG_ISOLATED int consecutivePollsWithErrors = 0; int consecutivePollsWithNoErrors = 0; @@ -465,13 +512,45 @@ void FabricPortsOrch::updateFabricDebugCounters() uint64_t testCodeErrors = 0; int autoIsolated = 0; + int cfgIsolated = 0; + int isolated = 0; string lnkStatus = "down"; string testState = "product"; + // Get appl_db values, and update state_db later with other attributes + string applKey = APPL_FABRIC_PORT_PREFIX + to_string(lane); + std::vector applValues; + string applResult = "False"; + bool exist = m_applTable->get(applKey, applValues); + if (!exist) + { + SWSS_LOG_NOTICE("No app infor for port %s", applKey.c_str()); + } + else + { + for (auto v : applValues) + { + applResult = fvValue(v); + if (fvField(v) == "isolateStatus") + { + if (applResult == "True") + { + cfgIsolated = 1; + } + else + { + cfgIsolated = 0; + } + SWSS_LOG_INFO("Port %s isolateStatus: %s %d", + applKey.c_str(), applResult.c_str(), cfgIsolated); + } + } + } + // Get the consecutive polls from the state db std::vector values; string valuePt; - bool exist = m_stateTable->get(key, values); + exist = m_stateTable->get(key, values); if (!exist) { SWSS_LOG_INFO("No state infor for port %s", key.c_str()); @@ -675,7 +754,6 @@ void FabricPortsOrch::updateFabricDebugCounters() valuePt = to_string(autoIsolated); m_stateTable->hset(key, "AUTO_ISOLATED", valuePt); SWSS_LOG_NOTICE("port %s set AUTO_ISOLATED %s", key.c_str(), valuePt.c_str()); - // Call SAI api here to actually isolated the link } else if (autoIsolated == 1 && consecutivePollsWithNoErrors >= recoveryPollsCfg && consecutivePollsWithNoFecErrs >= fecUnisolatePolls) @@ -685,9 +763,28 @@ void FabricPortsOrch::updateFabricDebugCounters() autoIsolated = 0; valuePt = to_string(autoIsolated); m_stateTable->hset(key, "AUTO_ISOLATED", valuePt); - SWSS_LOG_NOTICE("port %s set AUTO_ISOLATED %s", key.c_str(), valuePt.c_str()); - // Can we call SAI api here to unisolate the link? + SWSS_LOG_INFO("port %s set AUTO_ISOLATED %s", key.c_str(), valuePt.c_str()); + } + if (cfgIsolated == 1) + { + isolated = 1; + SWSS_LOG_INFO("port %s keep isolated due to configuation",key.c_str()); + } + else + { + if (autoIsolated == 1) + { + isolated = 1; + SWSS_LOG_INFO("port %s keep isolated due to autoisolation",key.c_str()); + } + else + { + isolated = 0; + SWSS_LOG_INFO("port %s unisolated",key.c_str()); + } } + // if "ISOLATED" is true, Call SAI api here to actually isolated the link + // if "ISOLATED" is false, Call SAP api to actually unisolate the link } else { @@ -726,6 +823,16 @@ void FabricPortsOrch::updateFabricDebugCounters() m_stateTable->hset(key, "CODE_ERRORS", valuePt.c_str()); SWSS_LOG_INFO("port %s set CODE_ERRORS %s", key.c_str(), valuePt.c_str()); + + valuePt = to_string(cfgIsolated); + m_stateTable->hset(key, "CONFIG_ISOLATED", valuePt.c_str()); + SWSS_LOG_INFO("port %s set CONFIG_ISOLATED %s", + key.c_str(), valuePt.c_str()); + + valuePt = to_string(isolated); + m_stateTable->hset(key, "ISOLATED", valuePt.c_str()); + SWSS_LOG_INFO("port %s set ISOLATED %s", + key.c_str(), valuePt.c_str()); } } @@ -733,8 +840,175 @@ void FabricPortsOrch::doTask() { } +void FabricPortsOrch::doFabricPortTask(Consumer &consumer) +{ + SWSS_LOG_NOTICE("FabricPortsOrch::doFabricPortTask"); + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + KeyOpFieldsValuesTuple t = it->second; + string key = kfvKey(t); + string op = kfvOp(t); + + if (op == SET_COMMAND) + { + string alias, lanes; + string isolateStatus; + int forceIsolateCnt = 0; + + for (auto i : kfvFieldsValues(t)) + { + if (fvField(i) == "alias") + { + alias = fvValue(i); + } + else if (fvField(i) == "lanes") + { + lanes = fvValue(i); + } + else if (fvField(i) == "isolateStatus") + { + isolateStatus = fvValue(i); + } + else if (fvField(i) == "forceUnisolateStatus") + { + forceIsolateCnt = stoi(fvValue(i)); + } + } + // This method may be called with only some fields included. + // In that case read in the missing field data. + if (alias == "") + { + string new_alias; + SWSS_LOG_NOTICE("alias is NULL, key: %s", key.c_str()); + if (m_applTable->hget(key, "alias", new_alias)) + { + alias = new_alias; + SWSS_LOG_NOTICE("read new_alias, key: '%s', value: '%s'", key.c_str(), new_alias.c_str()); + } + else + { + SWSS_LOG_NOTICE("hget failed for key: %s, alias", key.c_str()); + } + } + if (lanes == "") + { + string new_lanes; + SWSS_LOG_NOTICE("lanes is NULL, key: %s", key.c_str()); + if (m_applTable->hget(key, "lanes", new_lanes)) + { + lanes = new_lanes; + SWSS_LOG_NOTICE("read new_lanes, key: '%s', value: '%s'", key.c_str(), new_lanes.c_str()); + } + else + { + SWSS_LOG_NOTICE("hget failed for key: %s, lanes", key.c_str()); + } + + } + if (isolateStatus == "") + { + string new_isolateStatus; + SWSS_LOG_NOTICE("isolateStatus is NULL, key: %s", key.c_str()); + if (m_applTable->hget(key, "isolateStatus", new_isolateStatus)) + { + isolateStatus = new_isolateStatus; + SWSS_LOG_NOTICE("read new_isolateStatus, key: '%s', value: '%s'", key.c_str(), new_isolateStatus.c_str()); + } + else + { + SWSS_LOG_NOTICE("hget failed for key: %s, isolateStatus", key.c_str()); + } + } + // Do not process if some data is still missing. + if (alias == "" || lanes == "" || isolateStatus == "" ) + { + SWSS_LOG_NOTICE("NULL values, skipping %s", key.c_str()); + it = consumer.m_toSync.erase(it); + continue; + } + SWSS_LOG_NOTICE("key %s alias %s isolateStatus %s lanes %s", + key.c_str(), alias.c_str(), isolateStatus.c_str(), lanes.c_str()); + // Call SAI api to isolate/unisolate the link here. + // Isolate the link if isolateStatus is True. + // Unisolate the link if isolateStatus is False. + + if (isolateStatus == "False") + { + // get state db value of forceIolatedCntInStateDb, + // if forceIolatedCnt != forceIolatedCntInStateDb + // 1) clear all isolate related flags in stateDb + // 2) replace the cnt in stateb + // + + std::vector values; + string state_key = FABRIC_PORT_PREFIX + lanes; + bool exist = m_stateTable->get(state_key, values); + if (!exist) + { + SWSS_LOG_NOTICE("React to unshut No state infor for port %s", state_key.c_str()); + } + else + { + SWSS_LOG_NOTICE("React to unshut port %s", state_key.c_str()); + } + int curVal = 0; + for (auto val : values) + { + if(fvField(val) == "FORCE_UN_ISOLATE") + { + curVal = stoi(fvValue(val)); + } + } + SWSS_LOG_INFO("Current %d Config %d", curVal, forceIsolateCnt); + if (curVal != forceIsolateCnt) + { + //update state_db; + string value_update; + value_update = to_string(forceIsolateCnt); + m_stateTable->hset(state_key, "FORCE_UN_ISOLATE", value_update.c_str()); + SWSS_LOG_NOTICE("port %s set FORCE_UN_ISOLATE %s", state_key.c_str(), value_update.c_str()); + + + // update all related fields in state_db: + // POLL_WITH_ERRORS 0 + m_stateTable->hset(state_key, "POLL_WITH_ERRORS", + m_defaultPollWithErrors.c_str()); + // POLL_WITH_NO_ERRORS 8 + m_stateTable->hset(state_key, "POLL_WITH_NO_ERRORS", + m_defaultPollWithNoErrors.c_str()); + // POLL_WITH_FEC_ERRORS 0 + m_stateTable->hset(state_key, "POLL_WITH_FEC_ERRORS", + m_defaultPollWithFecErrors.c_str()); + // POLL_WITH_NOFEC_ERRORS 8 + m_stateTable->hset(state_key, "POLL_WITH_NOFEC_ERRORS", + m_defaultPollWithNoFecErrors.c_str()); + // CONFIG_ISOLATED 0 + m_stateTable->hset(state_key, "CONFIG_ISOLATED", + m_defaultConfigIsolated.c_str()); + // ISOLATED 0 + m_stateTable->hset(state_key, "ISOLATED", + m_defaultIsolated.c_str()); + // AUTO_ISOLATED 0 + m_stateTable->hset(state_key, "AUTO_ISOLATED", + m_defaultAutoIsolated.c_str()); + } + } + } + it = consumer.m_toSync.erase(it); + } +} + void FabricPortsOrch::doTask(Consumer &consumer) { + SWSS_LOG_NOTICE("doTask from FabricPortsOrch"); + + string table_name = consumer.getTableName(); + + if (table_name == APP_FABRIC_MONITOR_PORT_TABLE_NAME) + { + doFabricPortTask(consumer); + } } void FabricPortsOrch::doTask(swss::SelectableTimer &timer) @@ -760,7 +1034,7 @@ void FabricPortsOrch::doTask(swss::SelectableTimer &timer) // Skip collecting debug information // as we don't have all fabric ports yet. return; - } + } if (m_getFabricPortListDone) { diff --git a/orchagent/fabricportsorch.h b/orchagent/fabricportsorch.h index 4c274cba00..0d637dec43 100644 --- a/orchagent/fabricportsorch.h +++ b/orchagent/fabricportsorch.h @@ -31,6 +31,7 @@ class FabricPortsOrch : public Orch, public Subject unique_ptr
m_portNamePortCounterTable; unique_ptr
m_fabricCounterTable; unique_ptr
m_applTable; + unique_ptr
m_applMonitorConstTable; unique_ptr m_flexCounterTable; swss::SelectableTimer *m_timer = nullptr; @@ -47,6 +48,15 @@ class FabricPortsOrch : public Orch, public Subject bool m_getFabricPortListDone = false; bool m_isQueueStatsGenerated = false; + + string m_defaultPollWithErrors = "0"; + string m_defaultPollWithNoErrors = "8"; + string m_defaultPollWithFecErrors = "0"; + string m_defaultPollWithNoFecErrors = "8"; + string m_defaultConfigIsolated = "0"; + string m_defaultIsolated = "0"; + string m_defaultAutoIsolated = "0"; + int getFabricPortList(); void generatePortStats(); void updateFabricPortState(); @@ -54,6 +64,7 @@ class FabricPortsOrch : public Orch, public Subject void doTask() override; void doTask(Consumer &consumer); + void doFabricPortTask(Consumer &consumer); void doTask(swss::SelectableTimer &timer); }; diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 63fd037fa6..05e58c6ae9 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -19,6 +19,8 @@ using namespace swss; #define SELECT_TIMEOUT 1000 #define PFC_WD_POLL_MSECS 100 +#define APP_FABRIC_MONITOR_PORT_TABLE_NAME "FABRIC_PORT_TABLE" + /* orchagent heart beat message interval */ #define HEART_BEAT_INTERVAL_MSECS 10 * 1000 @@ -513,8 +515,10 @@ bool OrchDaemon::init() if (m_fabricEnabled) { + // register APP_FABRIC_MONITOR_PORT_TABLE_NAME table + const int fabric_portsorch_base_pri = 30; vector fabric_port_tables = { - // empty for now + { APP_FABRIC_MONITOR_PORT_TABLE_NAME, fabric_portsorch_base_pri } }; gFabricPortsOrch = new FabricPortsOrch(m_applDb, fabric_port_tables, m_fabricPortStatEnabled, m_fabricQueueStatEnabled); m_orchList.push_back(gFabricPortsOrch); @@ -1072,8 +1076,9 @@ bool FabricOrchDaemon::init() SWSS_LOG_ENTER(); SWSS_LOG_NOTICE("FabricOrchDaemon init"); + const int fabric_portsorch_base_pri = 30; vector fabric_port_tables = { - // empty for now, I don't consume anything yet + { APP_FABRIC_MONITOR_PORT_TABLE_NAME, fabric_portsorch_base_pri } }; gFabricPortsOrch = new FabricPortsOrch(m_applDb, fabric_port_tables); addOrchList(gFabricPortsOrch); diff --git a/tests/test_fabric.py b/tests/test_fabric.py index 2d1ea8c293..72ad828790 100644 --- a/tests/test_fabric.py +++ b/tests/test_fabric.py @@ -73,6 +73,14 @@ def test_voq_switch(self, vst): port_counters_stat_keys = flex_db.get_keys("FLEX_COUNTER_TABLE:" + meta_data['group_name']) for port_stat in port_counters_stat_keys: assert port_stat in dict(port_counters_keys.items()).values(), "Non port created on PORT_STAT_COUNTER group: {}".format(port_stat) + + # update some config_db entries + cfg_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + tb = swsscommon.Table(cfg_db, "FABRIC_PORT") + fvs = swsscommon.FieldValuePairs([("isolateStatus","True")]) + tb.set("FABRIC_PORT|Fabric0", fvs ) + fvs = swsscommon.FieldValuePairs([("forceUnisolateStatus", "1")]) + tb.set("FABRIC_PORT|Fabric0", fvs ) else: print( "We do not check switch type:", cfg_switch_type ) diff --git a/tests/virtual_chassis/8/default_config.json b/tests/virtual_chassis/8/default_config.json index b50c86ffff..6f77a1ade2 100644 --- a/tests/virtual_chassis/8/default_config.json +++ b/tests/virtual_chassis/8/default_config.json @@ -10,85 +10,109 @@ "comment" : "default_config for a vs that runs chassis_db" } }, + "FABRIC_MONITOR": { + "FABRIC_MONITOR_DATA": { + "monErrThreshCrcCells": "1", + "monErrThreshRxCells": "61035156", + "monPollThreshRecovery": "8", + "monPollThreshIsolation": "1" + } + }, "FABRIC_PORT": { "Fabric0": { "alias": "Fabric0", "isolateStatus": "False", + "forceUnisolateStatus": "0", "lanes": "0" }, "Fabric1": { "alias": "Fabric1", "isolateStatus": "False", + "forceUnisolateStatus": "0", "lanes": "1" }, "Fabric2": { "alias": "Fabric2", "isolateStatus": "False", + "forceUnisolateStatus": "0", "lanes": "2" }, "Fabric3": { "alias": "Fabric3", "isolateStatus": "False", + "forceUnisolateStatus": "0", "lanes": "3" }, "Fabric4": { "alias": "Fabric4", "isolateStatus": "False", + "forceUnisolateStatus": "0", "lanes": "4" }, "Fabric5": { "alias": "Fabric5", "isolateStatus": "False", + "forceUnisolateStatus": "0", "lanes": "5" }, "Fabric6": { "alias": "Fabric6", "isolateStatus": "False", + "forceUnisolateStatus": "0", "lanes": "6" }, "Fabric7": { "alias": "Fabric7", "isolateStatus": "False", + "forceUnisolateStatus": "0", "lanes": "7" }, "Fabric8": { "alias": "Fabric8", "isolateStatus": "False", + "forceUnisolateStatus": "0", "lanes": "8" }, "Fabric9": { "alias": "Fabric9", "isolateStatus": "False", + "forceUnisolateStatus": "0", "lanes": "9" }, "Fabric10": { "alias": "Fabric10", "isolateStatus": "False", + "forceUnisolateStatus": "0", "lanes": "10" }, "Fabric11": { "alias": "Fabric11", "isolateStatus": "False", + "forceUnisolateStatus": "0", "lanes": "11" }, "Fabric12": { "alias": "Fabric12", "isolateStatus": "False", + "forceUnisolateStatus": "0", "lanes": "12" }, "Fabric13": { "alias": "Fabric13", "isolateStatus": "False", + "forceUnisolateStatus": "0", "lanes": "13" }, "Fabric14": { "alias": "Fabric14", "isolateStatus": "False", + "forceUnisolateStatus": "0", "lanes": "14" }, "Fabric15": { "alias": "Fabric15", "isolateStatus": "False", + "forceUnisolateStatus": "0", "lanes": "15" } } From ec4639536c2c688064c611e7e72616a8dffd0429 Mon Sep 17 00:00:00 2001 From: xiaodong hu <32903206+huseratgithub@users.noreply.github.com> Date: Wed, 17 Apr 2024 01:25:26 +0800 Subject: [PATCH 15/34] [twamporch] Explicitly initialize local variable (#3115) What I did Explicitly initialized local variable. Why I did it We met below error message in sonic-buildimage armhf build (sonic-net/sonic-buildimage#18334) --- orchagent/twamporch.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/orchagent/twamporch.cpp b/orchagent/twamporch.cpp index 58f7b5921f..cd4fe0b666 100644 --- a/orchagent/twamporch.cpp +++ b/orchagent/twamporch.cpp @@ -690,6 +690,7 @@ task_process_status TwampOrch::createEntry(const string& key, const vector Date: Tue, 16 Apr 2024 17:26:42 -0500 Subject: [PATCH 16/34] Add bookworm build to the PR checkers (#3114) What I did Add a Bookworm build to the PR checkers. Also fix some Bookworm build errors that crept in. Why I did it Buildimage now builds swss for Bookworm, so the build needs to succeed. --- azure-pipelines.yml | 39 +++++++++++++++++++++ orchagent/p4orch/tests/acl_manager_test.cpp | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 083fb1047c..e3255ba15b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -92,6 +92,45 @@ stages: artifact_name: sonic-swss.arm64 archive_gcov: false +- stage: BuildBookworm + dependsOn: BuildArm + condition: succeeded('BuildArm') + jobs: + - template: .azure-pipelines/build-template.yml + parameters: + arch: amd64 + pool: sonicbld + sonic_slave: sonic-slave-bookworm + common_lib_artifact_name: common-lib + swss_common_artifact_name: sonic-swss-common-bookworm + sairedis_artifact_name: sonic-sairedis-bookworm + artifact_name: sonic-swss-bookworm + archive_gcov: false + + - template: .azure-pipelines/build-template.yml + parameters: + arch: armhf + timeout: 240 + pool: sonicbld-armhf + sonic_slave: sonic-slave-bookworm-armhf + common_lib_artifact_name: common-lib.armhf + swss_common_artifact_name: sonic-swss-common-bookworm.armhf + sairedis_artifact_name: sonic-sairedis-bookworm.armhf + artifact_name: sonic-swss-bookworm.armhf + archive_gcov: false + + - template: .azure-pipelines/build-template.yml + parameters: + arch: arm64 + timeout: 240 + pool: sonicbld-arm64 + sonic_slave: sonic-slave-bookworm-arm64 + common_lib_artifact_name: common-lib.arm64 + swss_common_artifact_name: sonic-swss-common-bookworm.arm64 + sairedis_artifact_name: sonic-sairedis-bookworm.arm64 + artifact_name: sonic-swss-bookworm.arm64 + archive_gcov: false + - stage: BuildDocker dependsOn: Build condition: succeeded('Build') diff --git a/orchagent/p4orch/tests/acl_manager_test.cpp b/orchagent/p4orch/tests/acl_manager_test.cpp index 107dfdfde5..13856c07ea 100644 --- a/orchagent/p4orch/tests/acl_manager_test.cpp +++ b/orchagent/p4orch/tests/acl_manager_test.cpp @@ -240,7 +240,7 @@ std::string BuildMatchFieldJsonStrKindComposite(std::vector elem { nlohmann::json match_json; match_json[kAclMatchFieldKind] = kAclMatchFieldKindComposite; - for (const auto element : elements) + for (const auto &element : elements) { match_json[kAclMatchFieldElements].push_back(element); } From 5ef737087a15f23d2038ca840e935f402ad92f31 Mon Sep 17 00:00:00 2001 From: bingwang-ms <66248323+bingwang-ms@users.noreply.github.com> Date: Mon, 22 Apr 2024 13:23:29 -0700 Subject: [PATCH 17/34] [ACL] Remove flex counter when updating ACL rule (#3118) What I did This PR is to fix sonic-net/sonic-buildimage#18719 When ACL rule is created for the first time, a flex counter is created and registered. When the same ACL rule is being updated, the FlexCounter created before is not removed, and another FlexCounter is created and registered. Why I did it Fix the issue that FlexCounter is duplicated when updating existing ACL rule. --- orchagent/aclorch.cpp | 6 ++++++ tests/dvslib/dvs_acl.py | 18 +++++++++++++++++- tests/test_acl.py | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/orchagent/aclorch.cpp b/orchagent/aclorch.cpp index 6906744cc2..5ad908f082 100644 --- a/orchagent/aclorch.cpp +++ b/orchagent/aclorch.cpp @@ -2586,6 +2586,12 @@ bool AclTable::add(shared_ptr newRule) if (ruleIter != rules.end()) { // If ACL rule already exists, delete it first + if (ruleIter->second->hasCounter()) + { + // Deregister the flex counter before deleting the rule + // A new flex counter will be created when the new rule is added + m_pAclOrch->deregisterFlexCounter(*(ruleIter->second)); + } if (ruleIter->second->remove()) { rules.erase(ruleIter); diff --git a/tests/dvslib/dvs_acl.py b/tests/dvslib/dvs_acl.py index 4315da3798..236ccaa0fc 100644 --- a/tests/dvslib/dvs_acl.py +++ b/tests/dvslib/dvs_acl.py @@ -685,6 +685,17 @@ def _match_acl_range(sai_acl_range): return True return _match_acl_range + + def get_acl_counter_oid(self, acl_rule_id=None) -> str: + if not acl_rule_id: + acl_rule_id = self._get_acl_rule_id() + + entry = self.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY", acl_rule_id) + counter_oid = entry.get("SAI_ACL_ENTRY_ATTR_ACTION_COUNTER") + return counter_oid + + def get_acl_rule_id(self) -> str: + return self._get_acl_rule_id() def _get_acl_rule_id(self) -> str: num_keys = len(self.asic_db.default_acl_entries) + 1 @@ -742,7 +753,12 @@ def _check_acl_entry_counters_map(self, acl_entry_oid: str): return rule_to_counter_map = self.counters_db.get_entry("ACL_COUNTER_RULE_MAP", "") counter_to_rule_map = {v: k for k, v in rule_to_counter_map.items()} - assert counter_oid in counter_to_rule_map + assert counter_oid in counter_to_rule_map + + def check_acl_counter_not_in_counters_map(self, acl_counter_oid: str): + rule_to_counter_map = self.counters_db.get_entry("ACL_COUNTER_RULE_MAP", "") + counter_to_rule_map = {v: k for k, v in rule_to_counter_map.items()} + assert acl_counter_oid not in counter_to_rule_map def verify_acl_table_status( self, diff --git a/tests/test_acl.py b/tests/test_acl.py index cf68d1516e..ed5789b2b0 100644 --- a/tests/test_acl.py +++ b/tests/test_acl.py @@ -1,5 +1,6 @@ import pytest from requests import request +import time L3_TABLE_TYPE = "L3" L3_TABLE_NAME = "L3_TEST" @@ -131,6 +132,38 @@ def test_InvalidAclRuleCreation(self, dvs_acl, l3_acl_table): dvs_acl.verify_acl_rule_status(L3_TABLE_NAME, "INVALID_RULE", None) dvs_acl.verify_no_acl_rules() + def test_AclRuleUpdate(self, dvs_acl, l3_acl_table): + """The test is to verify there is no duplicated flex counter when updating an ACL rule + """ + config_qualifiers = {"SRC_IP": "10.10.10.10/32"} + expected_sai_qualifiers = { + "SAI_ACL_ENTRY_ATTR_FIELD_SRC_IP": dvs_acl.get_simple_qualifier_comparator("10.10.10.10&mask:255.255.255.255") + } + + dvs_acl.create_acl_rule(L3_TABLE_NAME, L3_RULE_NAME, config_qualifiers) + dvs_acl.verify_acl_rule(expected_sai_qualifiers) + + acl_rule_id = dvs_acl.get_acl_rule_id() + counter_id = dvs_acl.get_acl_counter_oid() + + new_config_qualifiers = {"SRC_IP": "10.10.10.11/32"} + new_expected_sai_qualifiers = { + "SAI_ACL_ENTRY_ATTR_FIELD_SRC_IP": dvs_acl.get_simple_qualifier_comparator("10.10.10.11&mask:255.255.255.255") + } + dvs_acl.update_acl_rule(L3_TABLE_NAME, L3_RULE_NAME, new_config_qualifiers) + # Verify the rule has been updated + retry = 5 + while dvs_acl.get_acl_rule_id() == acl_rule_id and retry >= 0: + retry -= 1 + time.sleep(1) + assert retry > 0 + dvs_acl.verify_acl_rule(new_expected_sai_qualifiers) + # Verify the previous counter is removed + if counter_id: + dvs_acl.check_acl_counter_not_in_counters_map(counter_id) + dvs_acl.remove_acl_rule(L3_TABLE_NAME, L3_RULE_NAME) + dvs_acl.verify_no_acl_rules() + def test_AclRuleL4SrcPort(self, dvs_acl, l3_acl_table): config_qualifiers = {"L4_SRC_PORT": "65000"} expected_sai_qualifiers = { From 054ed34bc162677bf5f4993a81a1477881041cce Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Tue, 30 Apr 2024 05:49:09 +0800 Subject: [PATCH 18/34] Support ASIC/SDK health event (#3020) * ASIC/SDK health event Support ASIC/SDK health event Fetch capabilities and expose to STATE_DB Register the event handler and categories for each severity when supported Handle suppress ASIC/SDK health event categories Handle ASIC/SDK health event reported by SAI redis in the callback context --- orchagent/Makefile.am | 1 + orchagent/eliminate_events.lua | 63 +++++ orchagent/notifications.cpp | 24 ++ orchagent/notifications.h | 8 + orchagent/orchdaemon.cpp | 2 + orchagent/p4orch/tests/Makefile.am | 1 + orchagent/p4orch/tests/test_main.cpp | 2 + orchagent/switchorch.cpp | 360 ++++++++++++++++++++++++++- orchagent/switchorch.h | 32 +++ tests/mock_tests/Makefile.am | 1 + tests/mock_tests/mock_table.cpp | 47 ++-- tests/mock_tests/switchorch_ut.cpp | 316 +++++++++++++++++++++++ 12 files changed, 839 insertions(+), 18 deletions(-) create mode 100644 orchagent/eliminate_events.lua create mode 100644 tests/mock_tests/switchorch_ut.cpp diff --git a/orchagent/Makefile.am b/orchagent/Makefile.am index e7743ab44d..7e1d0b7143 100644 --- a/orchagent/Makefile.am +++ b/orchagent/Makefile.am @@ -17,6 +17,7 @@ CFLAGS_SAI = -I /usr/include/sai swssdir = $(datadir)/swss dist_swss_DATA = \ + eliminate_events.lua \ rif_rates.lua \ pfc_detect_innovium.lua \ pfc_detect_mellanox.lua \ diff --git a/orchagent/eliminate_events.lua b/orchagent/eliminate_events.lua new file mode 100644 index 0000000000..871e6c1fb0 --- /dev/null +++ b/orchagent/eliminate_events.lua @@ -0,0 +1,63 @@ +-- KEYS - None +-- ARGV - None + +local state_db = "6" +local config_db = "4" + +local result = {} + +redis.call('SELECT', config_db) +local severity_keys = redis.call('KEYS', 'SUPPRESS_ASIC_SDK_HEALTH_EVENT*') +if #severity_keys == 0 then + return result +end + +local max_events = {} +for i = 1, #severity_keys, 1 do + local max_event = redis.call('HGET', severity_keys[i], 'max_events') + if max_event then + max_events[string.sub(severity_keys[i], 32, -1)] = tonumber(max_event) + end +end + +if not next (max_events) then + return result +end + +redis.call('SELECT', state_db) +local events = {} + +local event_keys = redis.call('KEYS', 'ASIC_SDK_HEALTH_EVENT_TABLE*') + +if #event_keys == 0 then + return result +end + +for i = 1, #event_keys, 1 do + local severity = redis.call('HGET', event_keys[i], 'severity') + if max_events[severity] ~= nil then + if events[severity] == nil then + events[severity] = {} + end + table.insert(events[severity], event_keys[i]) + end +end + +for severity in pairs(max_events) do + local number_received_events = 0 + if events[severity] ~= nil then + number_received_events = #events[severity] + end + if number_received_events > max_events[severity] then + table.sort(events[severity]) + local number_to_eliminate = number_received_events - max_events[severity] + for i = 1, number_to_eliminate, 1 do + redis.call('DEL', events[severity][i]) + end + table.insert(result, severity .. " events: maximum " .. max_events[severity] .. ", received " .. number_received_events .. ", eliminated " .. number_to_eliminate) + else + table.insert(result, severity .. " events: maximum " .. max_events[severity] .. ", received " .. number_received_events .. ", not exceeding the maximum") + end +end + +return result diff --git a/orchagent/notifications.cpp b/orchagent/notifications.cpp index 9455620fb5..4738ba28fb 100644 --- a/orchagent/notifications.cpp +++ b/orchagent/notifications.cpp @@ -4,6 +4,9 @@ extern "C" { #include "logger.h" #include "notifications.h" +#include "switchorch.h" + +extern SwitchOrch *gSwitchOrch; #ifdef ASAN_ENABLED #include @@ -40,6 +43,12 @@ void on_switch_shutdown_request(sai_object_id_t switch_id) /* TODO: Later a better restart story will be told here */ SWSS_LOG_ERROR("Syncd stopped"); + if (gSwitchOrch->isFatalEventReceived()) + { + SWSS_LOG_ERROR("Orchagent aborted due to fatal SAI error received"); + abort(); + } + /* The quick_exit() is used instead of the exit() to avoid a following data race: * the exit() calls the destructors for global static variables (e.g.BufferOrch::m_buffer_type_maps) @@ -59,3 +68,18 @@ void on_port_host_tx_ready(sai_object_id_t switch_id, sai_object_id_t port_id, s // don't use this event handler, because it runs by libsairedis in a separate thread // which causes concurrency access to the DB } + +void on_switch_asic_sdk_health_event(sai_object_id_t switch_id, + sai_switch_asic_sdk_health_severity_t severity, + sai_timespec_t timestamp, + sai_switch_asic_sdk_health_category_t category, + sai_switch_health_data_t data, + const sai_u8_list_t description) +{ + gSwitchOrch->onSwitchAsicSdkHealthEvent(switch_id, + severity, + timestamp, + category, + data, + description); +} diff --git a/orchagent/notifications.h b/orchagent/notifications.h index 403b358a12..f639d332c5 100644 --- a/orchagent/notifications.h +++ b/orchagent/notifications.h @@ -12,4 +12,12 @@ void on_twamp_session_event(uint32_t count, sai_twamp_session_event_notification // The function prototype information can be found here: // https://github.com/sonic-net/sonic-sairedis/blob/master/meta/NotificationSwitchShutdownRequest.cpp#L49 void on_switch_shutdown_request(sai_object_id_t switch_id); + void on_port_host_tx_ready(sai_object_id_t switch_id, sai_object_id_t port_id, sai_port_host_tx_ready_status_t m_portHostTxReadyStatus); + +void on_switch_asic_sdk_health_event(sai_object_id_t switch_id, + sai_switch_asic_sdk_health_severity_t severity, + sai_timespec_t timestamp, + sai_switch_asic_sdk_health_category_t category, + sai_switch_health_data_t data, + const sai_u8_list_t description); diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 05e58c6ae9..568c84e733 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -117,10 +117,12 @@ bool OrchDaemon::init() TableConnector app_switch_table(m_applDb, APP_SWITCH_TABLE_NAME); TableConnector conf_asic_sensors(m_configDb, CFG_ASIC_SENSORS_TABLE_NAME); TableConnector conf_switch_hash(m_configDb, CFG_SWITCH_HASH_TABLE_NAME); + TableConnector conf_suppress_asic_sdk_health_categories(m_configDb, CFG_SUPPRESS_ASIC_SDK_HEALTH_EVENT_NAME); vector switch_tables = { conf_switch_hash, conf_asic_sensors, + conf_suppress_asic_sdk_health_categories, app_switch_table }; diff --git a/orchagent/p4orch/tests/Makefile.am b/orchagent/p4orch/tests/Makefile.am index d541bbe637..2c7301311f 100644 --- a/orchagent/p4orch/tests/Makefile.am +++ b/orchagent/p4orch/tests/Makefile.am @@ -35,6 +35,7 @@ p4orch_tests_SOURCES = $(ORCHAGENT_DIR)/orch.cpp \ $(ORCHAGENT_DIR)/flex_counter/flow_counter_handler.cpp \ $(ORCHAGENT_DIR)/port/port_capabilities.cpp \ $(ORCHAGENT_DIR)/port/porthlpr.cpp \ + $(ORCHAGENT_DIR)/notifications.cpp \ $(P4ORCH_DIR)/p4oidmapper.cpp \ $(P4ORCH_DIR)/p4orch.cpp \ $(P4ORCH_DIR)/p4orch_util.cpp \ diff --git a/orchagent/p4orch/tests/test_main.cpp b/orchagent/p4orch/tests/test_main.cpp index 0170588a42..96d005ea24 100644 --- a/orchagent/p4orch/tests/test_main.cpp +++ b/orchagent/p4orch/tests/test_main.cpp @@ -35,6 +35,8 @@ sai_object_id_t kMirrorSessionOid1 = 9001; char *gMirrorSession2 = "mirror-session-2"; sai_object_id_t kMirrorSessionOid2 = 9002; sai_object_id_t gUnderlayIfId; +string gMyAsicName = ""; +event_handle_t g_events_handle; #define DEFAULT_BATCH_SIZE 128 #define DEFAULT_MAX_BULK_SIZE 1000 diff --git a/orchagent/switchorch.cpp b/orchagent/switchorch.cpp index 06dc36e472..9dc9bcfbde 100644 --- a/orchagent/switchorch.cpp +++ b/orchagent/switchorch.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "switchorch.h" #include "crmorch.h" @@ -10,6 +11,9 @@ #include "macaddress.h" #include "return_code.h" #include "saihelper.h" +#include "sai_serialize.h" +#include "notifications.h" +#include "redisapi.h" using namespace std; using namespace swss; @@ -20,6 +24,8 @@ extern sai_acl_api_t *sai_acl_api; extern sai_hash_api_t *sai_hash_api; extern MacAddress gVxlanMacAddress; extern CrmOrch *gCrmOrch; +extern event_handle_t g_events_handle; +extern string gMyAsicName; const map switch_attribute_map = { @@ -47,6 +53,43 @@ const map packet_action_map = {"trap", SAI_PACKET_ACTION_TRAP} }; +const map switch_asic_sdk_health_event_severity_to_switch_attribute_map = +{ + {"fatal", SAI_SWITCH_ATTR_REG_FATAL_SWITCH_ASIC_SDK_HEALTH_CATEGORY}, + {"warning", SAI_SWITCH_ATTR_REG_WARNING_SWITCH_ASIC_SDK_HEALTH_CATEGORY}, + {"notice", SAI_SWITCH_ATTR_REG_NOTICE_SWITCH_ASIC_SDK_HEALTH_CATEGORY} +}; + +const map switch_asic_sdk_health_event_severity_reverse_map = +{ + {SAI_SWITCH_ASIC_SDK_HEALTH_SEVERITY_FATAL, "fatal"}, + {SAI_SWITCH_ASIC_SDK_HEALTH_SEVERITY_WARNING, "warning"}, + {SAI_SWITCH_ASIC_SDK_HEALTH_SEVERITY_NOTICE, "notice"}, +}; + +const map switch_asic_sdk_health_event_category_reverse_map = +{ + {SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_SW, "software"}, + {SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_FW, "firmware"}, + {SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_CPU_HW, "cpu_hw"}, + {SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_ASIC_HW, "asic_hw"} +}; + +const map switch_asic_sdk_health_event_category_map = +{ + {"software", SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_SW}, + {"firmware", SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_FW}, + {"cpu_hw", SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_CPU_HW}, + {"asic_hw", SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_ASIC_HW} +}; + +const std::set switch_asic_sdk_health_event_category_universal_set = +{ + SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_SW, + SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_FW, + SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_CPU_HW, + SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_ASIC_HW +}; const std::set switch_non_sai_attribute_set = {"ordered_ecmp"}; @@ -77,12 +120,15 @@ SwitchOrch::SwitchOrch(DBConnector *db, vector& connectors, Tabl m_db(db), m_stateDb(new DBConnector(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0)), m_asicSensorsTable(new Table(m_stateDb.get(), ASIC_TEMPERATURE_INFO_TABLE_NAME)), - m_sensorsPollerTimer (new SelectableTimer((timespec { .tv_sec = DEFAULT_ASIC_SENSORS_POLLER_INTERVAL, .tv_nsec = 0 }))) + m_sensorsPollerTimer (new SelectableTimer((timespec { .tv_sec = DEFAULT_ASIC_SENSORS_POLLER_INTERVAL, .tv_nsec = 0 }))), + m_stateDbForNotification(new DBConnector(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0)), + m_asicSdkHealthEventTable(new Table(m_stateDbForNotification.get(), STATE_ASIC_SDK_HEALTH_EVENT_TABLE_NAME)) { m_restartCheckNotificationConsumer = new NotificationConsumer(db, "RESTARTCHECK"); auto restartCheckNotifier = new Notifier(m_restartCheckNotificationConsumer, this, "RESTARTCHECK"); Orch::addExecutor(restartCheckNotifier); + initAsicSdkHealthEventNotification(); set_switch_pfc_dlr_init_capability(); initSensorsTable(); querySwitchTpidCapability(); @@ -93,6 +139,100 @@ SwitchOrch::SwitchOrch(DBConnector *db, vector& connectors, Tabl Orch::addExecutor(executorT); } +void SwitchOrch::initAsicSdkHealthEventNotification() +{ + sai_attribute_t attr; + sai_status_t status; + vector fvVector; + vector> reg_severities = { + {SAI_SWITCH_ATTR_REG_FATAL_SWITCH_ASIC_SDK_HEALTH_CATEGORY, SWITCH_CAPABILITY_TABLE_REG_FATAL_ASIC_SDK_HEALTH_CATEGORY, "fatal"}, + {SAI_SWITCH_ATTR_REG_WARNING_SWITCH_ASIC_SDK_HEALTH_CATEGORY, SWITCH_CAPABILITY_TABLE_REG_WARNING_ASIC_SDK_HEALTH_CATEGORY, "warning"}, + {SAI_SWITCH_ATTR_REG_NOTICE_SWITCH_ASIC_SDK_HEALTH_CATEGORY, SWITCH_CAPABILITY_TABLE_REG_NOTICE_ASIC_SDK_HEALTH_CATEGORY, "notice"} + }; + + bool supported = querySwitchCapability(SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_SWITCH_ASIC_SDK_HEALTH_EVENT_NOTIFY); + if (supported) + { + attr.id = SAI_SWITCH_ATTR_SWITCH_ASIC_SDK_HEALTH_EVENT_NOTIFY; + attr.value.ptr = (void *)on_switch_asic_sdk_health_event; + status = sai_switch_api->set_switch_attribute(gSwitchId, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to register ASIC/SDK health event handler: %s", sai_serialize_status(status).c_str()); + supported = false; + } + else + { + fvVector.emplace_back(SWITCH_CAPABILITY_TABLE_ASIC_SDK_HEALTH_EVENT_CAPABLE, "true"); + } + } + else + { + SWSS_LOG_NOTICE("ASIC/SDK health event is not supported"); + } + + DBConnector cfgDb("CONFIG_DB", 0); + Table cfgSuppressASHETable(&cfgDb, CFG_SUPPRESS_ASIC_SDK_HEALTH_EVENT_NAME); + string suppressedCategories; + bool atLeastOneSupported = false; + + if (!supported) + { + fvVector.emplace_back(SWITCH_CAPABILITY_TABLE_ASIC_SDK_HEALTH_EVENT_CAPABLE, "false"); + for (auto c : reg_severities) + { + fvVector.emplace_back(get<1>(c), "false"); + } + set_switch_capability(fvVector); + + return; + } + + for (auto c : reg_severities) + { + supported = querySwitchCapability(SAI_OBJECT_TYPE_SWITCH, get<0>(c)); + if (supported) + { + cfgSuppressASHETable.hget(get<2>(c), "categories", suppressedCategories); + registerAsicSdkHealthEventCategories(get<0>(c), get<2>(c), suppressedCategories, true); + suppressedCategories.clear(); + + m_supportedAsicSdkHealthEventAttributes.insert(get<0>(c)); + fvVector.emplace_back(get<1>(c), "true"); + } + else + { + SWSS_LOG_NOTICE("Unsupport to register ASIC/SDK health categories for severity %s", get<2>(c).c_str()); + fvVector.emplace_back(get<1>(c), "false"); + } + atLeastOneSupported = atLeastOneSupported || supported; + } + + set_switch_capability(fvVector); + + if (atLeastOneSupported) + { + try + { + // Load the Lua script to eliminate oldest entries + string eliminateEventsLuaScript = swss::loadLuaScript("eliminate_events.lua"); + m_eliminateEventsSha = swss::loadRedisScript(m_stateDb.get(), eliminateEventsLuaScript); + + // Init timer + auto interv = timespec { .tv_sec = ASIC_SDK_HEALTH_EVENT_ELIMINATE_INTERVAL, .tv_nsec = 0 }; + m_eliminateEventsTimer = new SelectableTimer(interv); + auto executor = new ExecutableTimer(m_eliminateEventsTimer, this, "ASIC_SDK_HEALTH_EVENT_ELIMINATE_TIMER"); + Orch::addExecutor(executor); + m_eliminateEventsTimer->start(); + } + catch (...) + { + // This can happen only on mock test. If it happens on a real switch, we should log an error message + SWSS_LOG_ERROR("Unable to load the Lua script to eliminate events\n"); + } + } +} + void SwitchOrch::initAclGroupsBindToSwitch() { // Create an ACL group per stage, INGRESS, EGRESS and PRE_INGRESS @@ -726,6 +866,133 @@ void SwitchOrch::doCfgSwitchHashTableTask(Consumer &consumer) } } +void SwitchOrch::registerAsicSdkHealthEventCategories(sai_switch_attr_t saiSeverity, const string &severityString, const string &suppressed_category_list, bool isInitializing) +{ + sai_status_t status; + set interested_categories_set = switch_asic_sdk_health_event_category_universal_set; + + SWSS_LOG_INFO("Register ASIC/SDK health event for severity %s(%d) with categories [%s] suppressed", severityString.c_str(), saiSeverity, suppressed_category_list.c_str()); + + if (!suppressed_category_list.empty()) + { + auto &&categories = tokenize(suppressed_category_list, ','); + for (auto category : categories) + { + try + { + interested_categories_set.erase(switch_asic_sdk_health_event_category_map.at(category)); + } + catch (std::out_of_range &e) + { + SWSS_LOG_ERROR("Unknown ASIC/SDK health category %s to suppress", category.c_str()); + continue; + } + } + } + + if (isInitializing && interested_categories_set.empty()) + { + SWSS_LOG_INFO("All categories are suppressed for severity %s", severityString.c_str()); + return; + } + + vector sai_categories(interested_categories_set.begin(), interested_categories_set.end()); + sai_attribute_t attr; + + attr.id = saiSeverity; + attr.value.s32list.count = (uint32_t)sai_categories.size(); + attr.value.s32list.list = sai_categories.data(); + status = sai_switch_api->set_switch_attribute(gSwitchId, &attr); + + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to register ASIC/SDK health event categories for severity %s, status: %s", severityString.c_str(), sai_serialize_status(status).c_str()); + } +} + +void SwitchOrch::doCfgSuppressAsicSdkHealthEventTableTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + + auto &map = consumer.m_toSync; + auto it = map.begin(); + + while (it != map.end()) + { + auto keyOpFieldsValues = it->second; + auto key = kfvKey(keyOpFieldsValues); + auto op = kfvOp(keyOpFieldsValues); + + SWSS_LOG_INFO("KEY: %s, OP: %s", key.c_str(), op.c_str()); + + if (key.empty()) + { + SWSS_LOG_ERROR("Failed to parse switch hash key: empty string"); + it = map.erase(it); + continue; + } + + sai_switch_attr_t saiSeverity; + try + { + saiSeverity = switch_asic_sdk_health_event_severity_to_switch_attribute_map.at(key); + } + catch (std::out_of_range &e) + { + SWSS_LOG_ERROR("Unknown severity %s in SUPPRESS_ASIC_SDK_HEALTH_EVENT table", key.c_str()); + it = map.erase(it); + continue; + } + + if (op == SET_COMMAND) + { + bool categoriesConfigured = false; + bool continueMainLoop = false; + for (const auto &cit : kfvFieldsValues(keyOpFieldsValues)) + { + auto fieldName = fvField(cit); + auto fieldValue = fvValue(cit); + + SWSS_LOG_INFO("FIELD: %s, VALUE: %s", fieldName.c_str(), fieldValue.c_str()); + + if (m_supportedAsicSdkHealthEventAttributes.find(saiSeverity) == m_supportedAsicSdkHealthEventAttributes.end()) + { + SWSS_LOG_NOTICE("Unsupport to register categories on severity %d", saiSeverity); + it = map.erase(it); + continueMainLoop = true; + break; + } + + if (fieldName == "categories") + { + registerAsicSdkHealthEventCategories(saiSeverity, key, fieldValue); + categoriesConfigured = true; + } + } + + if (continueMainLoop) + { + continue; + } + + if (!categoriesConfigured) + { + registerAsicSdkHealthEventCategories(saiSeverity, key); + } + } + else if (op == DEL_COMMAND) + { + registerAsicSdkHealthEventCategories(saiSeverity, key); + } + else + { + SWSS_LOG_ERROR("Unknown operation(%s)", op.c_str()); + } + + it = map.erase(it); + } +} + void SwitchOrch::doTask(Consumer &consumer) { SWSS_LOG_ENTER(); @@ -744,6 +1011,10 @@ void SwitchOrch::doTask(Consumer &consumer) { doCfgSwitchHashTableTask(consumer); } + else if (tableName == CFG_SUPPRESS_ASIC_SDK_HEALTH_EVENT_NAME) + { + doCfgSuppressAsicSdkHealthEventTableTask(consumer); + } else { SWSS_LOG_ERROR("Unknown table : %s", tableName.c_str()); @@ -799,6 +1070,85 @@ void SwitchOrch::restartCheckReply(const string &op, const string &data, std::ve checkRestartReadyDone(); } +void SwitchOrch::onSwitchAsicSdkHealthEvent(sai_object_id_t switch_id, + sai_switch_asic_sdk_health_severity_t severity, + sai_timespec_t timestamp, + sai_switch_asic_sdk_health_category_t category, + sai_switch_health_data_t data, + const sai_u8_list_t &description) +{ + std::vector values; + const string &severity_str = switch_asic_sdk_health_event_severity_reverse_map.at(severity); + const string &category_str = switch_asic_sdk_health_event_category_reverse_map.at(category); + string description_str; + const std::time_t &t = (std::time_t)timestamp.tv_sec; + stringstream time_ss; + time_ss << std::put_time(std::localtime(&t), "%Y-%m-%d %H:%M:%S"); + + switch (data.data_type) + { + case SAI_HEALTH_DATA_TYPE_GENERAL: + { + vector description_with_terminator(description.list, description.list + description.count); + // Add the terminate character + description_with_terminator.push_back(0); + description_str = string(reinterpret_cast(description_with_terminator.data())); + // Remove unprintable characters but keep CR and NL + if (description_str.end() != + description_str.erase(std::remove_if( + description_str.begin(), + description_str.end(), + [](unsigned char x) { + return (x != 0x0d) && (x != 0x0a) && !std::isprint(x); + }), + description_str.end())) + { + SWSS_LOG_NOTICE("Unprintable characters in description of ASIC/SDK health event"); + } + break; + } + default: + SWSS_LOG_ERROR("Unknown data type %d when receiving ASIC/SDK health event", data.data_type); + // Do not return. The ASIC/SDK health event will still be recorded but without the description + break; + } + + event_params_t params = { + { "sai_timestamp", time_ss.str() }, + { "severity", severity_str }, + { "category", category_str }, + { "description", description_str }}; + + string asic_name_str; + if (!gMyAsicName.empty()) + { + asic_name_str = "asic " + gMyAsicName + ","; + params["asic_name"] = gMyAsicName; + } + + if (severity == SAI_SWITCH_ASIC_SDK_HEALTH_SEVERITY_FATAL) + { + SWSS_LOG_ERROR("[%s] ASIC/SDK health event occurred at %s, %scategory %s: %s", severity_str.c_str(), time_ss.str().c_str(), asic_name_str.c_str(), category_str.c_str(), description_str.c_str()); + } + else + { + SWSS_LOG_NOTICE("[%s] ASIC/SDK health event occurred at %s, %scategory %s: %s", severity_str.c_str(), time_ss.str().c_str(), asic_name_str.c_str(), category_str.c_str(), description_str.c_str()); + } + + values.emplace_back("severity", severity_str); + values.emplace_back("category", category_str); + values.emplace_back("description", description_str); + + m_asicSdkHealthEventTable->set(time_ss.str(),values); + + event_publish(g_events_handle, "asic-sdk-health-event", ¶ms); + + if (severity == SAI_SWITCH_ASIC_SDK_HEALTH_SEVERITY_FATAL) + { + m_fatalEventCount++; + } +} + bool SwitchOrch::setAgingFDB(uint32_t sec) { sai_attribute_t attr; @@ -912,6 +1262,14 @@ void SwitchOrch::doTask(SelectableTimer &timer) } } } + else if (&timer == m_eliminateEventsTimer) + { + auto ret = swss::runRedisScript(*m_stateDb, m_eliminateEventsSha, {}, {}); + for (auto str: ret) + { + SWSS_LOG_INFO("Eliminate ASIC/SDK health %s", str.c_str()); + } + } } void SwitchOrch::initSensorsTable() diff --git a/orchagent/switchorch.h b/orchagent/switchorch.h index 7135bcdc39..5c347e0887 100644 --- a/orchagent/switchorch.h +++ b/orchagent/switchorch.h @@ -16,6 +16,12 @@ #define SWITCH_CAPABILITY_TABLE_PFC_DLR_INIT_CAPABLE "PFC_DLR_INIT_CAPABLE" #define SWITCH_CAPABILITY_TABLE_PORT_EGRESS_SAMPLE_CAPABLE "PORT_EGRESS_SAMPLE_CAPABLE" +#define ASIC_SDK_HEALTH_EVENT_ELIMINATE_INTERVAL 3600 +#define SWITCH_CAPABILITY_TABLE_ASIC_SDK_HEALTH_EVENT_CAPABLE "ASIC_SDK_HEALTH_EVENT" +#define SWITCH_CAPABILITY_TABLE_REG_FATAL_ASIC_SDK_HEALTH_CATEGORY "REG_FATAL_ASIC_SDK_HEALTH_CATEGORY" +#define SWITCH_CAPABILITY_TABLE_REG_WARNING_ASIC_SDK_HEALTH_CATEGORY "REG_WARNING_ASIC_SDK_HEALTH_CATEGORY" +#define SWITCH_CAPABILITY_TABLE_REG_NOTICE_ASIC_SDK_HEALTH_CATEGORY "REG_NOTICE_ASIC_SDK_HEALTH_CATEGORY" + struct WarmRestartCheck { bool checkRestartReadyState; @@ -46,11 +52,24 @@ class SwitchOrch : public Orch bool checkOrderedEcmpEnable() { return m_orderedEcmpEnable; } + void onSwitchAsicSdkHealthEvent(sai_object_id_t switch_id, + sai_switch_asic_sdk_health_severity_t severity, + sai_timespec_t timestamp, + sai_switch_asic_sdk_health_category_t category, + sai_switch_health_data_t data, + const sai_u8_list_t &description); + + inline bool isFatalEventReceived() const + { + return (m_fatalEventCount != 0); + } + private: void doTask(Consumer &consumer); void doTask(swss::SelectableTimer &timer); void doCfgSwitchHashTableTask(Consumer &consumer); void doCfgSensorsTableTask(Consumer &consumer); + void doCfgSuppressAsicSdkHealthEventTableTask(Consumer &consumer); void doAppSwitchTableTask(Consumer &consumer); void initSensorsTable(); void querySwitchTpidCapability(); @@ -79,6 +98,8 @@ class SwitchOrch : public Orch swss::NotificationConsumer* m_restartCheckNotificationConsumer; void doTask(swss::NotificationConsumer& consumer); + void doAsicSdkHealthEventNotificationConsumerTask(swss::NotificationConsumer& consumer); + void doRestartCheckNotificationConsumerTask(swss::NotificationConsumer& consumer); swss::DBConnector *m_db; swss::Table m_switchTable; std::map m_aclGroups; @@ -99,6 +120,17 @@ class SwitchOrch : public Orch bool m_orderedEcmpEnable = false; bool m_PfcDlrInitEnable = false; + // ASIC SDK health event + std::shared_ptr m_stateDbForNotification = nullptr; + std::shared_ptr m_asicSdkHealthEventTable = nullptr; + std::set m_supportedAsicSdkHealthEventAttributes; + std::string m_eliminateEventsSha; + swss::SelectableTimer* m_eliminateEventsTimer = nullptr; + uint32_t m_fatalEventCount = 0; + + void initAsicSdkHealthEventNotification(); + void registerAsicSdkHealthEventCategories(sai_switch_attr_t saiSeverity, const std::string &severityString, const std::string &suppressed_category_list="", bool isInitializing=false); + // Switch hash SAI defaults struct { struct { diff --git a/tests/mock_tests/Makefile.am b/tests/mock_tests/Makefile.am index 96c95b121b..db410907c5 100644 --- a/tests/mock_tests/Makefile.am +++ b/tests/mock_tests/Makefile.am @@ -57,6 +57,7 @@ tests_SOURCES = aclorch_ut.cpp \ mux_rollback_ut.cpp \ warmrestartassist_ut.cpp \ test_failure_handling.cpp \ + switchorch_ut.cpp \ warmrestarthelper_ut.cpp \ neighorch_ut.cpp \ twamporch_ut.cpp \ diff --git a/tests/mock_tests/mock_table.cpp b/tests/mock_tests/mock_table.cpp index 4d512a9835..df5e7e5753 100644 --- a/tests/mock_tests/mock_table.cpp +++ b/tests/mock_tests/mock_table.cpp @@ -23,6 +23,26 @@ namespace swss using namespace testing_db; + void merge_values(std::vector &existing_values, const std::vector &values) + { + std::vector new_values(values); + std::set field_set; + for (auto &value : values) + { + field_set.insert(fvField(value)); + } + for (auto &value : existing_values) + { + auto &field = fvField(value); + if (field_set.find(field) != field_set.end()) + { + continue; + } + new_values.push_back(value); + } + existing_values.swap(new_values); + } + bool Table::get(const std::string &key, std::vector &ovalues) { auto table = gDB[m_pipe->getDbId()][getTableName()]; @@ -61,7 +81,15 @@ namespace swss const std::string &prefix) { auto &table = gDB[m_pipe->getDbId()][getTableName()]; - table[key] = values; + auto iter = table.find(key); + if (iter == table.end()) + { + table[key] = values; + } + else + { + merge_values(iter->second, values); + } } void Table::getKeys(std::vector &keys) @@ -95,22 +123,7 @@ namespace swss } else { - std::vector new_values(values); - std::set field_set; - for (auto &value : values) - { - field_set.insert(fvField(value)); - } - for (auto &value : iter->second) - { - auto &field = fvField(value); - if (field_set.find(field) != field_set.end()) - { - continue; - } - new_values.push_back(value); - } - iter->second.swap(new_values); + merge_values(iter->second, values); } } diff --git a/tests/mock_tests/switchorch_ut.cpp b/tests/mock_tests/switchorch_ut.cpp new file mode 100644 index 0000000000..b123207909 --- /dev/null +++ b/tests/mock_tests/switchorch_ut.cpp @@ -0,0 +1,316 @@ +#define private public // make Directory::m_values available to clean it. +#include "directory.h" +#undef private +#define protected public +#include "orch.h" +#undef protected +#include "ut_helper.h" +#include "mock_orchagent_main.h" +#include "mock_table.h" +#include "mock_response_publisher.h" + +extern void on_switch_asic_sdk_health_event(sai_object_id_t switch_id, + sai_switch_asic_sdk_health_severity_t severity, + sai_timespec_t timestamp, + sai_switch_asic_sdk_health_category_t category, + sai_switch_health_data_t data, + const sai_u8_list_t description); + +namespace switchorch_test +{ + using namespace std; + + sai_switch_api_t ut_sai_switch_api; + sai_switch_api_t *pold_sai_switch_api; + + shared_ptr m_app_db; + shared_ptr m_config_db; + shared_ptr m_state_db; + + sai_switch_attr_t _ut_stub_asic_sdk_health_event_attribute_to_check; + bool _ut_stub_asic_sdk_health_event_check_all; + uint32_t _ut_stub_asic_sdk_health_event_call_count; + map> _ut_stub_asic_sdk_health_event_category_sets; + set _ut_stub_asic_sdk_health_event_passed_categories; + + bool _ut_reg_event_unsupported; + + sai_status_t _ut_stub_sai_set_switch_attribute( + _In_ sai_object_id_t switch_id, + _In_ const sai_attribute_t *attr) + { + switch (attr[0].id) + { + case SAI_SWITCH_ATTR_SWITCH_ASIC_SDK_HEALTH_EVENT_NOTIFY: + if (_ut_reg_event_unsupported) + { + return SAI_STATUS_NOT_IMPLEMENTED; + } + break; + case SAI_SWITCH_ATTR_REG_FATAL_SWITCH_ASIC_SDK_HEALTH_CATEGORY: + case SAI_SWITCH_ATTR_REG_WARNING_SWITCH_ASIC_SDK_HEALTH_CATEGORY: + case SAI_SWITCH_ATTR_REG_NOTICE_SWITCH_ASIC_SDK_HEALTH_CATEGORY: + if (_ut_stub_asic_sdk_health_event_check_all) + { + _ut_stub_asic_sdk_health_event_call_count++; + auto *passed_category_list = reinterpret_cast(attr[0].value.s32list.list); + _ut_stub_asic_sdk_health_event_category_sets[(sai_switch_attr_t)attr[0].id] = set(passed_category_list, passed_category_list + attr[0].value.s32list.count); + } + return SAI_STATUS_SUCCESS; + default: + break; + } + return pold_sai_switch_api->set_switch_attribute(switch_id, attr); + } + + void _hook_sai_apis() + { + ut_sai_switch_api = *sai_switch_api; + pold_sai_switch_api = sai_switch_api; + ut_sai_switch_api.set_switch_attribute = _ut_stub_sai_set_switch_attribute; + sai_switch_api = &ut_sai_switch_api; + } + + void _unhook_sai_apis() + { + sai_switch_api = pold_sai_switch_api; + } + + struct SwitchOrchTest : public ::testing::Test + { + SwitchOrchTest() + { + } + + void SetUp() override + { + // Init switch and create dependencies + m_app_db = make_shared("APPL_DB", 0); + m_config_db = make_shared("CONFIG_DB", 0); + m_state_db = make_shared("STATE_DB", 0); + + _ut_reg_event_unsupported = false; + + map profile = { + { "SAI_VS_SWITCH_TYPE", "SAI_VS_SWITCH_TYPE_BCM56850" }, + { "KV_DEVICE_MAC_ADDRESS", "20:03:04:05:06:00" } + }; + + ut_helper::initSaiApi(profile); + + sai_attribute_t attr; + + attr.id = SAI_SWITCH_ATTR_INIT_SWITCH; + attr.value.booldata = true; + + auto status = sai_switch_api->create_switch(&gSwitchId, 1, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + } + + void initSwitchOrch() + { + TableConnector stateDbSwitchTable(m_state_db.get(), "SWITCH_CAPABILITY"); + TableConnector conf_asic_sensors(m_config_db.get(), CFG_ASIC_SENSORS_TABLE_NAME); + TableConnector app_switch_table(m_app_db.get(), APP_SWITCH_TABLE_NAME); + TableConnector conf_suppress_asic_sdk_health_categories(m_config_db.get(), CFG_SUPPRESS_ASIC_SDK_HEALTH_EVENT_NAME); + + vector switch_tables = { + conf_asic_sensors, + conf_suppress_asic_sdk_health_categories, + app_switch_table + }; + + ASSERT_EQ(gSwitchOrch, nullptr); + gSwitchOrch = new SwitchOrch(m_app_db.get(), switch_tables, stateDbSwitchTable); + } + + void TearDown() override + { + ::testing_db::reset(); + + _ut_stub_asic_sdk_health_event_category_sets.clear(); + + gDirectory.m_values.clear(); + + delete gSwitchOrch; + gSwitchOrch = nullptr; + + ut_helper::uninitSaiApi(); + } + }; + + TEST_F(SwitchOrchTest, SwitchOrchTestSuppressCategories) + { + Table suppressAsicSdkHealthEventTable = Table(m_config_db.get(), CFG_SUPPRESS_ASIC_SDK_HEALTH_EVENT_NAME); + + suppressAsicSdkHealthEventTable.set("fatal", + { + {"max_events", "1000"} + }); + suppressAsicSdkHealthEventTable.set("warning", + { + {"categories", "software,firmware,cpu_hw,asic_hw"} + }); + + _ut_stub_asic_sdk_health_event_check_all = true; + auto call_count = _ut_stub_asic_sdk_health_event_call_count; + + _hook_sai_apis(); + initSwitchOrch(); + + vector ts; + std::deque entries; + set all_categories({ + SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_SW, + SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_FW, + SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_CPU_HW, + SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_ASIC_HW}); + set empty_category; + + call_count += 2; + ASSERT_EQ(_ut_stub_asic_sdk_health_event_call_count, call_count); + ASSERT_EQ(_ut_stub_asic_sdk_health_event_category_sets[SAI_SWITCH_ATTR_REG_FATAL_SWITCH_ASIC_SDK_HEALTH_CATEGORY], all_categories); + ASSERT_EQ(_ut_stub_asic_sdk_health_event_category_sets[SAI_SWITCH_ATTR_REG_WARNING_SWITCH_ASIC_SDK_HEALTH_CATEGORY], empty_category); + ASSERT_EQ(_ut_stub_asic_sdk_health_event_category_sets[SAI_SWITCH_ATTR_REG_NOTICE_SWITCH_ASIC_SDK_HEALTH_CATEGORY], all_categories); + + // case: severity: fatal, operation: suppress all categories + entries.push_back({"fatal", "SET", + { + {"categories", "software,firmware,cpu_hw,asic_hw"} + }}); + auto consumer = dynamic_cast(gSwitchOrch->getExecutor(CFG_SUPPRESS_ASIC_SDK_HEALTH_EVENT_NAME)); + consumer->addToSync(entries); + entries.clear(); + static_cast(gSwitchOrch)->doTask(); + ASSERT_EQ(_ut_stub_asic_sdk_health_event_category_sets[SAI_SWITCH_ATTR_REG_FATAL_SWITCH_ASIC_SDK_HEALTH_CATEGORY], empty_category); + call_count++; + ASSERT_EQ(_ut_stub_asic_sdk_health_event_call_count, call_count); + + // case: severity: warning, operation: suppress partial categories + entries.push_back({"warning", "SET", + { + {"categories", "software,cpu_hw,invalid_category"} + }}); + consumer->addToSync(entries); + entries.clear(); + static_cast(gSwitchOrch)->doTask(); + ASSERT_EQ(_ut_stub_asic_sdk_health_event_category_sets[SAI_SWITCH_ATTR_REG_WARNING_SWITCH_ASIC_SDK_HEALTH_CATEGORY], + set({ + SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_FW, + SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_ASIC_HW})); + call_count++; + ASSERT_EQ(_ut_stub_asic_sdk_health_event_call_count, call_count); + + // case: invalid severity, nothing changed (to satisfy coverate) + entries.push_back({"warninga", "SET", + { + {"categories", "software,cpu_hw,asic_hw"} + }}); + consumer->addToSync(entries); + entries.clear(); + static_cast(gSwitchOrch)->doTask(); + // No SAI API called + ASSERT_EQ(_ut_stub_asic_sdk_health_event_call_count, call_count); + + // case: severity: warning, operation: set max_events only, which means to remove suppress list + entries.push_back({"warning", "SET", + { + {"max_events", "10"} + }}); + consumer->addToSync(entries); + entries.clear(); + static_cast(gSwitchOrch)->doTask(); + call_count++; + ASSERT_EQ(_ut_stub_asic_sdk_health_event_call_count, call_count); + ASSERT_EQ(_ut_stub_asic_sdk_health_event_category_sets[SAI_SWITCH_ATTR_REG_WARNING_SWITCH_ASIC_SDK_HEALTH_CATEGORY], all_categories); + + // case: severity: notice, operation: suppress no category + entries.push_back({"notice", "DEL", {}}); + consumer->addToSync(entries); + entries.clear(); + static_cast(gSwitchOrch)->doTask(); + ASSERT_EQ(_ut_stub_asic_sdk_health_event_category_sets[SAI_SWITCH_ATTR_REG_NOTICE_SWITCH_ASIC_SDK_HEALTH_CATEGORY], all_categories); + call_count++; + ASSERT_EQ(_ut_stub_asic_sdk_health_event_call_count, call_count); + + _unhook_sai_apis(); + } + + TEST_F(SwitchOrchTest, SwitchOrchTestCheckCapability) + { + initSwitchOrch(); + + string value; + gSwitchOrch->m_switchTable.hget("switch", SWITCH_CAPABILITY_TABLE_ASIC_SDK_HEALTH_EVENT_CAPABLE, value); + ASSERT_EQ(value, "true"); + gSwitchOrch->m_switchTable.hget("switch", SWITCH_CAPABILITY_TABLE_REG_FATAL_ASIC_SDK_HEALTH_CATEGORY, value); + ASSERT_EQ(value, "true"); + gSwitchOrch->m_switchTable.hget("switch", SWITCH_CAPABILITY_TABLE_REG_WARNING_ASIC_SDK_HEALTH_CATEGORY, value); + ASSERT_EQ(value, "true"); + gSwitchOrch->m_switchTable.hget("switch", SWITCH_CAPABILITY_TABLE_REG_NOTICE_ASIC_SDK_HEALTH_CATEGORY, value); + ASSERT_EQ(value, "true"); + } + + TEST_F(SwitchOrchTest, SwitchOrchTestCheckCapabilityUnsupported) + { + _ut_reg_event_unsupported = true; + _ut_stub_asic_sdk_health_event_check_all = true; + + _hook_sai_apis(); + initSwitchOrch(); + + string value; + gSwitchOrch->m_switchTable.hget("switch", SWITCH_CAPABILITY_TABLE_ASIC_SDK_HEALTH_EVENT_CAPABLE, value); + ASSERT_EQ(value, "false"); + gSwitchOrch->m_switchTable.hget("switch", SWITCH_CAPABILITY_TABLE_REG_FATAL_ASIC_SDK_HEALTH_CATEGORY, value); + ASSERT_EQ(value, "false"); + gSwitchOrch->m_switchTable.hget("switch", SWITCH_CAPABILITY_TABLE_REG_WARNING_ASIC_SDK_HEALTH_CATEGORY, value); + ASSERT_EQ(value, "false"); + gSwitchOrch->m_switchTable.hget("switch", SWITCH_CAPABILITY_TABLE_REG_NOTICE_ASIC_SDK_HEALTH_CATEGORY, value); + ASSERT_EQ(value, "false"); + + // case: unsupported severity. To satisfy coverage. + vector ts; + std::deque entries; + Table suppressAsicSdkHealthEventTable = Table(m_config_db.get(), CFG_SUPPRESS_ASIC_SDK_HEALTH_EVENT_NAME); + entries.push_back({"fatal", "SET", + { + {"categories", "software,firmware,cpu_hw,asic_hw"} + }}); + set empty_category; + auto consumer = dynamic_cast(gSwitchOrch->getExecutor(CFG_SUPPRESS_ASIC_SDK_HEALTH_EVENT_NAME)); + consumer->addToSync(entries); + entries.clear(); + auto call_count = _ut_stub_asic_sdk_health_event_call_count; + static_cast(gSwitchOrch)->doTask(); + ASSERT_EQ(_ut_stub_asic_sdk_health_event_category_sets[SAI_SWITCH_ATTR_REG_FATAL_SWITCH_ASIC_SDK_HEALTH_CATEGORY], empty_category); + ASSERT_EQ(_ut_stub_asic_sdk_health_event_call_count, call_count); + } + + TEST_F(SwitchOrchTest, SwitchOrchTestHandleEvent) + { + initSwitchOrch(); + + sai_timespec_t timestamp = {.tv_sec = 1701160447, .tv_nsec = 538710245}; + sai_switch_health_data_t data = {.data_type = SAI_HEALTH_DATA_TYPE_GENERAL}; + vector data_from_sai({100, 101, 115, 99, 114, 105, 112, 116, 105, 245, 111, 110, 245, 10, 123, 125, 100, 100}); + sai_u8_list_t description; + description.list = data_from_sai.data(); + description.count = (uint32_t)(data_from_sai.size() - 2); + on_switch_asic_sdk_health_event(gSwitchId, + SAI_SWITCH_ASIC_SDK_HEALTH_SEVERITY_FATAL, + timestamp, + SAI_SWITCH_ASIC_SDK_HEALTH_CATEGORY_FW, + data, + description); + + string key = "2023-11-28 08:34:07"; + string value; + gSwitchOrch->m_asicSdkHealthEventTable->hget(key, "category", value); + ASSERT_EQ(value, "firmware"); + gSwitchOrch->m_asicSdkHealthEventTable->hget(key, "severity", value); + ASSERT_EQ(value, "fatal"); + gSwitchOrch->m_asicSdkHealthEventTable->hget(key, "description", value); + ASSERT_EQ(value, "description\n{}"); + } +} From 7612326c0d96fecc610685914825e690433e2304 Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Wed, 1 May 2024 00:21:08 +0800 Subject: [PATCH 19/34] Do not apply zero buffer profile list until all buffer pools are ready (#3112) Do not apply zero buffer profile list until all buffer pools are ready #3112 It was harmless unless too many messages indicating the depending buffer pools and profiles triggers syslog rate limit. --- cfgmgr/buffermgrdyn.cpp | 18 +++++------ tests/mock_tests/buffermgrdyn_ut.cpp | 48 ++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/cfgmgr/buffermgrdyn.cpp b/cfgmgr/buffermgrdyn.cpp index 6c9a1e831e..e39fc040ac 100644 --- a/cfgmgr/buffermgrdyn.cpp +++ b/cfgmgr/buffermgrdyn.cpp @@ -934,15 +934,6 @@ void BufferMgrDynamic::updateBufferObjectToDb(const string &key, const string &p void BufferMgrDynamic::updateBufferObjectListToDb(const string &key, const string &profileList, buffer_direction_t dir) { auto &table = m_applBufferProfileListTables[dir]; - const auto &direction = m_bufferDirectionNames[dir]; - - if (!m_bufferPoolReady) - { - SWSS_LOG_NOTICE("Buffer pools are not ready when configuring buffer %s profile list %s, pending", direction.c_str(), key.c_str()); - m_bufferObjectsPending = true; - return; - } - vector fvVector; fvVector.emplace_back(buffer_profile_list_field_name, profileList); @@ -3245,6 +3236,15 @@ task_process_status BufferMgrDynamic::handleSingleBufferPortProfileListEntry(con } } + if (!m_bufferPoolReady) + { + const auto &direction = m_bufferDirectionNames[dir]; + + SWSS_LOG_NOTICE("Buffer pools are not ready when configuring buffer %s profile list %s, pending", direction.c_str(), key.c_str()); + m_bufferObjectsPending = true; + return task_process_status::task_success; + } + auto &portInfo = m_portInfoLookup[port]; if (PORT_ADMIN_DOWN != portInfo.state) { diff --git a/tests/mock_tests/buffermgrdyn_ut.cpp b/tests/mock_tests/buffermgrdyn_ut.cpp index 1c23a17410..bd633db108 100644 --- a/tests/mock_tests/buffermgrdyn_ut.cpp +++ b/tests/mock_tests/buffermgrdyn_ut.cpp @@ -823,6 +823,54 @@ namespace buffermgrdyn_test } } + TEST_F(BufferMgrDynTest, BufferMgrDynTestReclaimingBufferProfileList) + { + vector fieldValues; + + SetUpReclaimingBuffer(); + shared_ptr> zero_profile = make_shared>(zeroProfile); + + InitDefaultLosslessParameter(); + InitMmuSize(); + + StartBufferManager(zero_profile); + + stateBufferTable.set("Ethernet0", + { + {"max_priority_groups", "8"}, + {"max_queues", "16"} + }); + m_dynamicBuffer->addExistingData(&stateBufferTable); + static_cast(m_dynamicBuffer)->doTask(); + + statePortTable.set("Ethernet0", + { + {"supported_speeds", "100000,50000,40000,25000,10000,1000"} + }); + InitPort("Ethernet0", "down"); + + InitBufferPool(); + InitDefaultBufferProfile(); + + InitBufferProfileList("Ethernet0", "ingress_lossless_profile", bufferIngProfileListTable); + InitBufferProfileList("Ethernet0", "egress_lossless_profile,egress_lossy_profile", bufferEgrProfileListTable); + + // No profile lists in the database until buffer pools are ready + CheckProfileList("Ethernet0", true, "ingress_lossless_profile", false); + CheckProfileList("Ethernet0", false, "egress_lossless_profile,egress_lossy_profile", false); + + // Make buffer pools ready + SetPortInitDone(); + m_dynamicBuffer->doTask(m_selectableTable); + + // Zero profile lists should be in the database + ASSERT_TRUE(appBufferIngProfileListTable.get("Ethernet0", fieldValues)); + ASSERT_EQ(fvValue(fieldValues[0]), "ingress_lossless_zero_profile"); + fieldValues.clear(); + ASSERT_TRUE(appBufferEgrProfileListTable.get("Ethernet0", fieldValues)); + ASSERT_EQ(fvValue(fieldValues[0]), "egress_lossless_zero_profile,egress_lossy_zero_profile"); + } + /* * Clear qos with reclaiming buffer * From c79fd932371455f7b4813c0948c762d82b835362 Mon Sep 17 00:00:00 2001 From: jfeng-arista <98421150+jfeng-arista@users.noreply.github.com> Date: Tue, 30 Apr 2024 09:21:53 -0700 Subject: [PATCH 20/34] Add fabric capacity monitoring code. (#3097) * Add fabric capacity monitoring code. * The HLD can be found at https://github.com/sonic-net/SONiC/blob/master/doc/voq/fabric.md The current design does not cover the card hotswap/OIR cases. We will discuss how to handle that in a separate proposal. --- orchagent/fabricportsorch.cpp | 182 ++++++++++++++++++++++++++++ orchagent/fabricportsorch.h | 5 + tests/test_fabric_capacity.py | 72 +++++++++++ tests/test_fabric_port_isolation.py | 3 +- 4 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 tests/test_fabric_capacity.py diff --git a/orchagent/fabricportsorch.cpp b/orchagent/fabricportsorch.cpp index b46fcede09..d61f5d13f2 100644 --- a/orchagent/fabricportsorch.cpp +++ b/orchagent/fabricportsorch.cpp @@ -35,6 +35,7 @@ #define RECOVERY_POLLS_CFG 8 #define ERROR_RATE_CRC_CELLS_CFG 1 #define ERROR_RATE_RX_CELLS_CFG 61035156 +#define FABRIC_LINK_RATE 44316 extern sai_object_id_t gSwitchId; extern sai_switch_api_t *sai_switch_api; @@ -76,6 +77,7 @@ FabricPortsOrch::FabricPortsOrch(DBConnector *appl_db, vector(new DBConnector("STATE_DB", 0)); m_stateTable = unique_ptr
(new Table(m_state_db.get(), APP_FABRIC_PORT_TABLE_NAME)); + m_fabricCapacityTable = unique_ptr
(new Table(m_state_db.get(), STATE_FABRIC_CAPACITY_TABLE_NAME)); m_counter_db = shared_ptr(new DBConnector("COUNTERS_DB", 0)); m_portNameQueueCounterTable = unique_ptr
(new Table(m_counter_db.get(), COUNTERS_FABRIC_QUEUE_NAME_MAP)); @@ -836,6 +838,185 @@ void FabricPortsOrch::updateFabricDebugCounters() } } +void FabricPortsOrch::updateFabricCapacity() +{ + // Init value for fabric capacity monitoring + int capacity = 0; + int downCapacity = 0; + string lnkStatus = "down"; + string configIsolated = "0"; + string isolated = "0"; + string autoIsolated = "0"; + int operating_links = 0; + int total_links = 0; + int threshold = 100; + std::vector constValues; + string applKey = FABRIC_MONITOR_DATA; + + // Get capacity warning threshold from APPL_DB table FABRIC_MONITOR_DATA + // By default, this threshold is 100 (percentage). + bool cfgVal = m_applMonitorConstTable->get("FABRIC_MONITOR_DATA", constValues); + if(!cfgVal) + { + SWSS_LOG_INFO("%s default values not set", applKey.c_str()); + } + else + { + SWSS_LOG_INFO("%s has default values", applKey.c_str()); + } + string configVal = "1"; + for (auto cv : constValues) + { + configVal = fvValue(cv); + if (fvField(cv) == "monCapacityThreshWarn") + { + threshold = stoi(configVal); + SWSS_LOG_INFO("monCapacityThreshWarn: %s %s", configVal.c_str(), fvField(cv).c_str()); + continue; + } + } + + // Check fabric capacity. + SWSS_LOG_INFO("FabricPortsOrch::updateFabricCapacity start"); + for (auto p : m_fabricLanePortMap) + { + int lane = p.first; + string key = FABRIC_PORT_PREFIX + to_string(lane); + std::vector values; + string valuePt; + + // Get fabric serdes link status from STATE_DB + bool exist = m_stateTable->get(key, values); + if (!exist) + { + SWSS_LOG_INFO("No state infor for port %s", key.c_str()); + return; + } + for (auto val : values) + { + valuePt = fvValue(val); + if (fvField(val) == "STATUS") + { + lnkStatus = valuePt; + continue; + } + if (fvField(val) == "CONFIG_ISOLATED") + { + configIsolated = valuePt; + continue; + } + if (fvField(val) == "ISOLATED") + { + isolated = valuePt; + continue; + } + if (fvField(val) == "AUTO_ISOLATED") + { + autoIsolated = valuePt; + continue; + } + } + // Calculate total number of serdes link, number of operational links, + // total fabric capacity. + bool linkIssue = false; + if (configIsolated == "1" || isolated == "1" || autoIsolated == "1") + { + linkIssue = true; + } + + if (lnkStatus == "down" || linkIssue == true) + { + downCapacity += FABRIC_LINK_RATE; + } + else + { + capacity += FABRIC_LINK_RATE; + operating_links += 1; + } + total_links += 1; + } + + SWSS_LOG_INFO("Capacity: %d Missing %d", capacity, downCapacity); + + // Get LAST_EVENT from STATE_DB + + // Calculate the current capacity to see if + // it is lower or higher than the threshold + string cur_event = "None"; + string event = "None"; + int expect_links = total_links * threshold / 100; + if (expect_links > operating_links) + { + cur_event = "Lower"; + } + else + { + cur_event = "Higher"; + } + + SWSS_LOG_NOTICE(" total link %d expected link %d oper link %d event %s", total_links, expect_links, operating_links, cur_event.c_str()); + + // Update the capacity data in this poll to STATE_DB + SWSS_LOG_INFO("Capacity: %d Missing %d", capacity, downCapacity); + + string lastEvent = "None"; + string lastTime = "Never"; + // Get the last event and time that event happend from STATE_DB + bool capacity_data = m_fabricCapacityTable->get("FABRIC_CAPACITY_DATA", constValues); + if (capacity_data) + { + for (auto cv : constValues) + { + if(fvField(cv) == "last_event") + { + lastEvent = fvValue(cv); + continue; + } + if(fvField(cv) == "last_event_time") + { + lastTime = fvValue(cv); + continue; + } + } + } + + auto now = std::chrono::system_clock::now(); + auto now_s = std::chrono::time_point_cast(now); + auto nse = now_s.time_since_epoch(); + + // If last event is None or higher, but the capacity is lower in this poll, + // update the STATE_DB with the event (lower) and the time. + // If the last event is lower, and the capacity is back to higher than the threshold, + // update the STATE_DB with the event (higher) and the time. + event = lastEvent; + if (cur_event == "Lower") + { + if (lastEvent == "None" || lastEvent == "Higher") + { + event = "Lower"; + lastTime = to_string(nse.count()); + } + } + else if (cur_event == "Higher") + { + if (lastEvent == "Lower") + { + event = "Higher"; + lastTime = to_string(nse.count()); + } + } + + // Update STATE_DB + SWSS_LOG_INFO("FabricPortsOrch::updateFabricCapacity now update STATE_DB"); + m_fabricCapacityTable->hset("FABRIC_CAPACITY_DATA", "fabric_capacity", to_string(capacity)); + m_fabricCapacityTable->hset("FABRIC_CAPACITY_DATA", "missing_capacity", to_string(downCapacity)); + m_fabricCapacityTable->hset("FABRIC_CAPACITY_DATA", "operating_links", to_string(operating_links)); + m_fabricCapacityTable->hset("FABRIC_CAPACITY_DATA", "number_of_links", to_string(total_links)); + m_fabricCapacityTable->hset("FABRIC_CAPACITY_DATA", "warning_threshold", to_string(threshold)); + m_fabricCapacityTable->hset("FABRIC_CAPACITY_DATA", "last_event", event); + m_fabricCapacityTable->hset("FABRIC_CAPACITY_DATA", "last_event_time", lastTime); +} + void FabricPortsOrch::doTask() { } @@ -1039,6 +1220,7 @@ void FabricPortsOrch::doTask(swss::SelectableTimer &timer) if (m_getFabricPortListDone) { updateFabricDebugCounters(); + updateFabricCapacity(); } } } diff --git a/orchagent/fabricportsorch.h b/orchagent/fabricportsorch.h index 0d637dec43..e72ae56e3c 100644 --- a/orchagent/fabricportsorch.h +++ b/orchagent/fabricportsorch.h @@ -9,6 +9,9 @@ #include "producertable.h" #include "flex_counter_manager.h" +#define STATE_FABRIC_CAPACITY_TABLE_NAME "FABRIC_CAPACITY_TABLE" +#define STATE_PORT_CAPACITY_TABLE_NAME "PORT_CAPACITY_TABLE" + class FabricPortsOrch : public Orch, public Subject { public: @@ -31,6 +34,7 @@ class FabricPortsOrch : public Orch, public Subject unique_ptr
m_portNamePortCounterTable; unique_ptr
m_fabricCounterTable; unique_ptr
m_applTable; + unique_ptr
m_fabricCapacityTable; unique_ptr
m_applMonitorConstTable; unique_ptr m_flexCounterTable; @@ -61,6 +65,7 @@ class FabricPortsOrch : public Orch, public Subject void generatePortStats(); void updateFabricPortState(); void updateFabricDebugCounters(); + void updateFabricCapacity(); void doTask() override; void doTask(Consumer &consumer); diff --git a/tests/test_fabric_capacity.py b/tests/test_fabric_capacity.py new file mode 100644 index 0000000000..91bb1b5e94 --- /dev/null +++ b/tests/test_fabric_capacity.py @@ -0,0 +1,72 @@ +import random +from dvslib.dvs_database import DVSDatabase +from dvslib.dvs_common import PollingConfig + + +class TestVirtualChassis(object): + def test_voq_switch_fabric_capacity(self, vst): + """Test basic fabric capacity infrastructure in VOQ switchs. + + This test validates that when fabric links get isolated, the fabric capacity + get updated in the state_db. + When the link get unisolated, the fabric capacity get set back as well. + """ + + dvss = vst.dvss + for name in dvss.keys(): + dvs = dvss[name] + # Get the config information and choose a linecard or fabric card to test. + config_db = dvs.get_config_db() + metatbl = config_db.get_entry("DEVICE_METADATA", "localhost") + + cfg_switch_type = metatbl.get("switch_type") + if cfg_switch_type == "fabric": + + # get state_db infor + sdb = dvs.get_state_db() + # There are 16 fabric ports in the test environment. + # Choose one link to test. + portNum = random.randint(1, 16) + cdb_port = "Fabric"+str(portNum) + sdb_port = "PORT"+str(portNum) + + max_poll = PollingConfig(polling_interval=60, timeout=600, strict=True) + + # setup test environment + sdb.update_entry("FABRIC_PORT_TABLE", sdb_port, {"TEST": "TEST"}) + + # get current fabric capacity + capacity = sdb.get_entry("FABRIC_CAPACITY_TABLE", "FABRIC_CAPACITY_DATA")['operating_links'] + if sdb.get_entry("FABRIC_PORT_TABLE", sdb_port)['STATUS'] == 'up': + try: + # clean up the testing port. + # set TEST_CRC_ERRORS to 0 + # set TEST_CODE_ERRORS to 0 + sdb.update_entry("FABRIC_PORT_TABLE", sdb_port, {"TEST_CRC_ERRORS":"0"}) + sdb.update_entry("FABRIC_PORT_TABLE", sdb_port, {"TEST_CODE_ERRORS": "0"}) + + # isolate the link from config_db + config_db.update_entry("FABRIC_PORT", cdb_port, {"isolateStatus": "True"}) + sdb.wait_for_field_match("FABRIC_PORT_TABLE", sdb_port, {"ISOLATED": "1"}, polling_config=max_poll) + # check if capacity reduced + sdb.wait_for_field_negative_match("FABRIC_CAPACITY_TABLE", "FABRIC_CAPACITY_DATA", {'operating_links': capacity}, polling_config=max_poll) + # unisolate the link from config_db + config_db.update_entry("FABRIC_PORT", cdb_port, {"isolateStatus": "False"}) + sdb.wait_for_field_match("FABRIC_PORT_TABLE", sdb_port, {"ISOLATED": "0"}, polling_config=max_poll) + sdb.wait_for_field_match("FABRIC_CAPACITY_TABLE", "FABRIC_CAPACITY_DATA", {'operating_links': capacity}, polling_config=max_poll) + finally: + # cleanup + sdb.update_entry("FABRIC_PORT_TABLE", sdb_port, {"TEST_CRC_ERRORS": "0"}) + sdb.update_entry("FABRIC_PORT_TABLE", sdb_port, {"TEST_CODE_ERRORS": "0"}) + sdb.update_entry("FABRIC_PORT_TABLE", sdb_port, {"TEST": "product"}) + else: + print("The link ", port, " is down") + else: + print("We do not check switch type:", cfg_switch_type) + + +# Add Dummy always-pass test at end as workaroud +# for issue when Flaky fail on final test it invokes module tear-down before retrying +def test_nonflaky_dummy(): + pass + diff --git a/tests/test_fabric_port_isolation.py b/tests/test_fabric_port_isolation.py index d92cb73fe1..d1b57a019f 100644 --- a/tests/test_fabric_port_isolation.py +++ b/tests/test_fabric_port_isolation.py @@ -29,9 +29,9 @@ def test_voq_switch_fabric_link(self, vst): portNum = random.randint(1, 16) port = "PORT"+str(portNum) # wait for link monitoring algorithm skips init pollings + sdb.update_entry("FABRIC_PORT_TABLE", port, {"TEST": "TEST"}) max_poll = PollingConfig(polling_interval=60, timeout=1200, strict=True) if sdb.get_entry("FABRIC_PORT_TABLE", port)['STATUS'] == 'up': - sdb.wait_for_field_match("FABRIC_PORT_TABLE", port, {"SKIP_FEC_ERR_ON_LNKUP_CNT": "2"}, polling_config=max_poll) try: # clean up the system for the testing port. # set TEST_CRC_ERRORS to 0 @@ -39,7 +39,6 @@ def test_voq_switch_fabric_link(self, vst): # set TEST to "TEST" sdb.update_entry("FABRIC_PORT_TABLE", port, {"TEST_CRC_ERRORS":"0"}) sdb.update_entry("FABRIC_PORT_TABLE", port, {"TEST_CODE_ERRORS": "0"}) - sdb.update_entry("FABRIC_PORT_TABLE", port, {"TEST": "TEST"}) # inject testing errors and wait for link get isolated. sdb.update_entry("FABRIC_PORT_TABLE", port, {"TEST_CRC_ERRORS": "2"}) sdb.wait_for_field_match("FABRIC_PORT_TABLE", port, {"AUTO_ISOLATED": "1"}, polling_config=max_poll) From 67e03128dedc061c51da7ccd7fd716f00d974bb3 Mon Sep 17 00:00:00 2001 From: Zhixin Zhu <44230426+zhixzhu@users.noreply.github.com> Date: Wed, 1 May 2024 00:22:34 +0800 Subject: [PATCH 21/34] change log level from ERR to WARN for pfc asym sai attribute not supported (#3125) * Change log level from ERR to WARN for pfc asym not supported --- orchagent/port/port_capabilities.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orchagent/port/port_capabilities.cpp b/orchagent/port/port_capabilities.cpp index a55334d9f1..dbe6c7090f 100644 --- a/orchagent/port/port_capabilities.cpp +++ b/orchagent/port/port_capabilities.cpp @@ -61,7 +61,7 @@ void PortCapabilities::queryPortAttrCapabilities(T &obj, sai_port_attr_t attrId) ); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR( + SWSS_LOG_WARN( "Failed to get attribute(%s) capabilities", toStr(SAI_OBJECT_TYPE_PORT, attrId).c_str() ); From 2e6c5b209d575f73b867de9f3e56b3be4066acec Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Wed, 1 May 2024 15:37:14 -0700 Subject: [PATCH 22/34] [DropCounter]Fix the ordering issue with dropcounter (#3128) --- orchagent/debugcounterorch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orchagent/debugcounterorch.cpp b/orchagent/debugcounterorch.cpp index ed27f400d4..882eaaf39b 100644 --- a/orchagent/debugcounterorch.cpp +++ b/orchagent/debugcounterorch.cpp @@ -336,7 +336,6 @@ task_process_status DebugCounterOrch::uninstallDebugCounter(const string& counte string counter_type = counter->getCounterType(); string counter_stat = counter->getDebugCounterSAIStat(); - debug_counters.erase(it); uninstallDebugFlexCounters(counter_type, counter_stat); if (counter_type == PORT_INGRESS_DROPS || counter_type == PORT_EGRESS_DROPS) @@ -347,6 +346,7 @@ task_process_status DebugCounterOrch::uninstallDebugCounter(const string& counte { m_counterNameToSwitchStatMap->hdel("", counter_name); } + debug_counters.erase(it); SWSS_LOG_NOTICE("Successfully deleted drop counter %s", counter_name.c_str()); return task_process_status::task_success; From 837e46757756dc07fd5840678fa73e8c27abaf20 Mon Sep 17 00:00:00 2001 From: arista-nwolfe <94405414+arista-nwolfe@users.noreply.github.com> Date: Tue, 7 May 2024 13:28:39 -0400 Subject: [PATCH 23/34] Remove unwanted newline character at end of timestamp (#3111) * Remove unwanted newline character at end of timestamp * Cleaner approach to generate timestamp string with no newline character * Use UTC rather than local time in timestamp --- orchagent/portsorch.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 50c23d4aec..4f2e709182 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -3120,12 +3120,18 @@ void PortsOrch::updateDbPortFlapCount(Port& port, sai_port_oper_status_t pstatus std::time_t now_c = std::chrono::system_clock::to_time_t(now); if (pstatus == SAI_PORT_OPER_STATUS_DOWN) { - FieldValueTuple tuple("last_down_time", std::ctime(&now_c)); + char buffer[32]; + // Format: Www Mmm dd hh:mm:ss yyyy + std::strftime(buffer, sizeof(buffer), "%a %b %d %H:%M:%S %Y", std::gmtime(&now_c)); + FieldValueTuple tuple("last_down_time", buffer); tuples.push_back(tuple); } else if (pstatus == SAI_PORT_OPER_STATUS_UP) { - FieldValueTuple tuple("last_up_time", std::ctime(&now_c)); + char buffer[32]; + // Format: Www Mmm dd hh:mm:ss yyyy + std::strftime(buffer, sizeof(buffer), "%a %b %d %H:%M:%S %Y", std::gmtime(&now_c)); + FieldValueTuple tuple("last_up_time", buffer); tuples.push_back(tuple); } m_portTable->set(port.m_alias, tuples); From f62eed23fcdd62544f3a7a0e5cea15b0cafa9600 Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Fri, 10 May 2024 00:35:23 +0800 Subject: [PATCH 24/34] [Mellanox] PFC watchdog long term solution to reduce false alarm (#3036) What I did Adjust PFC watchdog detection algorithm to reduce false alarms. In the old PFC watchdog detection algorithm, the PFC watchdog can be triggered if either of the following conditions is satisfied in a detection interval: There are packets accumulated in the queue && there is no packet sent out of the queue && there are PFC frames received in the queue There is no packet accumulated in the queue and there are PFC frames received and blocking more than 80% of the detection interval. The new PFC watchdog detection algorithm merges two conditions into one: The PFC watchdog is triggered only if: There are packets accumulated in the queue && there is no packet sent out of the queue && there are PFC frames received and blocking more than 99% of the detection interval. --- orchagent/pfc_detect_mellanox.lua | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/orchagent/pfc_detect_mellanox.lua b/orchagent/pfc_detect_mellanox.lua index 826a577d62..5e6d8c00c5 100644 --- a/orchagent/pfc_detect_mellanox.lua +++ b/orchagent/pfc_detect_mellanox.lua @@ -18,9 +18,11 @@ local timestamp_struct = redis.call('TIME') local timestamp_current = timestamp_struct[1] + timestamp_struct[2] / 1000000 local timestamp_string = tostring(timestamp_current) redis.call('HSET', 'TIMESTAMP', 'pfcwd_poll_timestamp_last', timestamp_string) -local real_poll_time = poll_time +local effective_poll_time = poll_time +local effective_poll_time_lasttime = redis.call('HGET', 'TIMESTAMP', 'effective_pfcwd_poll_time_last') if timestamp_last ~= false then - real_poll_time = (timestamp_current - tonumber(timestamp_last)) * 1000000 + effective_poll_time = (timestamp_current - tonumber(timestamp_last)) * 1000000 + redis.call('HSET', 'TIMESTAMP', 'effective_pfcwd_poll_time_last', effective_poll_time) end -- Iterate through each queue @@ -78,27 +80,30 @@ for i = n, 1, -1 do packets_last = tonumber(packets_last) pfc_rx_packets_last = tonumber(pfc_rx_packets_last) pfc_duration_last = tonumber(pfc_duration_last) - local storm_condition = (pfc_duration - pfc_duration_last) > (poll_time * 0.8) + local storm_condition = (pfc_duration - pfc_duration_last) > (effective_poll_time * 0.99) -- Check actual condition of queue being in PFC storm - if (occupancy_bytes > 0 and packets - packets_last == 0 and pfc_rx_packets - pfc_rx_packets_last > 0) or + if (occupancy_bytes > 0 and packets - packets_last == 0 and storm_condition) or -- DEBUG CODE START. Uncomment to enable - (debug_storm == "enabled") or + (debug_storm == "enabled") -- DEBUG CODE END. - (occupancy_bytes == 0 and packets - packets_last == 0 and storm_condition) then - if time_left <= poll_time then + then + if time_left <= effective_poll_time then redis.call('HDEL', counters_table_name .. ':' .. port_id, pfc_rx_pkt_key .. '_last') redis.call('HDEL', counters_table_name .. ':' .. port_id, pfc_duration_key .. '_last') local occupancy_string = '"occupancy","' .. tostring(occupancy_bytes) .. '",' local packets_string = '"packets","' .. tostring(packets) .. '","packets_last","' .. tostring(packets_last) .. '",' local pfc_rx_packets_string = '"pfc_rx_packets","' .. tostring(pfc_rx_packets) .. '","pfc_rx_packets_last","' .. tostring(pfc_rx_packets_last) .. '",' local storm_condition_string = '"pfc_duration","' .. tostring(pfc_duration) .. '","pfc_duration_last","' .. tostring(pfc_duration_last) .. '",' - local timestamps = '"timestamp","' .. timestamp_string .. '","timestamp_last","' .. timestamp_last .. '","real_poll_time","' .. real_poll_time .. '"' + local timestamps = '"timestamp","' .. timestamp_string .. '","timestamp_last","' .. timestamp_last .. '","effective_poll_time","' .. effective_poll_time .. '"' + if effective_poll_time_lasttime ~= false then + timestamps = timestamps .. ',"effective_pfcwd_poll_time_last","' .. effective_poll_time_lasttime .. '"' + end redis.call('PUBLISH', 'PFC_WD_ACTION', '["' .. KEYS[i] .. '","storm",' .. occupancy_string .. packets_string .. pfc_rx_packets_string .. storm_condition_string .. timestamps .. ']') is_deadlock = true time_left = detection_time else - time_left = time_left - poll_time + time_left = time_left - effective_poll_time end else if pfc_wd_action == 'alert' and pfc_wd_status ~= 'operational' then From 198eb3d1f16f3e5746f1613b74a3debcbc2ac669 Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Fri, 10 May 2024 17:42:37 -0700 Subject: [PATCH 25/34] Add transceiver info to bake only if supported (#3142) * Add transceiver info to bake only if supported --- orchagent/portsorch.cpp | 8 ++++---- orchagent/portsorch.h | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 4f2e709182..b946c96624 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -553,8 +553,6 @@ PortsOrch::PortsOrch(DBConnector *db, DBConnector *stateDb, vector Date: Sat, 11 May 2024 00:00:07 -0700 Subject: [PATCH 26/34] [VRF]Fixing vrf orch to update state_db when evpn nvo arrives late (#3140) --- orchagent/vrforch.cpp | 1 + tests/test_evpn_l3_vxlan.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/orchagent/vrforch.cpp b/orchagent/vrforch.cpp index 776cf1eb0f..a47661412f 100644 --- a/orchagent/vrforch.cpp +++ b/orchagent/vrforch.cpp @@ -147,6 +147,7 @@ bool VRFOrch::addOperation(const Request& request) return false; } + m_stateVrfObjectTable.hset(vrf_name, "state", "ok"); SWSS_LOG_NOTICE("VRF '%s' was updated", vrf_name.c_str()); } diff --git a/tests/test_evpn_l3_vxlan.py b/tests/test_evpn_l3_vxlan.py index 3f424f3830..8820f484e6 100644 --- a/tests/test_evpn_l3_vxlan.py +++ b/tests/test_evpn_l3_vxlan.py @@ -17,6 +17,7 @@ def setup_db(self, dvs): self.pdb = swsscommon.DBConnector(0, dvs.redis_sock, 0) self.adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) self.cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0) + self.sdb = swsscommon.DBConnector(6, dvs.redis_sock, 0) # Test 1 - Create and Delete SIP Tunnel and VRF VNI Map entries # @pytest.mark.skip(reason="Starting Route Orch, VRF Orch to be merged") @@ -597,6 +598,34 @@ def test_tunnel_ipv6_routes(self, dvs, testlog): vxlan_obj.remove_vlan(dvs, "100") + def test_vrf_state_db_update(self, dvs, testlog): + vxlan_obj = self.get_vxlan_obj() + helper = self.get_vxlan_helper() + + self.setup_db(dvs) + tunnel_name = 'tunnel_2' + map_name = 'map_1000_100' + vrf_map_name = 'evpn_map_1000_Vrf-RED' + + vxlan_obj.fetch_exist_entries(dvs) + + + vxlan_obj.create_vrf(dvs, "Vrf-RED") + vxlan_obj.create_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED', '1000') + + time.sleep(2) + #adding nvo after + vxlan_obj.create_vxlan_tunnel(dvs, tunnel_name, '6.6.6.6') + vxlan_obj.create_evpn_nvo(dvs, 'nvo1', tunnel_name) + exp_attr = [ + ("state", "ok"), + ] + helper.check_object(self.sdb, "VRF_OBJECT_TABLE", 'Vrf-RED', exp_attr) + vxlan_obj.remove_vxlan_vrf_tunnel_map(dvs, 'Vrf-RED') + vxlan_obj.remove_vrf(dvs, "Vrf-RED") + vxlan_obj.remove_vxlan_tunnel(dvs, tunnel_name) + vxlan_obj.remove_evpn_nvo(dvs, 'nvo1') + # Add Dummy always-pass test at end as workaroud # for issue when Flaky fail on final test it invokes module tear-down before retrying def test_nonflaky_dummy(): From 2f8bd9cf6df839abec0ecc9bf31fc9c4b06a6c47 Mon Sep 17 00:00:00 2001 From: Kumaresh Perumal Date: Tue, 14 May 2024 15:58:04 -0700 Subject: [PATCH 27/34] Add support for ECMP and LAG hash offset (#3138) * Add support for ECMP and LAG hash offset What I did Add support to update ECMP and LAG hash offset. Orchagent checks for SAI attribute capability and configure the offset values. Why I did it To avoid ECMP hash imbalance across T0 and T1s, different hash offsets can be configured. How I verified it sonic-mgmt tests ipfwd/test_nhop_group.py --- orchagent/switchorch.cpp | 31 +++++++++++++++++++++++++++++-- tests/test_switch.py | 23 +++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/orchagent/switchorch.cpp b/orchagent/switchorch.cpp index 9dc9bcfbde..1674673366 100644 --- a/orchagent/switchorch.cpp +++ b/orchagent/switchorch.cpp @@ -37,7 +37,9 @@ const map switch_attribute_map = {"fdb_aging_time", SAI_SWITCH_ATTR_FDB_AGING_TIME}, {"debug_shell_enable", SAI_SWITCH_ATTR_SWITCH_SHELL_ENABLE}, {"vxlan_port", SAI_SWITCH_ATTR_VXLAN_DEFAULT_PORT}, - {"vxlan_router_mac", SAI_SWITCH_ATTR_VXLAN_DEFAULT_ROUTER_MAC} + {"vxlan_router_mac", SAI_SWITCH_ATTR_VXLAN_DEFAULT_ROUTER_MAC}, + {"ecmp_hash_offset", SAI_SWITCH_ATTR_ECMP_DEFAULT_HASH_OFFSET}, + {"lag_hash_offset", SAI_SWITCH_ATTR_LAG_DEFAULT_HASH_OFFSET} }; const map switch_tunnel_attribute_map = @@ -541,6 +543,8 @@ void SwitchOrch::doAppSwitchTableTask(Consumer &consumer) MacAddress mac_addr; bool invalid_attr = false; + bool ret = false; + bool unsupported_attr = false; switch (attr.id) { case SAI_SWITCH_ATTR_FDB_UNICAST_MISS_PACKET_ACTION: @@ -578,11 +582,34 @@ void SwitchOrch::doAppSwitchTableTask(Consumer &consumer) memcpy(attr.value.mac, mac_addr.getMac(), sizeof(sai_mac_t)); break; + case SAI_SWITCH_ATTR_ECMP_DEFAULT_HASH_OFFSET: + ret = querySwitchCapability(SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_ECMP_DEFAULT_HASH_OFFSET); + if (ret == false) + { + unsupported_attr = true; + } + else + { + attr.value.u8 = to_uint(value); + } + break; + case SAI_SWITCH_ATTR_LAG_DEFAULT_HASH_OFFSET: + ret = querySwitchCapability(SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_LAG_DEFAULT_HASH_OFFSET); + if (ret == false) + { + unsupported_attr = true; + } + else + { + attr.value.u8 = to_uint(value); + } + break; + default: invalid_attr = true; break; } - if (invalid_attr) + if (invalid_attr || unsupported_attr) { /* break from kfvFieldsValues for loop */ break; diff --git a/tests/test_switch.py b/tests/test_switch.py index 93cfd1389c..652fa46573 100644 --- a/tests/test_switch.py +++ b/tests/test_switch.py @@ -65,6 +65,27 @@ def vxlan_switch_test(dvs, oid, port, mac, mask, sport): ) +def ecmp_lag_hash_offset_test(dvs, oid, lag_offset, ecmp_offset): + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + create_entry_pst( + app_db, + "SWITCH_TABLE", ':', "switch", + [ + ("ecmp_hash_offset", ecmp_offset), + ("lag_hash_offset", lag_offset) + ], + ) + time.sleep(2) + + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + check_object(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_SWITCH", oid, + { + 'SAI_SWITCH_ATTR_ECMP_DEFAULT_HASH_OFFSET': ecmp_offset, + 'SAI_SWITCH_ATTR_LAG_DEFAULT_HASH_OFFSET': lag_offset, + } + ) + + class TestSwitch(object): ''' Test- Check switch attributes @@ -75,6 +96,8 @@ def test_switch_attribute(self, dvs, testlog): vxlan_switch_test(dvs, switch_oid, "56789", "00:0A:0B:0C:0D:0E", "15", "56789") + ecmp_lag_hash_offset_test(dvs, switch_oid, "10", "10") + # Add Dummy always-pass test at end as workaroud # for issue when Flaky fail on final test it invokes module tear-down before retrying From 26a5a1cbce66f62291f138c7438bd0b2c6d0d928 Mon Sep 17 00:00:00 2001 From: Stephen Sun <5379172+stephenxs@users.noreply.github.com> Date: Thu, 16 May 2024 00:34:06 +0800 Subject: [PATCH 28/34] Fix flex counter out-of-order issue by notifying counter operations using SelectableChannel (#3076) * Fix flow counter sequence issue using redis SAI switch API enable counter polling and create counter group SAI switch API is invoked to enable counter polling and create counter group CLI option to choose whether the new infra should be used --- orchagent/bufferorch.cpp | 46 +- orchagent/bufferorch.h | 5 +- orchagent/copporch.cpp | 19 +- orchagent/copporch.h | 2 - orchagent/fabricportsorch.cpp | 2 - orchagent/fabricportsorch.h | 1 - .../flex_counter/flex_counter_manager.cpp | 79 +- orchagent/flex_counter/flex_counter_manager.h | 12 +- orchagent/flexcounterorch.cpp | 23 +- orchagent/flexcounterorch.h | 4 - orchagent/intfsorch.cpp | 43 +- orchagent/intfsorch.h | 4 +- orchagent/macsecorch.cpp | 12 +- orchagent/main.cpp | 13 +- orchagent/p4orch/tests/test_main.cpp | 54 ++ orchagent/pfcwdorch.cpp | 44 +- orchagent/pfcwdorch.h | 6 +- orchagent/portsorch.cpp | 95 +- orchagent/portsorch.h | 7 +- orchagent/saihelper.cpp | 294 ++++++ orchagent/saihelper.h | 30 + orchagent/vxlanorch.cpp | 8 +- tests/mock_tests/Makefile.am | 1 + tests/mock_tests/bufferorch_ut.cpp | 3 + tests/mock_tests/flexcounter_ut.cpp | 845 ++++++++++++++++++ tests/mock_tests/mock_orch_test.h | 3 +- tests/mock_tests/mock_orchagent_main.cpp | 1 + tests/mock_tests/mock_table.cpp | 74 +- tests/mock_tests/qosorch_ut.cpp | 3 + tests/mock_tests/routeorch_ut.cpp | 3 + 30 files changed, 1482 insertions(+), 254 deletions(-) create mode 100644 tests/mock_tests/flexcounter_ut.cpp diff --git a/orchagent/bufferorch.cpp b/orchagent/bufferorch.cpp index c3a63c5ec3..ccbc8e9b25 100644 --- a/orchagent/bufferorch.cpp +++ b/orchagent/bufferorch.cpp @@ -23,9 +23,6 @@ extern string gMySwitchType; extern string gMyHostName; extern string gMyAsicName; -#define BUFFER_POOL_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS "60000" - - static const vector bufferPoolWatermarkStatIds = { SAI_BUFFER_POOL_STAT_WATERMARK_BYTES, @@ -52,9 +49,6 @@ std::map> queue_port_flags; BufferOrch::BufferOrch(DBConnector *applDb, DBConnector *confDb, DBConnector *stateDb, vector &tableNames) : Orch(applDb, tableNames), - m_flexCounterDb(new DBConnector("FLEX_COUNTER_DB", 0)), - m_flexCounterTable(new ProducerTable(m_flexCounterDb.get(), FLEX_COUNTER_TABLE)), - m_flexCounterGroupTable(new ProducerTable(m_flexCounterDb.get(), FLEX_COUNTER_GROUP_TABLE)), m_countersDb(new DBConnector("COUNTERS_DB", 0)), m_stateBufferMaximumValueTable(stateDb, STATE_BUFFER_MAXIMUM_VALUE_TABLE) { @@ -229,22 +223,23 @@ void BufferOrch::initBufferConstants() void BufferOrch::initFlexCounterGroupTable(void) { string bufferPoolWmPluginName = "watermark_bufferpool.lua"; + string bufferPoolWmSha; try { string bufferPoolLuaScript = swss::loadLuaScript(bufferPoolWmPluginName); - string bufferPoolWmSha = swss::loadRedisScript(m_countersDb.get(), bufferPoolLuaScript); - - vector fvTuples; - fvTuples.emplace_back(BUFFER_POOL_PLUGIN_FIELD, bufferPoolWmSha); - fvTuples.emplace_back(POLL_INTERVAL_FIELD, BUFFER_POOL_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS); - - m_flexCounterGroupTable->set(BUFFER_POOL_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, fvTuples); + bufferPoolWmSha = swss::loadRedisScript(m_countersDb.get(), bufferPoolLuaScript); } catch (const runtime_error &e) { SWSS_LOG_ERROR("Buffer pool watermark lua script and/or flex counter group not set successfully. Runtime error: %s", e.what()); } + + setFlexCounterGroupParameter(BUFFER_POOL_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, + BUFFER_POOL_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS, + "", // do not touch stats_mode + BUFFER_POOL_PLUGIN_FIELD, + bufferPoolWmSha); } bool BufferOrch::isPortReady(const std::string& port_name) const @@ -275,7 +270,7 @@ void BufferOrch::clearBufferPoolWatermarkCounterIdList(const sai_object_id_t obj if (m_isBufferPoolWatermarkCounterIdListGenerated) { string key = BUFFER_POOL_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP ":" + sai_serialize_object_id(object_id); - m_flexCounterTable->del(key); + stopFlexCounterPolling(gSwitchId, key); } } @@ -326,37 +321,32 @@ void BufferOrch::generateBufferPoolWatermarkCounterIdList(void) if (!noWmClrCapability) { - vector fvs; - - fvs.emplace_back(STATS_MODE_FIELD, STATS_MODE_READ_AND_CLEAR); - m_flexCounterGroupTable->set(BUFFER_POOL_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, fvs); + setFlexCounterGroupStatsMode(BUFFER_POOL_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, + STATS_MODE_READ_AND_CLEAR); } // Push buffer pool watermark COUNTER_ID_LIST to FLEX_COUNTER_TABLE on a per buffer pool basis - vector fvTuples; - fvTuples.emplace_back(BUFFER_POOL_COUNTER_ID_LIST, statList); + string stats_mode; + bitMask = 1; + for (const auto &it : *(m_buffer_type_maps[APP_BUFFER_POOL_TABLE_NAME])) { string key = BUFFER_POOL_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP ":" + sai_serialize_object_id(it.second.m_saiObjectId); + stats_mode = ""; + if (noWmClrCapability) { - string stats_mode = STATS_MODE_READ_AND_CLEAR; if (noWmClrCapability & bitMask) { stats_mode = STATS_MODE_READ; } - fvTuples.emplace_back(STATS_MODE_FIELD, stats_mode); - m_flexCounterTable->set(key, fvTuples); - fvTuples.pop_back(); bitMask <<= 1; } - else - { - m_flexCounterTable->set(key, fvTuples); - } + + startFlexCounterPolling(gSwitchId, key, statList, BUFFER_POOL_COUNTER_ID_LIST, stats_mode); } m_isBufferPoolWatermarkCounterIdListGenerated = true; diff --git a/orchagent/bufferorch.h b/orchagent/bufferorch.h index de1e75c0a6..f78fe05318 100644 --- a/orchagent/bufferorch.h +++ b/orchagent/bufferorch.h @@ -9,6 +9,7 @@ #include "redisapi.h" #define BUFFER_POOL_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP "BUFFER_POOL_WATERMARK_STAT_COUNTER" +#define BUFFER_POOL_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS "60000" const string buffer_size_field_name = "size"; const string buffer_pool_type_field_name = "type"; @@ -63,10 +64,6 @@ class BufferOrch : public Orch std::unordered_map m_ready_list; std::unordered_map> m_port_ready_list_ref; - unique_ptr m_flexCounterDb; - unique_ptr m_flexCounterGroupTable; - unique_ptr m_flexCounterTable; - Table m_stateBufferMaximumValueTable; unique_ptr m_countersDb; diff --git a/orchagent/copporch.cpp b/orchagent/copporch.cpp index 9d597c601f..56f2cb4db2 100644 --- a/orchagent/copporch.cpp +++ b/orchagent/copporch.cpp @@ -26,6 +26,7 @@ extern sai_object_id_t gSwitchId; extern PortsOrch* gPortsOrch; extern Directory gDirectory; extern bool gIsNatSupported; +extern bool gTraditionalFlexCounter; #define FLEX_COUNTER_UPD_INTERVAL 1 @@ -126,11 +127,9 @@ const uint HOSTIF_TRAP_COUNTER_POLLING_INTERVAL_MS = 10000; CoppOrch::CoppOrch(DBConnector* db, string tableName) : Orch(db, tableName), m_counter_db(std::shared_ptr(new DBConnector("COUNTERS_DB", 0))), - m_flex_db(std::shared_ptr(new DBConnector("FLEX_COUNTER_DB", 0))), m_asic_db(std::shared_ptr(new DBConnector("ASIC_DB", 0))), m_counter_table(std::unique_ptr
(new Table(m_counter_db.get(), COUNTERS_TRAP_NAME_MAP))), m_vidToRidTable(std::unique_ptr
(new Table(m_asic_db.get(), "VIDTORID"))), - m_flex_counter_group_table(std::unique_ptr(new ProducerTable(m_flex_db.get(), FLEX_COUNTER_GROUP_TABLE))), m_trap_counter_manager(HOSTIF_TRAP_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, HOSTIF_TRAP_COUNTER_POLLING_INTERVAL_MS, false) { SWSS_LOG_ENTER(); @@ -772,7 +771,7 @@ void CoppOrch::doTask(SelectableTimer &timer) for (auto it = m_pendingAddToFlexCntr.begin(); it != m_pendingAddToFlexCntr.end(); ) { const auto id = sai_serialize_object_id(it->first); - if (m_vidToRidTable->hget("", id, value)) + if (!gTraditionalFlexCounter || m_vidToRidTable->hget("", id, value)) { SWSS_LOG_INFO("Registering %s, id %s", it->second.c_str(), id.c_str()); @@ -1205,20 +1204,22 @@ void CoppOrch::initTrapRatePlugin() } std::string trapRatePluginName = "trap_rates.lua"; + std::string trapSha; try { std::string trapLuaScript = swss::loadLuaScript(trapRatePluginName); - std::string trapSha = swss::loadRedisScript(m_counter_db.get(), trapLuaScript); - - vector fieldValues; - fieldValues.emplace_back(FLOW_COUNTER_PLUGIN_FIELD, trapSha); - fieldValues.emplace_back(STATS_MODE_FIELD, STATS_MODE_READ); - m_flex_counter_group_table->set(HOSTIF_TRAP_COUNTER_FLEX_COUNTER_GROUP, fieldValues); + trapSha = swss::loadRedisScript(m_counter_db.get(), trapLuaScript); } catch (const runtime_error &e) { SWSS_LOG_ERROR("Trap flex counter groups were not set successfully: %s", e.what()); } + + setFlexCounterGroupParameter(HOSTIF_TRAP_COUNTER_FLEX_COUNTER_GROUP, + "", // Do not touch poll interval + STATS_MODE_READ, + FLOW_COUNTER_PLUGIN_FIELD, + trapSha); m_trap_rate_plugin_loaded = true; } diff --git a/orchagent/copporch.h b/orchagent/copporch.h index c8f956b6d7..fa49324a88 100644 --- a/orchagent/copporch.h +++ b/orchagent/copporch.h @@ -98,11 +98,9 @@ class CoppOrch : public Orch std::map m_pendingAddToFlexCntr; std::shared_ptr m_counter_db; - std::shared_ptr m_flex_db; std::shared_ptr m_asic_db; std::unique_ptr
m_counter_table; std::unique_ptr
m_vidToRidTable; - std::unique_ptr m_flex_counter_group_table; FlexCounterManager m_trap_counter_manager; diff --git a/orchagent/fabricportsorch.cpp b/orchagent/fabricportsorch.cpp index d61f5d13f2..c7eb448856 100644 --- a/orchagent/fabricportsorch.cpp +++ b/orchagent/fabricportsorch.cpp @@ -84,8 +84,6 @@ FabricPortsOrch::FabricPortsOrch(DBConnector *appl_db, vector(new Table(m_counter_db.get(), COUNTERS_FABRIC_PORT_NAME_MAP)); m_fabricCounterTable = unique_ptr
(new Table(m_counter_db.get(), COUNTERS_TABLE)); - m_flex_db = shared_ptr(new DBConnector("FLEX_COUNTER_DB", 0)); - m_flexCounterTable = unique_ptr(new ProducerTable(m_flex_db.get(), APP_FABRIC_PORT_TABLE_NAME)); m_appl_db = shared_ptr(new DBConnector("APPL_DB", 0)); m_applTable = unique_ptr
(new Table(m_appl_db.get(), APP_FABRIC_MONITOR_PORT_TABLE_NAME)); m_applMonitorConstTable = unique_ptr
(new Table(m_appl_db.get(), APP_FABRIC_MONITOR_DATA_TABLE_NAME)); diff --git a/orchagent/fabricportsorch.h b/orchagent/fabricportsorch.h index e72ae56e3c..4795a6a6fc 100644 --- a/orchagent/fabricportsorch.h +++ b/orchagent/fabricportsorch.h @@ -26,7 +26,6 @@ class FabricPortsOrch : public Orch, public Subject shared_ptr m_state_db; shared_ptr m_counter_db; - shared_ptr m_flex_db; shared_ptr m_appl_db; unique_ptr
m_stateTable; diff --git a/orchagent/flex_counter/flex_counter_manager.cpp b/orchagent/flex_counter/flex_counter_manager.cpp index 95fb28171d..c29c4b9d6e 100644 --- a/orchagent/flex_counter/flex_counter_manager.cpp +++ b/orchagent/flex_counter/flex_counter_manager.cpp @@ -18,6 +18,10 @@ using swss::DBConnector; using swss::FieldValueTuple; using swss::ProducerTable; +extern sai_switch_api_t *sai_switch_api; + +extern sai_object_id_t gSwitchId; + const string FLEX_COUNTER_ENABLE("enable"); const string FLEX_COUNTER_DISABLE("disable"); @@ -89,13 +93,13 @@ FlexCounterManager::FlexCounterManager( const uint polling_interval, const bool enabled, FieldValueTuple fv_plugin) : - FlexCounterManager("FLEX_COUNTER_DB", group_name, stats_mode, + FlexCounterManager(false, group_name, stats_mode, polling_interval, enabled, fv_plugin) { } FlexCounterManager::FlexCounterManager( - const string& db_name, + const bool is_gearbox, const string& group_name, const StatsMode stats_mode, const uint polling_interval, @@ -106,11 +110,7 @@ FlexCounterManager::FlexCounterManager( polling_interval(polling_interval), enabled(enabled), fv_plugin(fv_plugin), - flex_counter_db(new DBConnector(db_name, 0)), - flex_counter_group_table(new ProducerTable(flex_counter_db.get(), - FLEX_COUNTER_GROUP_TABLE)), - flex_counter_table(new ProducerTable(flex_counter_db.get(), - FLEX_COUNTER_TABLE)) + is_gearbox(is_gearbox) { SWSS_LOG_ENTER(); @@ -125,13 +125,10 @@ FlexCounterManager::~FlexCounterManager() for (const auto& counter: installed_counters) { - flex_counter_table->del(getFlexCounterTableKey(group_name, counter)); + stopFlexCounterPolling(counter.second, getFlexCounterTableKey(group_name, counter.first)); } - if (flex_counter_group_table != nullptr) - { - flex_counter_group_table->del(group_name); - } + delFlexCounterGroup(group_name, is_gearbox); SWSS_LOG_DEBUG("Deleted flex counter group '%s'.", group_name.c_str()); } @@ -140,19 +137,13 @@ void FlexCounterManager::applyGroupConfiguration() { SWSS_LOG_ENTER(); - vector field_values = - { - FieldValueTuple(STATS_MODE_FIELD, stats_mode_lookup.at(stats_mode)), - FieldValueTuple(POLL_INTERVAL_FIELD, std::to_string(polling_interval)), - FieldValueTuple(FLEX_COUNTER_STATUS_FIELD, status_lookup.at(enabled)) - }; - - if (!fvField(fv_plugin).empty()) - { - field_values.emplace_back(fv_plugin); - } - - flex_counter_group_table->set(group_name, field_values); + setFlexCounterGroupParameter(group_name, + std::to_string(polling_interval), + stats_mode_lookup.at(stats_mode), + fvField(fv_plugin), + fvValue(fv_plugin), + status_lookup.at(enabled), + is_gearbox); } void FlexCounterManager::updateGroupPollingInterval( @@ -160,11 +151,7 @@ void FlexCounterManager::updateGroupPollingInterval( { SWSS_LOG_ENTER(); - vector field_values = - { - FieldValueTuple(POLL_INTERVAL_FIELD, std::to_string(polling_interval)) - }; - flex_counter_group_table->set(group_name, field_values); + setFlexCounterGroupPollInterval(group_name, std::to_string(polling_interval), is_gearbox); SWSS_LOG_DEBUG("Set polling interval for flex counter group '%s' to %d ms.", group_name.c_str(), polling_interval); @@ -181,11 +168,7 @@ void FlexCounterManager::enableFlexCounterGroup() return; } - vector field_values = - { - FieldValueTuple(FLEX_COUNTER_STATUS_FIELD, FLEX_COUNTER_ENABLE) - }; - flex_counter_group_table->set(group_name, field_values); + setFlexCounterGroupOperation(group_name, FLEX_COUNTER_ENABLE, is_gearbox); enabled = true; SWSS_LOG_DEBUG("Enabling flex counters for group '%s'.", @@ -203,11 +186,7 @@ void FlexCounterManager::disableFlexCounterGroup() return; } - vector field_values = - { - FieldValueTuple(FLEX_COUNTER_STATUS_FIELD, FLEX_COUNTER_DISABLE) - }; - flex_counter_group_table->set(group_name, field_values); + setFlexCounterGroupOperation(group_name, FLEX_COUNTER_DISABLE, is_gearbox); enabled = false; SWSS_LOG_DEBUG("Disabling flex counters for group '%s'.", @@ -219,7 +198,8 @@ void FlexCounterManager::disableFlexCounterGroup() void FlexCounterManager::setCounterIdList( const sai_object_id_t object_id, const CounterType counter_type, - const unordered_set& counter_stats) + const unordered_set& counter_stats, + const sai_object_id_t switch_id) { SWSS_LOG_ENTER(); @@ -231,12 +211,12 @@ void FlexCounterManager::setCounterIdList( return; } - std::vector field_values = - { - FieldValueTuple(counter_type_it->second, serializeCounterStats(counter_stats)) - }; - flex_counter_table->set(getFlexCounterTableKey(group_name, object_id), field_values); - installed_counters.insert(object_id); + auto key = getFlexCounterTableKey(group_name, object_id); + auto counter_ids = serializeCounterStats(counter_stats); + auto effective_switch_id = switch_id == SAI_NULL_OBJECT_ID ? gSwitchId : switch_id; + + startFlexCounterPolling(effective_switch_id, key, counter_ids, counter_type_it->second); + installed_counters[object_id] = effective_switch_id; SWSS_LOG_DEBUG("Updated flex counter id list for object '%" PRIu64 "' in group '%s'.", object_id, @@ -258,7 +238,8 @@ void FlexCounterManager::clearCounterIdList(const sai_object_id_t object_id) return; } - flex_counter_table->del(getFlexCounterTableKey(group_name, object_id)); + auto key = getFlexCounterTableKey(group_name, object_id); + stopFlexCounterPolling(installed_counters[object_id], key); installed_counters.erase(counter_it); SWSS_LOG_DEBUG("Cleared flex counter id list for object '%" PRIu64 "' in group '%s'.", @@ -272,7 +253,7 @@ string FlexCounterManager::getFlexCounterTableKey( { SWSS_LOG_ENTER(); - return group_name + flex_counter_table->getTableNameSeparator() + sai_serialize_object_id(object_id); + return group_name + ":" + sai_serialize_object_id(object_id); } // serializeCounterStats turns a set of stats into a format suitable for FLEX_COUNTER_DB. diff --git a/orchagent/flex_counter/flex_counter_manager.h b/orchagent/flex_counter/flex_counter_manager.h index 38bf829058..80a9e606e6 100644 --- a/orchagent/flex_counter/flex_counter_manager.h +++ b/orchagent/flex_counter/flex_counter_manager.h @@ -53,7 +53,7 @@ class FlexCounterManager {} FlexCounterManager( - const std::string& db_name, + const bool is_gearbox, const std::string& group_name, const StatsMode stats_mode, const uint polling_interval, @@ -71,7 +71,8 @@ class FlexCounterManager void setCounterIdList( const sai_object_id_t object_id, const CounterType counter_type, - const std::unordered_set& counter_stats); + const std::unordered_set& counter_stats, + const sai_object_id_t switch_id=SAI_NULL_OBJECT_ID); void clearCounterIdList(const sai_object_id_t object_id); const std::string& getGroupName() const @@ -109,11 +110,8 @@ class FlexCounterManager uint polling_interval; bool enabled; swss::FieldValueTuple fv_plugin; - std::unordered_set installed_counters; - - std::shared_ptr flex_counter_db = nullptr; - std::shared_ptr flex_counter_group_table = nullptr; - std::shared_ptr flex_counter_table = nullptr; + std::unordered_map installed_counters; + bool is_gearbox; static const std::unordered_map stats_mode_lookup; static const std::unordered_map status_lookup; diff --git a/orchagent/flexcounterorch.cpp b/orchagent/flexcounterorch.cpp index bc974181f1..19302face9 100644 --- a/orchagent/flexcounterorch.cpp +++ b/orchagent/flexcounterorch.cpp @@ -16,6 +16,7 @@ #include "flowcounterrouteorch.h" extern sai_port_api_t *sai_port_api; +extern sai_switch_api_t *sai_switch_api; extern PortsOrch *gPortsOrch; extern FabricPortsOrch *gFabricPortsOrch; @@ -24,6 +25,7 @@ extern BufferOrch *gBufferOrch; extern Directory gDirectory; extern CoppOrch *gCoppOrch; extern FlowCounterRouteOrch *gFlowCounterRouteOrch; +extern sai_object_id_t gSwitchId; #define BUFFER_POOL_WATERMARK_KEY "BUFFER_POOL_WATERMARK" #define PORT_KEY "PORT" @@ -67,11 +69,7 @@ FlexCounterOrch::FlexCounterOrch(DBConnector *db, vector &tableNames): m_flexCounterConfigTable(db, CFG_FLEX_COUNTER_TABLE_NAME), m_bufferQueueConfigTable(db, CFG_BUFFER_QUEUE_TABLE_NAME), m_bufferPgConfigTable(db, CFG_BUFFER_PG_TABLE_NAME), - m_deviceMetadataConfigTable(db, CFG_DEVICE_METADATA_TABLE_NAME), - m_flexCounterDb(new DBConnector("FLEX_COUNTER_DB", 0)), - m_flexCounterGroupTable(new ProducerTable(m_flexCounterDb.get(), FLEX_COUNTER_GROUP_TABLE)), - m_gbflexCounterDb(new DBConnector("GB_FLEX_COUNTER_DB", 0)), - m_gbflexCounterGroupTable(new ProducerTable(m_gbflexCounterDb.get(), FLEX_COUNTER_GROUP_TABLE)) + m_deviceMetadataConfigTable(db, CFG_DEVICE_METADATA_TABLE_NAME) { SWSS_LOG_ENTER(); } @@ -115,6 +113,7 @@ void FlexCounterOrch::doTask(Consumer &consumer) if (op == SET_COMMAND) { auto itDelay = std::find(std::begin(data), std::end(data), FieldValueTuple(FLEX_COUNTER_DELAY_STATUS_FIELD, "true")); + string poll_interval; if (itDelay != data.end()) { @@ -128,14 +127,13 @@ void FlexCounterOrch::doTask(Consumer &consumer) if (field == POLL_INTERVAL_FIELD) { - vector fieldValues; - fieldValues.emplace_back(POLL_INTERVAL_FIELD, value); - m_flexCounterGroupTable->set(flexCounterGroupMap[key], fieldValues); + setFlexCounterGroupPollInterval(flexCounterGroupMap[key], value); + if (gPortsOrch && gPortsOrch->isGearboxEnabled()) { if (key == PORT_KEY || key.rfind("MACSEC", 0) == 0) { - m_gbflexCounterGroupTable->set(flexCounterGroupMap[key], fieldValues); + setFlexCounterGroupPollInterval(flexCounterGroupMap[key], value, true); } } } @@ -228,15 +226,14 @@ void FlexCounterOrch::doTask(Consumer &consumer) m_route_flow_counter_enabled = false; } } - vector fieldValues; - fieldValues.emplace_back(FLEX_COUNTER_STATUS_FIELD, value); - m_flexCounterGroupTable->set(flexCounterGroupMap[key], fieldValues); + + setFlexCounterGroupOperation(flexCounterGroupMap[key], value); if (gPortsOrch && gPortsOrch->isGearboxEnabled()) { if (key == PORT_KEY || key.rfind("MACSEC", 0) == 0) { - m_gbflexCounterGroupTable->set(flexCounterGroupMap[key], fieldValues); + setFlexCounterGroupOperation(flexCounterGroupMap[key], value, true); } } } diff --git a/orchagent/flexcounterorch.h b/orchagent/flexcounterorch.h index 06a1ddadbc..4bc74dc3b8 100644 --- a/orchagent/flexcounterorch.h +++ b/orchagent/flexcounterorch.h @@ -55,10 +55,6 @@ class FlexCounterOrch: public Orch bool bake() override; private: - std::shared_ptr m_flexCounterDb = nullptr; - std::shared_ptr m_flexCounterGroupTable = nullptr; - std::shared_ptr m_gbflexCounterDb = nullptr; - std::shared_ptr m_gbflexCounterGroupTable = nullptr; bool m_port_counter_enabled = false; bool m_port_buffer_drop_counter_enabled = false; bool m_queue_enabled = false; diff --git a/orchagent/intfsorch.cpp b/orchagent/intfsorch.cpp index 2a5e34ff93..a02c628fcf 100644 --- a/orchagent/intfsorch.cpp +++ b/orchagent/intfsorch.cpp @@ -37,10 +37,10 @@ extern bool gIsNatSupported; extern NeighOrch *gNeighOrch; extern string gMySwitchType; extern int32_t gVoqMySwitchId; +extern bool gTraditionalFlexCounter; const int intfsorch_pri = 35; -#define RIF_FLEX_STAT_COUNTER_POLL_MSECS "1000" #define UPDATE_MAPS_SEC 1 #define MGMT_VRF "mgmt" @@ -64,44 +64,40 @@ IntfsOrch::IntfsOrch(DBConnector *db, string tableName, VRFOrch *vrf_orch, DBCon /* Initialize DB connectors */ m_counter_db = shared_ptr(new DBConnector("COUNTERS_DB", 0)); - m_flex_db = shared_ptr(new DBConnector("FLEX_COUNTER_DB", 0)); m_asic_db = shared_ptr(new DBConnector("ASIC_DB", 0)); /* Initialize COUNTER_DB tables */ m_rifNameTable = unique_ptr
(new Table(m_counter_db.get(), COUNTERS_RIF_NAME_MAP)); m_rifTypeTable = unique_ptr
(new Table(m_counter_db.get(), COUNTERS_RIF_TYPE_MAP)); - m_vidToRidTable = unique_ptr
(new Table(m_asic_db.get(), "VIDTORID")); + if (gTraditionalFlexCounter) + { + m_vidToRidTable = unique_ptr
(new Table(m_asic_db.get(), "VIDTORID")); + } + auto intervT = timespec { .tv_sec = UPDATE_MAPS_SEC , .tv_nsec = 0 }; m_updateMapsTimer = new SelectableTimer(intervT); auto executorT = new ExecutableTimer(m_updateMapsTimer, this, "UPDATE_MAPS_TIMER"); Orch::addExecutor(executorT); - /* Initialize FLEX_COUNTER_DB tables */ - m_flexCounterTable = unique_ptr(new ProducerTable(m_flex_db.get(), FLEX_COUNTER_TABLE)); - m_flexCounterGroupTable = unique_ptr(new ProducerTable(m_flex_db.get(), FLEX_COUNTER_GROUP_TABLE)); - - vector fieldValues; - fieldValues.emplace_back(POLL_INTERVAL_FIELD, RIF_FLEX_STAT_COUNTER_POLL_MSECS); - fieldValues.emplace_back(STATS_MODE_FIELD, STATS_MODE_READ); - m_flexCounterGroupTable->set(RIF_STAT_COUNTER_FLEX_COUNTER_GROUP, fieldValues); string rifRatePluginName = "rif_rates.lua"; + string rifRateSha; try { string rifRateLuaScript = swss::loadLuaScript(rifRatePluginName); - string rifRateSha = swss::loadRedisScript(m_counter_db.get(), rifRateLuaScript); - - vector fieldValues; - fieldValues.emplace_back(RIF_PLUGIN_FIELD, rifRateSha); - fieldValues.emplace_back(POLL_INTERVAL_FIELD, RIF_FLEX_STAT_COUNTER_POLL_MSECS); - fieldValues.emplace_back(STATS_MODE_FIELD, STATS_MODE_READ); - m_flexCounterGroupTable->set(RIF_STAT_COUNTER_FLEX_COUNTER_GROUP, fieldValues); + rifRateSha = swss::loadRedisScript(m_counter_db.get(), rifRateLuaScript); } catch (const runtime_error &e) { SWSS_LOG_WARN("RIF flex counter group plugins was not set successfully: %s", e.what()); } + setFlexCounterGroupParameter(RIF_STAT_COUNTER_FLEX_COUNTER_GROUP, + RIF_FLEX_STAT_COUNTER_POLL_MSECS, + STATS_MODE_READ, + RIF_PLUGIN_FIELD, + rifRateSha); + if(gMySwitchType == "voq") { //Add subscriber to process VOQ system interface @@ -1506,11 +1502,11 @@ void IntfsOrch::addRifToFlexCounter(const string &id, const string &name, const { counters_stream << sai_serialize_router_interface_stat(it) << comma; } + auto &&counters_str = counters_stream.str(); /* check the state of intf, if registering the intf to FC will result in runtime error */ - vector fieldValues; - fieldValues.emplace_back(RIF_COUNTER_ID_LIST, counters_stream.str()); - m_flexCounterTable->set(key, fieldValues); + startFlexCounterPolling(gSwitchId, key, counters_str.c_str(), RIF_COUNTER_ID_LIST); + SWSS_LOG_DEBUG("Registered interface %s to Flex counter", name.c_str()); } @@ -1524,7 +1520,8 @@ void IntfsOrch::removeRifFromFlexCounter(const string &id, const string &name) /* remove it from FLEX_COUNTER_DB */ string key = getRifFlexCounterTableKey(id); - m_flexCounterTable->del(key); + stopFlexCounterPolling(gSwitchId, key); + SWSS_LOG_DEBUG("Unregistered interface %s from Flex counter", name.c_str()); } @@ -1584,7 +1581,7 @@ void IntfsOrch::doTask(SelectableTimer &timer) type = ""; break; } - if (m_vidToRidTable->hget("", id, value)) + if (!gTraditionalFlexCounter || m_vidToRidTable->hget("", id, value)) { SWSS_LOG_INFO("Registering %s it is ready", it->m_alias.c_str()); addRifToFlexCounter(id, it->m_alias, type); diff --git a/orchagent/intfsorch.h b/orchagent/intfsorch.h index ea15ada14b..71d89be725 100644 --- a/orchagent/intfsorch.h +++ b/orchagent/intfsorch.h @@ -18,6 +18,7 @@ extern MacAddress gMacAddress; #define RIF_STAT_COUNTER_FLEX_COUNTER_GROUP "RIF_STAT_COUNTER" #define RIF_RATE_COUNTER_FLEX_COUNTER_GROUP "RIF_RATE_COUNTER" +#define RIF_FLEX_STAT_COUNTER_POLL_MSECS "1000" struct IntfsEntry { @@ -84,13 +85,10 @@ class IntfsOrch : public Orch void doTask(SelectableTimer &timer); shared_ptr m_counter_db; - shared_ptr m_flex_db; shared_ptr m_asic_db; unique_ptr
m_rifNameTable; unique_ptr
m_rifTypeTable; unique_ptr
m_vidToRidTable; - unique_ptr m_flexCounterTable; - unique_ptr m_flexCounterGroupTable; std::set m_removingIntfses; diff --git a/orchagent/macsecorch.cpp b/orchagent/macsecorch.cpp index 9a5e48f883..bedf4fd882 100644 --- a/orchagent/macsecorch.cpp +++ b/orchagent/macsecorch.cpp @@ -621,17 +621,17 @@ MACsecOrch::MACsecOrch( StatsMode::READ, MACSEC_STAT_POLLING_INTERVAL_MS, true), m_gb_macsec_sa_attr_manager( - "GB_FLEX_COUNTER_DB", + true, COUNTERS_MACSEC_SA_ATTR_GROUP, StatsMode::READ, MACSEC_STAT_XPN_POLLING_INTERVAL_MS, true), m_gb_macsec_sa_stat_manager( - "GB_FLEX_COUNTER_DB", + true, COUNTERS_MACSEC_SA_GROUP, StatsMode::READ, MACSEC_STAT_POLLING_INTERVAL_MS, true), m_gb_macsec_flow_stat_manager( - "GB_FLEX_COUNTER_DB", + true, COUNTERS_MACSEC_FLOW_GROUP, StatsMode::READ, MACSEC_STAT_POLLING_INTERVAL_MS, true) @@ -2352,16 +2352,16 @@ void MACsecOrch::installCounter( switch(counter_type) { case CounterType::MACSEC_SA_ATTR: - MACsecSaAttrStatManager(ctx).setCounterIdList(obj_id, counter_type, counter_stats); + MACsecSaAttrStatManager(ctx).setCounterIdList(obj_id, counter_type, counter_stats, *ctx.get_switch_id()); break; case CounterType::MACSEC_SA: - MACsecSaStatManager(ctx).setCounterIdList(obj_id, counter_type, counter_stats); + MACsecSaStatManager(ctx).setCounterIdList(obj_id, counter_type, counter_stats, *ctx.get_switch_id()); MACsecCountersMap(ctx).hset("", obj_name, sai_serialize_object_id(obj_id)); break; case CounterType::MACSEC_FLOW: - MACsecFlowStatManager(ctx).setCounterIdList(obj_id, counter_type, counter_stats); + MACsecFlowStatManager(ctx).setCounterIdList(obj_id, counter_type, counter_stats, *ctx.get_switch_id()); break; default: diff --git a/orchagent/main.cpp b/orchagent/main.cpp index 0add517a05..ad03648a7d 100644 --- a/orchagent/main.cpp +++ b/orchagent/main.cpp @@ -68,10 +68,11 @@ int32_t gVoqMaxCores = 0; uint32_t gCfgSystemPorts = 0; string gMyHostName = ""; string gMyAsicName = ""; +bool gTraditionalFlexCounter = false; void usage() { - cout << "usage: orchagent [-h] [-r record_type] [-d record_location] [-f swss_rec_filename] [-j sairedis_rec_filename] [-b batch_size] [-m MAC] [-i INST_ID] [-s] [-z mode] [-k bulk_size] [-q zmq_server_address]" << endl; + cout << "usage: orchagent [-h] [-r record_type] [-d record_location] [-f swss_rec_filename] [-j sairedis_rec_filename] [-b batch_size] [-m MAC] [-i INST_ID] [-s] [-z mode] [-k bulk_size] [-q zmq_server_address] [-c mode]" << endl; cout << " -h: display this message" << endl; cout << " -r record_type: record orchagent logs with type (default 3)" << endl; cout << " Bit 0: sairedis.rec, Bit 1: swss.rec, Bit 2: responsepublisher.rec. For example:" << endl; @@ -90,6 +91,7 @@ void usage() cout << " -j sairedis_rec_filename: sairedis record log filename(default sairedis.rec)" << endl; cout << " -k max bulk size in bulk mode (default 1000)" << endl; cout << " -q zmq_server_address: ZMQ server address (default disable ZMQ)" << endl; + cout << " -c counter mode (traditional|asic_db), default: asic_db" << endl; } void sighup_handler(int signo) @@ -344,7 +346,7 @@ int main(int argc, char **argv) string responsepublisher_rec_filename = Recorder::RESPPUB_FNAME; int record_type = 3; // Only swss and sairedis recordings enabled by default. - while ((opt = getopt(argc, argv, "b:m:r:f:j:d:i:hsz:k:q:")) != -1) + while ((opt = getopt(argc, argv, "b:m:r:f:j:d:i:hsz:k:q:c:")) != -1) { switch (opt) { @@ -395,6 +397,12 @@ int main(int argc, char **argv) case 'z': sai_deserialize_redis_communication_mode(optarg, gRedisCommunicationMode); break; + case 'c': + if (optarg == string("traditional")) + { + gTraditionalFlexCounter = true; + } + break; case 'f': if (optarg) @@ -446,6 +454,7 @@ int main(int argc, char **argv) /* Initialize sairedis */ initSaiApi(); initSaiRedis(); + initFlexCounterTables(); /* Initialize remaining recorder parameters */ Recorder::Instance().swss.setRecord( diff --git a/orchagent/p4orch/tests/test_main.cpp b/orchagent/p4orch/tests/test_main.cpp index 96d005ea24..2f855be545 100644 --- a/orchagent/p4orch/tests/test_main.cpp +++ b/orchagent/p4orch/tests/test_main.cpp @@ -44,6 +44,7 @@ extern int gBatchSize; size_t gMaxBulkSize = DEFAULT_MAX_BULK_SIZE; bool gSyncMode = false; bool gIsNatSupported = false; +bool gTraditionalFlexCounter = false; PortsOrch *gPortsOrch; CrmOrch *gCrmOrch; @@ -241,3 +242,56 @@ int main(int argc, char *argv[]) return RUN_ALL_TESTS(); } + +void setFlexCounterGroupParameter(const std::string &group, + const std::string &poll_interval, + const std::string &stats_mode, + const std::string &plugin_name, + const std::string &plugins, + const std::string &operation, + bool is_gearbox) +{ + return; +} + +void setFlexCounterGroupPollInterval(const std::string &group, + const std::string &poll_interval, + bool is_gearbox) +{ + return; +} + +void setFlexCounterGroupOperation(const std::string &group, + const std::string &operation, + bool is_gearbox) +{ + return; +} + +void setFlexCounterGroupStatsMode(const std::string &group, + const std::string &stats_mode, + bool is_gearbox) +{ + return; +} + +void delFlexCounterGroup(const std::string &group, + bool is_gearbox) +{ + return; +} + +void startFlexCounterPolling(sai_object_id_t switch_oid, + const std::string &key, + const std::string &counter_ids, + const std::string &counter_field_name, + const std::string &stats_mode) +{ + return; +} + +void stopFlexCounterPolling(sai_object_id_t switch_oid, + const std::string &key) +{ + return; +} diff --git a/orchagent/pfcwdorch.cpp b/orchagent/pfcwdorch.cpp index 7c78f81d6b..3cd8808097 100644 --- a/orchagent/pfcwdorch.cpp +++ b/orchagent/pfcwdorch.cpp @@ -345,9 +345,7 @@ task_process_status PfcWdSwOrch::createEntry(const if (field == POLL_INTERVAL_FIELD) { - vector fieldValues; - fieldValues.emplace_back(POLL_INTERVAL_FIELD, value); - m_flexCounterGroupTable->set(PFC_WD_FLEX_COUNTER_GROUP, fieldValues); + setFlexCounterGroupPollInterval(PFC_WD_FLEX_COUNTER_GROUP, value); } else if (field == BIG_RED_SWITCH_FIELD) { @@ -551,13 +549,10 @@ bool PfcWdSwOrch::registerInWdDb(const Port& port, if (!c_portStatIds.empty()) { string key = getFlexCounterTableKey(sai_serialize_object_id(port.m_port_id)); - vector fieldValues; - // Only register lossless tc counters in database. string str = counterIdsToStr(c_portStatIds, &sai_serialize_port_stat); string filteredStr = filterPfcCounters(str, losslessTc); - fieldValues.emplace_back(PORT_COUNTER_ID_LIST, filteredStr); - m_flexCounterTable->set(key, fieldValues); + startFlexCounterPolling(gSwitchId, key, filteredStr, PORT_COUNTER_ID_LIST); } for (auto i : losslessTc) @@ -578,26 +573,23 @@ bool PfcWdSwOrch::registerInWdDb(const Port& port, this->getCountersTable()->set(queueIdStr, countersFieldValues); // We register our queues in PFC_WD table so that syncd will know that it must poll them - vector queueFieldValues; + string key = getFlexCounterTableKey(queueIdStr); if (!c_queueStatIds.empty()) { string str = counterIdsToStr(c_queueStatIds, sai_serialize_queue_stat); - queueFieldValues.emplace_back(QUEUE_COUNTER_ID_LIST, str); + startFlexCounterPolling(gSwitchId, key, str, QUEUE_COUNTER_ID_LIST); } if (!c_queueAttrIds.empty()) { string str = counterIdsToStr(c_queueAttrIds, sai_serialize_queue_attr); - queueFieldValues.emplace_back(QUEUE_ATTR_ID_LIST, str); + startFlexCounterPolling(gSwitchId, key, str, QUEUE_ATTR_ID_LIST); } // Create internal entry m_entryMap.emplace(queueId, PfcWdQueueEntry(action, port.m_port_id, i, port.m_alias)); - string key = getFlexCounterTableKey(queueIdStr); - m_flexCounterTable->set(key, queueFieldValues); - // Initialize PFC WD related counters PfcWdActionHandler::initWdCounters( this->getCountersTable(), @@ -658,15 +650,15 @@ void PfcWdSwOrch::unregisterFromWdDb(const Port& po SWSS_LOG_ENTER(); string key = getFlexCounterTableKey(sai_serialize_object_id(port.m_port_id)); - m_flexCounterTable->del(key); + stopFlexCounterPolling(gSwitchId, key); for (uint8_t i = 0; i < PFC_WD_TC_MAX; i++) { sai_object_id_t queueId = port.m_queue_ids[i]; - string key = getFlexCounterTableKey(sai_serialize_object_id(queueId)); + key = getFlexCounterTableKey(sai_serialize_object_id(queueId)); // Unregister in syncd - m_flexCounterTable->del(key); + stopFlexCounterPolling(gSwitchId, key); auto entry = m_entryMap.find(queueId); if (entry != m_entryMap.end() && entry->second.handler != nullptr) @@ -692,9 +684,6 @@ PfcWdSwOrch::PfcWdSwOrch( const vector &queueAttrIds, int pollInterval): PfcWdOrch(db, tableNames), - m_flexCounterDb(new DBConnector("FLEX_COUNTER_DB", 0)), - m_flexCounterTable(new ProducerTable(m_flexCounterDb.get(), FLEX_COUNTER_TABLE)), - m_flexCounterGroupTable(new ProducerTable(m_flexCounterDb.get(), FLEX_COUNTER_GROUP_TABLE)), c_portStatIds(portStatIds), c_queueStatIds(queueStatIds), c_queueAttrIds(queueAttrIds), @@ -707,6 +696,8 @@ PfcWdSwOrch::PfcWdSwOrch( string detectSha, restoreSha; string detectPluginName = "pfc_detect_" + this->m_platform + ".lua"; string restorePluginName; + string pollIntervalStr = to_string(m_pollInterval); + string plugins; if (this->m_platform == CISCO_8000_PLATFORM_SUBSTRING) { restorePluginName = "pfc_restore_" + this->m_platform + ".lua"; } else { @@ -724,18 +715,19 @@ PfcWdSwOrch::PfcWdSwOrch( restoreSha = swss::loadRedisScript( this->getCountersDb().get(), restoreLuaScript); - - vector fieldValues; - fieldValues.emplace_back(QUEUE_PLUGIN_FIELD, detectSha + "," + restoreSha); - fieldValues.emplace_back(POLL_INTERVAL_FIELD, to_string(m_pollInterval)); - fieldValues.emplace_back(STATS_MODE_FIELD, STATS_MODE_READ); - m_flexCounterGroupTable->set(PFC_WD_FLEX_COUNTER_GROUP, fieldValues); + plugins = detectSha + "," + restoreSha; } catch (...) { SWSS_LOG_WARN("Lua scripts and polling interval for PFC watchdog were not set successfully"); } + setFlexCounterGroupParameter(PFC_WD_FLEX_COUNTER_GROUP, + pollIntervalStr, + STATS_MODE_READ, + QUEUE_PLUGIN_FIELD, + plugins); + auto consumer = new swss::NotificationConsumer( this->getCountersDb().get(), "PFC_WD_ACTION"); @@ -758,7 +750,7 @@ template PfcWdSwOrch::~PfcWdSwOrch(void) { SWSS_LOG_ENTER(); - m_flexCounterGroupTable->del(PFC_WD_FLEX_COUNTER_GROUP); + delFlexCounterGroup(PFC_WD_FLEX_COUNTER_GROUP); } template diff --git a/orchagent/pfcwdorch.h b/orchagent/pfcwdorch.h index 935582289c..261c1e2c3d 100644 --- a/orchagent/pfcwdorch.h +++ b/orchagent/pfcwdorch.h @@ -15,6 +15,8 @@ extern "C" { #define PFC_WD_FLEX_COUNTER_GROUP "PFC_WD" +const string pfc_wd_flex_counter_group = PFC_WD_FLEX_COUNTER_GROUP; + enum class PfcWdAction { PFC_WD_ACTION_UNKNOWN, @@ -137,10 +139,6 @@ class PfcWdSwOrch: public PfcWdOrch const vector c_queueStatIds; const vector c_queueAttrIds; - shared_ptr m_flexCounterDb = nullptr; - shared_ptr m_flexCounterTable = nullptr; - shared_ptr m_flexCounterGroupTable = nullptr; - bool m_bigRedSwitchFlag = false; int m_pollInterval; diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index b946c96624..429fb3d198 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -45,6 +45,7 @@ extern sai_queue_api_t *sai_queue_api; extern sai_object_id_t gSwitchId; extern sai_fdb_api_t *sai_fdb_api; extern sai_l2mc_group_api_t *sai_l2mc_group_api; +extern sai_buffer_api_t *sai_buffer_api; extern IntfsOrch *gIntfsOrch; extern NeighOrch *gNeighOrch; extern CrmOrch *gCrmOrch; @@ -72,10 +73,6 @@ extern event_handle_t g_events_handle; #define PORT_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS 1000 #define PORT_BUFFER_DROP_STAT_POLLING_INTERVAL_MS 60000 #define QUEUE_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS 10000 -#define QUEUE_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS "60000" -#define PG_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS "60000" -#define PG_DROP_FLEX_STAT_COUNTER_POLL_MSECS "10000" -#define PORT_RATE_FLEX_COUNTER_POLLING_INTERVAL_MS "1000" // types -------------------------------------------------------------------------------------------------------------- @@ -412,7 +409,7 @@ PortsOrch::PortsOrch(DBConnector *db, DBConnector *stateDb, vector(new Table(m_counter_db.get(), COUNTERS_PG_PORT_MAP)); m_pgIndexTable = unique_ptr
(new Table(m_counter_db.get(), COUNTERS_PG_INDEX_MAP)); - m_flex_db = shared_ptr(new DBConnector("FLEX_COUNTER_DB", 0)); - m_flexCounterTable = unique_ptr(new ProducerTable(m_flex_db.get(), FLEX_COUNTER_TABLE)); - m_flexCounterGroupTable = unique_ptr(new ProducerTable(m_flex_db.get(), FLEX_COUNTER_GROUP_TABLE)); - m_state_db = shared_ptr(new DBConnector("STATE_DB", 0)); m_stateBufferMaximumValueTable = unique_ptr
(new Table(m_state_db.get(), STATE_BUFFER_MAXIMUM_VALUE_TABLE)); initGearbox(); - string queueWmSha, pgWmSha; + string queueWmSha, pgWmSha, portRateSha; string queueWmPluginName = "watermark_queue.lua"; string pgWmPluginName = "watermark_pg.lua"; string portRatePluginName = "port_rates.lua"; @@ -474,36 +467,35 @@ PortsOrch::PortsOrch(DBConnector *db, DBConnector *stateDb, vector fieldValues; - fieldValues.emplace_back(QUEUE_PLUGIN_FIELD, queueWmSha); - fieldValues.emplace_back(POLL_INTERVAL_FIELD, QUEUE_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS); - fieldValues.emplace_back(STATS_MODE_FIELD, STATS_MODE_READ_AND_CLEAR); - m_flexCounterGroupTable->set(QUEUE_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, fieldValues); - - fieldValues.clear(); - fieldValues.emplace_back(PG_PLUGIN_FIELD, pgWmSha); - fieldValues.emplace_back(POLL_INTERVAL_FIELD, PG_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS); - fieldValues.emplace_back(STATS_MODE_FIELD, STATS_MODE_READ_AND_CLEAR); - m_flexCounterGroupTable->set(PG_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, fieldValues); - - fieldValues.clear(); - fieldValues.emplace_back(PORT_PLUGIN_FIELD, portRateSha); - fieldValues.emplace_back(POLL_INTERVAL_FIELD, PORT_RATE_FLEX_COUNTER_POLLING_INTERVAL_MS); - fieldValues.emplace_back(STATS_MODE_FIELD, STATS_MODE_READ); - m_flexCounterGroupTable->set(PORT_STAT_COUNTER_FLEX_COUNTER_GROUP, fieldValues); - - fieldValues.clear(); - fieldValues.emplace_back(POLL_INTERVAL_FIELD, PG_DROP_FLEX_STAT_COUNTER_POLL_MSECS); - fieldValues.emplace_back(STATS_MODE_FIELD, STATS_MODE_READ); - m_flexCounterGroupTable->set(PG_DROP_STAT_COUNTER_FLEX_COUNTER_GROUP, fieldValues); + portRateSha = swss::loadRedisScript(m_counter_db.get(), portRateLuaScript); } catch (const runtime_error &e) { SWSS_LOG_ERROR("Port flex counter groups were not set successfully: %s", e.what()); } + setFlexCounterGroupParameter(QUEUE_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, + QUEUE_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS, + STATS_MODE_READ_AND_CLEAR, + QUEUE_PLUGIN_FIELD, + queueWmSha); + + setFlexCounterGroupParameter(PG_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, + PG_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS, + STATS_MODE_READ_AND_CLEAR, + PG_PLUGIN_FIELD, + pgWmSha); + + setFlexCounterGroupParameter(PORT_STAT_COUNTER_FLEX_COUNTER_GROUP, + PORT_RATE_FLEX_COUNTER_POLLING_INTERVAL_MS, + STATS_MODE_READ, + PORT_PLUGIN_FIELD, + portRateSha); + + setFlexCounterGroupParameter(PG_DROP_STAT_COUNTER_FLEX_COUNTER_GROUP, + PG_DROP_FLEX_STAT_COUNTER_POLL_MSECS, + STATS_MODE_READ); + /* Get CPU port */ this->initializeCpuPort(); @@ -3172,6 +3164,10 @@ sai_status_t PortsOrch::removePort(sai_object_id_t port_id) } /* else : port is in default state or not yet created */ + /* Remove port counters */ + port_stat_manager.clearCounterIdList(port.m_port_id); + port_buffer_drop_stat_manager.clearCounterIdList(port.m_port_id); + /* * Remove port serdes (if exists) before removing port since this * reference is dependency. @@ -3269,10 +3265,10 @@ bool PortsOrch::initPort(const PortConfig &port) auto gbport_counter_stats = generateCounterStats(PORT_STAT_COUNTER_FLEX_COUNTER_GROUP, true); if (p.m_system_side_id) gb_port_stat_manager.setCounterIdList(p.m_system_side_id, - CounterType::PORT, gbport_counter_stats); + CounterType::PORT, gbport_counter_stats, p.m_switch_id); if (p.m_line_side_id) gb_port_stat_manager.setCounterIdList(p.m_line_side_id, - CounterType::PORT, gbport_counter_stats); + CounterType::PORT, gbport_counter_stats, p.m_switch_id); } if (flex_counters_orch->getPortBufferDropCountersState()) { @@ -7091,11 +7087,9 @@ void PortsOrch::addQueueWatermarkFlexCountersPerPortPerQueueIndex(const Port& po counters_stream << delimiter << sai_serialize_queue_stat(it); delimiter = comma; } + auto &&counters_str = counters_stream.str(); - vector fieldValues; - fieldValues.emplace_back(QUEUE_COUNTER_ID_LIST, counters_stream.str()); - - m_flexCounterTable->set(key, fieldValues); + startFlexCounterPolling(gSwitchId, key, counters_str, QUEUE_COUNTER_ID_LIST); } void PortsOrch::createPortBufferQueueCounters(const Port &port, string queues) @@ -7198,7 +7192,7 @@ void PortsOrch::removePortBufferQueueCounters(const Port &port, string queues) { // Remove watermark queue counters string key = getQueueWatermarkFlexCounterTableKey(id); - m_flexCounterTable->del(key); + stopFlexCounterPolling(gSwitchId, key); } } @@ -7385,9 +7379,8 @@ void PortsOrch::addPriorityGroupFlexCountersPerPortPerPgIndex(const Port& port, delimiter = comma; } } - vector fieldValues; - fieldValues.emplace_back(PG_COUNTER_ID_LIST, ingress_pg_drop_packets_counters_stream.str()); - m_flexCounterTable->set(key, fieldValues); + auto &&counters_str = ingress_pg_drop_packets_counters_stream.str(); + startFlexCounterPolling(gSwitchId, key, counters_str, PG_COUNTER_ID_LIST); } void PortsOrch::addPriorityGroupWatermarkFlexCounters(map pgsStateVector) @@ -7455,9 +7448,9 @@ void PortsOrch::addPriorityGroupWatermarkFlexCountersPerPortPerPgIndex(const Por delimiter = comma; } - vector fieldValues; - fieldValues.emplace_back(PG_COUNTER_ID_LIST, counters_stream.str()); - m_flexCounterTable->set(key, fieldValues); + auto &&counters_str = counters_stream.str(); + + startFlexCounterPolling(gSwitchId, key, counters_str, PG_COUNTER_ID_LIST); } void PortsOrch::removePortBufferPgCounters(const Port& port, string pgs) @@ -7490,14 +7483,14 @@ void PortsOrch::removePortBufferPgCounters(const Port& port, string pgs) { // Remove dropped packets counters from flex_counter string key = getPriorityGroupDropPacketsFlexCounterTableKey(id); - m_flexCounterTable->del(key); + stopFlexCounterPolling(gSwitchId, key); } if (flexCounterOrch->getPgWatermarkCountersState()) { // Remove watermark counters from flex_counter string key = getPriorityGroupWatermarkFlexCounterTableKey(id); - m_flexCounterTable->del(key); + stopFlexCounterPolling(gSwitchId, key); } } @@ -7524,10 +7517,10 @@ void PortsOrch::generatePortCounterMap() CounterType::PORT, port_counter_stats); if (it.second.m_system_side_id) gb_port_stat_manager.setCounterIdList(it.second.m_system_side_id, - CounterType::PORT, gbport_counter_stats); + CounterType::PORT, gbport_counter_stats, it.second.m_switch_id); if (it.second.m_line_side_id) gb_port_stat_manager.setCounterIdList(it.second.m_line_side_id, - CounterType::PORT, gbport_counter_stats); + CounterType::PORT, gbport_counter_stats, it.second.m_switch_id); } m_isPortCounterMapGenerated = true; diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index d19c4b02a9..b79c23530c 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -31,6 +31,10 @@ #define QUEUE_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP "QUEUE_WATERMARK_STAT_COUNTER" #define PG_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP "PG_WATERMARK_STAT_COUNTER" #define PG_DROP_STAT_COUNTER_FLEX_COUNTER_GROUP "PG_DROP_STAT_COUNTER" +#define QUEUE_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS "60000" +#define PG_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS "60000" +#define PG_DROP_FLEX_STAT_COUNTER_POLL_MSECS "10000" +#define PORT_RATE_FLEX_COUNTER_POLLING_INTERVAL_MS "1000" typedef std::vector PortSupportedSpeeds; typedef std::set PortSupportedFecModes; @@ -255,8 +259,6 @@ class PortsOrch : public Orch, public Subject unique_ptr
m_pgPortTable; unique_ptr
m_pgIndexTable; unique_ptr
m_stateBufferMaximumValueTable; - unique_ptr m_flexCounterTable; - unique_ptr m_flexCounterGroupTable; Table m_portStateTable; std::string getQueueWatermarkFlexCounterTableKey(std::string s); @@ -265,7 +267,6 @@ class PortsOrch : public Orch, public Subject std::string getPortRateFlexCounterTableKey(std::string s); shared_ptr m_counter_db; - shared_ptr m_flex_db; shared_ptr m_state_db; shared_ptr m_notificationsDb; diff --git a/orchagent/saihelper.cpp b/orchagent/saihelper.cpp index d731b7b8ac..d8d35bd62b 100644 --- a/orchagent/saihelper.cpp +++ b/orchagent/saihelper.cpp @@ -3,6 +3,7 @@ extern "C" { #include "sai.h" #include "saistatus.h" #include "saiextensions.h" +#include "sairedis.h" } #include @@ -85,6 +86,16 @@ sai_dash_direction_lookup_api_t* sai_dash_direction_lookup_api; sai_twamp_api_t* sai_twamp_api; extern sai_object_id_t gSwitchId; +extern bool gTraditionalFlexCounter; + +vector gGearboxOids; + +unique_ptr gFlexCounterDb; +unique_ptr gFlexCounterGroupTable; +unique_ptr gFlexCounterTable; +unique_ptr gGearBoxFlexCounterDb; +unique_ptr gGearBoxFlexCounterGroupTable; +unique_ptr gGearBoxFlexCounterTable; static map hardware_access_map = { @@ -261,6 +272,20 @@ void initSaiApi() sai_log_set(SAI_API_TWAMP, SAI_LOG_LEVEL_NOTICE); } +void initFlexCounterTables() +{ + if (gTraditionalFlexCounter) + { + gFlexCounterDb = std::make_unique("FLEX_COUNTER_DB", 0); + gFlexCounterTable = std::make_unique(gFlexCounterDb.get(), FLEX_COUNTER_TABLE); + gFlexCounterGroupTable = std::make_unique(gFlexCounterDb.get(), FLEX_COUNTER_GROUP_TABLE); + + gGearBoxFlexCounterDb = std::make_unique("GB_FLEX_COUNTER_DB", 0); + gGearBoxFlexCounterTable = std::make_unique(gGearBoxFlexCounterDb.get(), FLEX_COUNTER_TABLE); + gGearBoxFlexCounterGroupTable = std::make_unique(gGearBoxFlexCounterDb.get(), FLEX_COUNTER_GROUP_TABLE); + } +} + void initSaiRedis() { /** @@ -480,6 +505,9 @@ sai_status_t initSaiPhyApi(swss::gearbox_phy_t *phy) phy->firmware_major_version = string(attr.value.chardata); } } + + gGearboxOids.push_back(phyOid); + return status; } @@ -803,3 +831,269 @@ void handleSaiFailure(bool abort_on_failure) abort(); } } + + +static inline void initSaiRedisCounterEmptyParameter(sai_s8_list_t &sai_s8_list) +{ + sai_s8_list.list = nullptr; + sai_s8_list.count = 0; +} + +static inline void initSaiRedisCounterEmptyParameter(sai_redis_flex_counter_group_parameter_t &flex_counter_group_param) +{ + initSaiRedisCounterEmptyParameter(flex_counter_group_param.poll_interval); + initSaiRedisCounterEmptyParameter(flex_counter_group_param.operation); + initSaiRedisCounterEmptyParameter(flex_counter_group_param.stats_mode); + initSaiRedisCounterEmptyParameter(flex_counter_group_param.plugin_name); + initSaiRedisCounterEmptyParameter(flex_counter_group_param.plugins); +} + +static inline void initSaiRedisCounterParameterFromString(sai_s8_list_t &sai_s8_list, const std::string &str) +{ + if (str.length() > 0) + { + sai_s8_list.list = (int8_t*)const_cast(str.c_str()); + sai_s8_list.count = (uint32_t)str.length(); + } + else + { + initSaiRedisCounterEmptyParameter(sai_s8_list); + } +} + +static inline void notifySyncdCounterOperation(bool is_gearbox, const sai_attribute_t &attr) +{ + if (sai_switch_api == nullptr) + { + // This can happen during destruction of the orchagent daemon. + SWSS_LOG_ERROR("sai_switch_api is NULL"); + return; + } + + if (!is_gearbox) + { + sai_switch_api->set_switch_attribute(gSwitchId, &attr); + } + else + { + for (auto gearbox_oid : gGearboxOids) + { + sai_switch_api->set_switch_attribute(gearbox_oid, &attr); + } + } +} + +static inline void operateFlexCounterDbSingleField(std::vector &fvTuples, + const string &field, const string &value) +{ + if (!field.empty() && !value.empty()) + { + fvTuples.emplace_back(field, value); + } +} + +static inline void operateFlexCounterGroupDatabase(const string &group, + const string &poll_interval, + const string &stats_mode, + const string &plugin_name, + const string &plugins, + const string &operation, + bool is_gearbox) +{ + std::vector fvTuples; + auto &flexCounterGroupTable = is_gearbox ? gGearBoxFlexCounterGroupTable : gFlexCounterGroupTable; + + operateFlexCounterDbSingleField(fvTuples, POLL_INTERVAL_FIELD, poll_interval); + operateFlexCounterDbSingleField(fvTuples, STATS_MODE_FIELD, stats_mode); + operateFlexCounterDbSingleField(fvTuples, plugin_name, plugins); + operateFlexCounterDbSingleField(fvTuples, FLEX_COUNTER_STATUS_FIELD, operation); + + flexCounterGroupTable->set(group, fvTuples); +} +void setFlexCounterGroupParameter(const string &group, + const string &poll_interval, + const string &stats_mode, + const string &plugin_name, + const string &plugins, + const string &operation, + bool is_gearbox) +{ + if (gTraditionalFlexCounter) + { + operateFlexCounterGroupDatabase(group, poll_interval, stats_mode, plugin_name, plugins, operation, is_gearbox); + return; + } + + sai_attribute_t attr; + sai_redis_flex_counter_group_parameter_t flex_counter_group_param; + + attr.id = SAI_REDIS_SWITCH_ATTR_FLEX_COUNTER_GROUP; + attr.value.ptr = &flex_counter_group_param; + + initSaiRedisCounterParameterFromString(flex_counter_group_param.counter_group_name, group); + initSaiRedisCounterParameterFromString(flex_counter_group_param.poll_interval, poll_interval); + initSaiRedisCounterParameterFromString(flex_counter_group_param.operation, operation); + initSaiRedisCounterParameterFromString(flex_counter_group_param.stats_mode, stats_mode); + initSaiRedisCounterParameterFromString(flex_counter_group_param.plugin_name, plugin_name); + initSaiRedisCounterParameterFromString(flex_counter_group_param.plugins, plugins); + + notifySyncdCounterOperation(is_gearbox, attr); +} + +void setFlexCounterGroupOperation(const string &group, + const string &operation, + bool is_gearbox) +{ + if (gTraditionalFlexCounter) + { + operateFlexCounterGroupDatabase(group, "", "", "", "", operation, is_gearbox); + return; + } + + sai_attribute_t attr; + sai_redis_flex_counter_group_parameter_t flex_counter_group_param; + + attr.id = SAI_REDIS_SWITCH_ATTR_FLEX_COUNTER_GROUP; + attr.value.ptr = &flex_counter_group_param; + + initSaiRedisCounterEmptyParameter(flex_counter_group_param); + initSaiRedisCounterParameterFromString(flex_counter_group_param.counter_group_name, group); + initSaiRedisCounterParameterFromString(flex_counter_group_param.operation, operation); + + notifySyncdCounterOperation(is_gearbox, attr); +} + +void setFlexCounterGroupPollInterval(const string &group, + const string &poll_interval, + bool is_gearbox) +{ + if (gTraditionalFlexCounter) + { + operateFlexCounterGroupDatabase(group, poll_interval, "", "", "", "", is_gearbox); + return; + } + + sai_attribute_t attr; + sai_redis_flex_counter_group_parameter_t flex_counter_group_param; + + attr.id = SAI_REDIS_SWITCH_ATTR_FLEX_COUNTER_GROUP; + attr.value.ptr = &flex_counter_group_param; + + initSaiRedisCounterEmptyParameter(flex_counter_group_param); + initSaiRedisCounterParameterFromString(flex_counter_group_param.counter_group_name, group); + initSaiRedisCounterParameterFromString(flex_counter_group_param.poll_interval, poll_interval); + + notifySyncdCounterOperation(is_gearbox, attr); +} + +void setFlexCounterGroupStatsMode(const std::string &group, + const std::string &stats_mode, + bool is_gearbox) +{ + if (gTraditionalFlexCounter) + { + operateFlexCounterGroupDatabase(group, "", stats_mode, "", "", "", is_gearbox); + return; + } + + sai_attribute_t attr; + sai_redis_flex_counter_group_parameter_t flex_counter_group_param; + + attr.id = SAI_REDIS_SWITCH_ATTR_FLEX_COUNTER_GROUP; + attr.value.ptr = &flex_counter_group_param; + + initSaiRedisCounterEmptyParameter(flex_counter_group_param); + initSaiRedisCounterParameterFromString(flex_counter_group_param.counter_group_name, group); + initSaiRedisCounterParameterFromString(flex_counter_group_param.stats_mode, stats_mode); + + notifySyncdCounterOperation(is_gearbox, attr); +} + +void delFlexCounterGroup(const std::string &group, + bool is_gearbox) +{ + if (gTraditionalFlexCounter) + { + auto &flexCounterGroupTable = is_gearbox ? gGearBoxFlexCounterGroupTable : gFlexCounterGroupTable; + + if (flexCounterGroupTable != nullptr) + { + flexCounterGroupTable->del(group); + } + + return; + } + + sai_attribute_t attr; + sai_redis_flex_counter_group_parameter_t flex_counter_group_param; + + attr.id = SAI_REDIS_SWITCH_ATTR_FLEX_COUNTER_GROUP; + attr.value.ptr = &flex_counter_group_param; + + initSaiRedisCounterEmptyParameter(flex_counter_group_param); + initSaiRedisCounterParameterFromString(flex_counter_group_param.counter_group_name, group); + + notifySyncdCounterOperation(is_gearbox, attr); +} + +void startFlexCounterPolling(sai_object_id_t switch_oid, + const std::string &key, + const std::string &counter_ids, + const std::string &counter_field_name, + const std::string &stats_mode) +{ + if (gTraditionalFlexCounter) + { + std::vector fvTuples; + auto &flexCounterTable = switch_oid == gSwitchId ? gFlexCounterTable : gGearBoxFlexCounterTable; + + operateFlexCounterDbSingleField(fvTuples, counter_field_name, counter_ids); + operateFlexCounterDbSingleField(fvTuples, STATS_MODE_FIELD, stats_mode); + + flexCounterTable->set(key, fvTuples); + + return; + } + + sai_attribute_t attr; + sai_redis_flex_counter_parameter_t flex_counter_param; + + attr.id = SAI_REDIS_SWITCH_ATTR_FLEX_COUNTER; + attr.value.ptr = &flex_counter_param; + + initSaiRedisCounterParameterFromString(flex_counter_param.counter_key, key); + initSaiRedisCounterParameterFromString(flex_counter_param.counter_ids, counter_ids); + initSaiRedisCounterParameterFromString(flex_counter_param.counter_field_name, counter_field_name); + initSaiRedisCounterParameterFromString(flex_counter_param.stats_mode, stats_mode); + + sai_switch_api->set_switch_attribute(switch_oid, &attr); +} + +void stopFlexCounterPolling(sai_object_id_t switch_oid, + const std::string &key) +{ + if (gTraditionalFlexCounter) + { + auto &flexCounterTable = switch_oid == gSwitchId ? gFlexCounterTable : gGearBoxFlexCounterTable; + + if (flexCounterTable != nullptr) + { + flexCounterTable->del(key); + } + + return; + } + + sai_attribute_t attr; + sai_redis_flex_counter_parameter_t flex_counter_param; + + attr.id = SAI_REDIS_SWITCH_ATTR_FLEX_COUNTER; + attr.value.ptr = &flex_counter_param; + + initSaiRedisCounterParameterFromString(flex_counter_param.counter_key, key); + initSaiRedisCounterEmptyParameter(flex_counter_param.counter_ids); + initSaiRedisCounterEmptyParameter(flex_counter_param.counter_field_name); + initSaiRedisCounterEmptyParameter(flex_counter_param.stats_mode); + + sai_switch_api->set_switch_attribute(switch_oid, &attr); +} diff --git a/orchagent/saihelper.h b/orchagent/saihelper.h index b83f894c2e..693fffd742 100644 --- a/orchagent/saihelper.h +++ b/orchagent/saihelper.h @@ -4,10 +4,12 @@ #include #include "orch.h" +#include "producertable.h" #define IS_ATTR_ID_IN_RANGE(attrId, objectType, attrPrefix) \ ((attrId) >= SAI_ ## objectType ## _ATTR_ ## attrPrefix ## _START && (attrId) <= SAI_ ## objectType ## _ATTR_ ## attrPrefix ## _END) +void initFlexCounterTables(); void initSaiApi(); void initSaiRedis(); sai_status_t initSaiPhyApi(swss::gearbox_phy_t *phy); @@ -19,3 +21,31 @@ task_process_status handleSaiRemoveStatus(sai_api_t api, sai_status_t status, vo task_process_status handleSaiGetStatus(sai_api_t api, sai_status_t status, void *context = nullptr); bool parseHandleSaiStatusFailure(task_process_status status); void handleSaiFailure(bool abort_on_failure); + +void setFlexCounterGroupParameter(const std::string &group, + const std::string &poll_interval, + const std::string &stats_mode, + const std::string &plugin_name="", + const std::string &plugins="", + const std::string &operation="", + bool is_gearbox=false); +void setFlexCounterGroupPollInterval(const std::string &group, + const std::string &poll_interval, + bool is_gearbox=false); +void setFlexCounterGroupOperation(const std::string &group, + const std::string &operation, + bool is_gearbox=false); +void setFlexCounterGroupStatsMode(const std::string &group, + const std::string &stats_mode, + bool is_gearbox=false); + +void delFlexCounterGroup(const std::string &group, + bool is_gearbox=false); + +void startFlexCounterPolling(sai_object_id_t switch_oid, + const std::string &key, + const std::string &counter_ids, + const std::string &counter_field_name, + const std::string &stats_mode=""); +void stopFlexCounterPolling(sai_object_id_t switch_oid, + const std::string &key); diff --git a/orchagent/vxlanorch.cpp b/orchagent/vxlanorch.cpp index 1983cf7286..05a2d3e603 100644 --- a/orchagent/vxlanorch.cpp +++ b/orchagent/vxlanorch.cpp @@ -30,6 +30,7 @@ extern Directory gDirectory; extern PortsOrch* gPortsOrch; extern sai_object_id_t gUnderlayIfId; extern FlexManagerDirectory g_FlexManagerDirectory; +extern bool gTraditionalFlexCounter; #define FLEX_COUNTER_UPD_INTERVAL 1 @@ -1219,7 +1220,10 @@ VxlanTunnelOrch::VxlanTunnelOrch(DBConnector *statedb, DBConnector *db, const st m_tunnelNameTable = unique_ptr
(new Table(m_counter_db.get(), COUNTERS_TUNNEL_NAME_MAP)); m_tunnelTypeTable = unique_ptr
(new Table(m_counter_db.get(), COUNTERS_TUNNEL_TYPE_MAP)); - m_vidToRidTable = unique_ptr
(new Table(m_asic_db.get(), "VIDTORID")); + if (gTraditionalFlexCounter) + { + m_vidToRidTable = make_unique
(m_asic_db.get(), "VIDTORID"); + } auto intervT = timespec { .tv_sec = FLEX_COUNTER_UPD_INTERVAL , .tv_nsec = 0 }; m_FlexCounterUpdTimer = new SelectableTimer(intervT); @@ -1237,7 +1241,7 @@ void VxlanTunnelOrch::doTask(SelectableTimer &timer) string value; const auto id = sai_serialize_object_id(it->first); - if (m_vidToRidTable->hget("", id, value)) + if (!gTraditionalFlexCounter || m_vidToRidTable->hget("", id, value)) { SWSS_LOG_INFO("Registering %s, id %s", it->second.c_str(), id.c_str()); vector tunnelNameFvs; diff --git a/tests/mock_tests/Makefile.am b/tests/mock_tests/Makefile.am index db410907c5..c3a305b1eb 100644 --- a/tests/mock_tests/Makefile.am +++ b/tests/mock_tests/Makefile.am @@ -61,6 +61,7 @@ tests_SOURCES = aclorch_ut.cpp \ warmrestarthelper_ut.cpp \ neighorch_ut.cpp \ twamporch_ut.cpp \ + flexcounter_ut.cpp \ $(top_srcdir)/warmrestart/warmRestartHelper.cpp \ $(top_srcdir)/lib/gearboxutils.cpp \ $(top_srcdir)/lib/subintf.cpp \ diff --git a/tests/mock_tests/bufferorch_ut.cpp b/tests/mock_tests/bufferorch_ut.cpp index 2cd15ee549..f92d5e1f6d 100644 --- a/tests/mock_tests/bufferorch_ut.cpp +++ b/tests/mock_tests/bufferorch_ut.cpp @@ -378,6 +378,9 @@ namespace bufferorch_test delete gCrmOrch; gCrmOrch = nullptr; + delete gBufferOrch; + gBufferOrch = nullptr; + delete gSwitchOrch; gSwitchOrch = nullptr; diff --git a/tests/mock_tests/flexcounter_ut.cpp b/tests/mock_tests/flexcounter_ut.cpp new file mode 100644 index 0000000000..b99f9cc25d --- /dev/null +++ b/tests/mock_tests/flexcounter_ut.cpp @@ -0,0 +1,845 @@ +#define private public // make Directory::m_values available to clean it. +#include "directory.h" +#undef private + +#include "json.h" +#include "ut_helper.h" +#include "mock_orchagent_main.h" +#include "mock_table.h" +#include "notifier.h" +#define private public +#include "pfcactionhandler.h" +#include "switchorch.h" +#include +#undef private +#define private public +#include "warm_restart.h" +#undef private + +#include + +extern bool gTraditionalFlexCounter; + +namespace flexcounter_test +{ + using namespace std; + + // SAI default ports + std::map> defaultPortList; + + shared_ptr mockFlexCounterDb; + shared_ptr mockFlexCounterGroupTable; + shared_ptr mockFlexCounterTable; + sai_set_switch_attribute_fn mockOldSaiSetSwitchAttribute; + + void mock_counter_init(sai_set_switch_attribute_fn old) + { + mockFlexCounterDb = make_shared("FLEX_COUNTER_DB", 0); + mockFlexCounterGroupTable = make_shared(mockFlexCounterDb.get(), "FLEX_COUNTER_GROUP_TABLE"); + mockFlexCounterTable = make_shared(mockFlexCounterDb.get(), "FLEX_COUNTER_TABLE"); + + mockOldSaiSetSwitchAttribute = old; + } + + sai_status_t mockFlexCounterOperation(sai_object_id_t objectId, const sai_attribute_t *attr) + { + if (objectId != gSwitchId) + { + return SAI_STATUS_FAILURE; + } + + auto *param = reinterpret_cast(attr->value.ptr); + std::vector entries; + auto serializedObjectId = sai_serialize_object_id(objectId); + std::string key((const char*)param->counter_key.list); + + if (param->stats_mode.list != nullptr) + { + entries.push_back({STATS_MODE_FIELD, (const char*)param->stats_mode.list}); + } + + if (param->counter_ids.list != nullptr) + { + entries.push_back({(const char*)param->counter_field_name.list, (const char*)param->counter_ids.list}); + mockFlexCounterTable->set(key, entries); + } + else + { + mockFlexCounterTable->del(key); + } + + return SAI_STATUS_SUCCESS; + } + + sai_status_t mockFlexCounterGroupOperation(sai_object_id_t objectId, const sai_attribute_t *attr) + { + if (objectId != gSwitchId) + { + return SAI_STATUS_FAILURE; + } + + std::vector entries; + sai_redis_flex_counter_group_parameter_t *flexCounterGroupParam = reinterpret_cast(attr->value.ptr); + + std::string key((const char*)flexCounterGroupParam->counter_group_name.list); + + if (flexCounterGroupParam->poll_interval.list != nullptr) + { + entries.push_back({POLL_INTERVAL_FIELD, (const char*)flexCounterGroupParam->poll_interval.list}); + } + + if (flexCounterGroupParam->stats_mode.list != nullptr) + { + entries.push_back({STATS_MODE_FIELD, (const char*)flexCounterGroupParam->stats_mode.list}); + } + + if (flexCounterGroupParam->plugin_name.list != nullptr) + { + entries.push_back({(const char*)flexCounterGroupParam->plugin_name.list, ""}); + } + + if (flexCounterGroupParam->operation.list != nullptr) + { + entries.push_back({FLEX_COUNTER_STATUS_FIELD, (const char*)flexCounterGroupParam->operation.list}); + } + + if (entries.size() > 0) + { + mockFlexCounterGroupTable->set(key, entries); + } + else + { + mockFlexCounterGroupTable->del(key); + } + + return SAI_STATUS_SUCCESS; + } + + bool _checkFlexCounterTableContent(std::shared_ptr table, const std::string key, std::vector entries) + { + vector fieldValues; + + if (table->get(key, fieldValues)) + { + set fvSet(fieldValues.begin(), fieldValues.end()); + set expectedSet(entries.begin(), entries.end()); + + bool result = (fvSet == expectedSet); + if (!result && gTraditionalFlexCounter && !entries.empty()) + { + // We can not mock plugin when counter model is traditional and plugin is empty string. + // As a result, the plugin field will not be inserted into the database. + // We add it into the entries fetched from database manually and redo comparing + // The plugin field must be the last one in entries vector + fvSet.insert(entries.back()); + result = (fvSet == expectedSet); + } + + return result; + } + + return entries.empty(); + } + + bool checkFlexCounterGroup(const std::string group, std::vector entries) + { + return _checkFlexCounterTableContent(mockFlexCounterGroupTable, group, entries); + } + + bool checkFlexCounter(const std::string group, sai_object_id_t oid, const std::string counter_field_name="", const std::string mode="") + { + std::vector entries; + + if (!mockFlexCounterTable->get(group + ":" + sai_serialize_object_id(oid), entries)) + { + return counter_field_name.empty(); + } + + if (fvField(entries[0]) == counter_field_name) + { + if (mode == "") + { + // only 1 item: counter IDs + return true; + } + else + { + // 1st item: counter ID, 2nd item: mode + return (fvField(entries[1]) == "mode") && (fvValue(entries[1]) == mode); + } + } + else if (mode != "") + { + // 1st item: mode, 2nd item: counter ID + return (fvField(entries[0]) == "mode") && (fvValue(entries[0]) == mode) && (fvField(entries[1]) == counter_field_name); + } + + return false; + } + + bool checkFlexCounter(const std::string group, sai_object_id_t oid, std::vector entries) + { + return _checkFlexCounterTableContent(mockFlexCounterTable, group + ":" + sai_serialize_object_id(oid), entries); + } + + sai_switch_api_t ut_sai_switch_api; + sai_switch_api_t *pold_sai_switch_api; + + sai_status_t _ut_stub_sai_set_switch_attribute( + _In_ sai_object_id_t switch_id, + _In_ const sai_attribute_t *attr) + { + if (attr[0].id == SAI_REDIS_SWITCH_ATTR_FLEX_COUNTER_GROUP) + { + mockFlexCounterGroupOperation(switch_id, attr); + } + else if (attr[0].id == SAI_REDIS_SWITCH_ATTR_FLEX_COUNTER) + { + mockFlexCounterOperation(switch_id, attr); + } + return pold_sai_switch_api->set_switch_attribute(switch_id, attr); + } + + void _hook_sai_switch_api() + { + ut_sai_switch_api = *sai_switch_api; + pold_sai_switch_api = sai_switch_api; + ut_sai_switch_api.set_switch_attribute = _ut_stub_sai_set_switch_attribute; + sai_switch_api = &ut_sai_switch_api; + mock_counter_init(nullptr); + } + + void _unhook_sai_switch_api() + { + sai_switch_api = pold_sai_switch_api; + } + + struct FlexCounterTest : public ::testing::TestWithParam> + { + shared_ptr m_app_db; + shared_ptr m_config_db; + shared_ptr m_state_db; + shared_ptr m_counters_db; + shared_ptr m_chassis_app_db; + shared_ptr m_asic_db; + shared_ptr m_flex_counter_db; + bool create_only_config_db_buffers; + + FlexCounterTest() + { + // FIXME: move out from constructor + m_app_db = make_shared( + "APPL_DB", 0); + m_counters_db = make_shared( + "COUNTERS_DB", 0); + m_config_db = make_shared( + "CONFIG_DB", 0); + m_state_db = make_shared( + "STATE_DB", 0); + m_chassis_app_db = make_shared( + "CHASSIS_APP_DB", 0); + m_asic_db = make_shared( + "ASIC_DB", 0); + m_flex_counter_db = make_shared( + "FLEX_COUNTER_DB", 0); + } + + virtual void SetUp() override + { + ::testing_db::reset(); + + gTraditionalFlexCounter = get<0>(GetParam()); + create_only_config_db_buffers = get<1>(GetParam()); + if (gTraditionalFlexCounter) + { + initFlexCounterTables(); + } + + _hook_sai_switch_api(); + + // Create dependencies ... + TableConnector stateDbSwitchTable(m_state_db.get(), "SWITCH_CAPABILITY"); + TableConnector app_switch_table(m_app_db.get(), APP_SWITCH_TABLE_NAME); + TableConnector conf_asic_sensors(m_config_db.get(), CFG_ASIC_SENSORS_TABLE_NAME); + + if (create_only_config_db_buffers) + { + Table deviceMetadata(m_config_db.get(), CFG_DEVICE_METADATA_TABLE_NAME); + deviceMetadata.set("localhost", { { "create_only_config_db_buffers", "true" } }); + } + + vector switch_tables = { + conf_asic_sensors, + app_switch_table + }; + + ASSERT_EQ(gSwitchOrch, nullptr); + gSwitchOrch = new SwitchOrch(m_app_db.get(), switch_tables, stateDbSwitchTable); + + const int portsorch_base_pri = 40; + + vector ports_tables = { + { APP_PORT_TABLE_NAME, portsorch_base_pri + 5 }, + { APP_SEND_TO_INGRESS_PORT_TABLE_NAME, portsorch_base_pri + 5 }, + { APP_VLAN_TABLE_NAME, portsorch_base_pri + 2 }, + { APP_VLAN_MEMBER_TABLE_NAME, portsorch_base_pri }, + { APP_LAG_TABLE_NAME, portsorch_base_pri + 4 }, + { APP_LAG_MEMBER_TABLE_NAME, portsorch_base_pri } + }; + + ASSERT_EQ(gPortsOrch, nullptr); + + gPortsOrch = new PortsOrch(m_app_db.get(), m_state_db.get(), ports_tables, m_chassis_app_db.get()); + + vector flex_counter_tables = { + CFG_FLEX_COUNTER_TABLE_NAME + }; + auto* flexCounterOrch = new FlexCounterOrch(m_config_db.get(), flex_counter_tables); + gDirectory.set(flexCounterOrch); + + vector buffer_tables = { APP_BUFFER_POOL_TABLE_NAME, + APP_BUFFER_PROFILE_TABLE_NAME, + APP_BUFFER_QUEUE_TABLE_NAME, + APP_BUFFER_PG_TABLE_NAME, + APP_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME, + APP_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME }; + + ASSERT_EQ(gBufferOrch, nullptr); + gBufferOrch = new BufferOrch(m_app_db.get(), m_config_db.get(), m_state_db.get(), buffer_tables); + + Table portTable = Table(m_app_db.get(), APP_PORT_TABLE_NAME); + + // Get SAI default ports to populate DB + auto ports = ut_helper::getInitialSaiPorts(); + + // Populate pot table with SAI ports + for (const auto &it : ports) + { + portTable.set(it.first, it.second); + } + + // Set PortConfigDone + portTable.set("PortConfigDone", { { "count", to_string(ports.size()) } }); + gPortsOrch->addExistingData(&portTable); + static_cast(gPortsOrch)->doTask(); + + portTable.set("PortInitDone", { { "lanes", "0" } }); + gPortsOrch->addExistingData(&portTable); + static_cast(gPortsOrch)->doTask(); + + ASSERT_EQ(gIntfsOrch, nullptr); + gIntfsOrch = new IntfsOrch(m_app_db.get(), APP_INTF_TABLE_NAME, gVrfOrch, m_chassis_app_db.get()); + } + + virtual void TearDown() override + { + ::testing_db::reset(); + + auto buffer_maps = BufferOrch::m_buffer_type_maps; + for (auto &i : buffer_maps) + { + i.second->clear(); + } + + delete gNeighOrch; + gNeighOrch = nullptr; + delete gFdbOrch; + gFdbOrch = nullptr; + delete gIntfsOrch; + gIntfsOrch = nullptr; + delete gPortsOrch; + gPortsOrch = nullptr; + delete gBufferOrch; + gBufferOrch = nullptr; + delete gQosOrch; + gQosOrch = nullptr; + delete gSwitchOrch; + gSwitchOrch = nullptr; + + // clear orchs saved in directory + gDirectory.m_values.clear(); + + _unhook_sai_switch_api(); + } + + static void SetUpTestCase() + { + // Init switch and create dependencies + + map profile = { + { "SAI_VS_SWITCH_TYPE", "SAI_VS_SWITCH_TYPE_BCM56850" }, + { "KV_DEVICE_MAC_ADDRESS", "20:03:04:05:06:00" } + }; + + auto status = ut_helper::initSaiApi(profile); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + sai_attribute_t attr; + + attr.id = SAI_SWITCH_ATTR_INIT_SWITCH; + attr.value.booldata = true; + + status = sai_switch_api->create_switch(&gSwitchId, 1, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + // Get switch source MAC address + attr.id = SAI_SWITCH_ATTR_SRC_MAC_ADDRESS; + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + gMacAddress = attr.value.mac; + + // Get the default virtual router ID + attr.id = SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID; + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + gVirtualRouterId = attr.value.oid; + + // Get SAI default ports + defaultPortList = ut_helper::getInitialSaiPorts(); + ASSERT_TRUE(!defaultPortList.empty()); + } + + static void TearDownTestCase() + { + auto status = sai_switch_api->remove_switch(gSwitchId); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + gSwitchId = 0; + + ut_helper::uninitSaiApi(); + } + + }; + + TEST_P(FlexCounterTest, CounterTest) + { + // Check flex counter database after system initialization + ASSERT_TRUE(checkFlexCounterGroup(QUEUE_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, + { + {STATS_MODE_FIELD, STATS_MODE_READ_AND_CLEAR}, + {POLL_INTERVAL_FIELD, QUEUE_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS}, + {QUEUE_PLUGIN_FIELD, ""} + })); + ASSERT_TRUE(checkFlexCounterGroup(PG_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, + { + {STATS_MODE_FIELD, STATS_MODE_READ_AND_CLEAR}, + {POLL_INTERVAL_FIELD, PG_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS}, + {PG_PLUGIN_FIELD, ""} + })); + ASSERT_TRUE(checkFlexCounterGroup(PORT_STAT_COUNTER_FLEX_COUNTER_GROUP, + { + {STATS_MODE_FIELD, STATS_MODE_READ}, + {POLL_INTERVAL_FIELD, PORT_RATE_FLEX_COUNTER_POLLING_INTERVAL_MS}, + {FLEX_COUNTER_STATUS_FIELD, "disable"}, + {PORT_PLUGIN_FIELD, ""} + })); + ASSERT_TRUE(checkFlexCounterGroup(PG_DROP_STAT_COUNTER_FLEX_COUNTER_GROUP, + { + {STATS_MODE_FIELD, STATS_MODE_READ}, + {POLL_INTERVAL_FIELD, PG_DROP_FLEX_STAT_COUNTER_POLL_MSECS}, + })); + ASSERT_TRUE(checkFlexCounterGroup(RIF_STAT_COUNTER_FLEX_COUNTER_GROUP, + { + {STATS_MODE_FIELD, STATS_MODE_READ}, + {POLL_INTERVAL_FIELD, "1000"}, + {RIF_PLUGIN_FIELD, ""}, + })); + + Table portTable = Table(m_app_db.get(), APP_PORT_TABLE_NAME); + Table sendToIngressPortTable = Table(m_app_db.get(), APP_SEND_TO_INGRESS_PORT_TABLE_NAME); + Table pgTable = Table(m_app_db.get(), APP_BUFFER_PG_TABLE_NAME); + Table pgTableCfg = Table(m_config_db.get(), CFG_BUFFER_PG_TABLE_NAME); + Table queueTable = Table(m_app_db.get(), APP_BUFFER_QUEUE_TABLE_NAME); + Table queueTableCfg = Table(m_config_db.get(), CFG_BUFFER_QUEUE_TABLE_NAME); + Table profileTable = Table(m_app_db.get(), APP_BUFFER_PROFILE_TABLE_NAME); + Table poolTable = Table(m_app_db.get(), APP_BUFFER_POOL_TABLE_NAME); + Table flexCounterCfg = Table(m_config_db.get(), CFG_FLEX_COUNTER_TABLE_NAME); + + // Get SAI default ports to populate DB + auto ports = ut_helper::getInitialSaiPorts(); + auto firstPortName = ports.begin()->first; + + // Create test buffer pool + poolTable.set( + "ingress_lossless_pool", + { + { "type", "ingress" }, + { "mode", "dynamic" }, + { "size", "4200000" }, + }); + poolTable.set( + "egress_lossless_pool", + { + { "type", "egress" }, + { "mode", "dynamic" }, + { "size", "4200000" }, + }); + + if (create_only_config_db_buffers) + { + // Create test buffer profile + profileTable.set("ingress_lossless_profile", { { "pool", "ingress_lossless_pool" }, + { "xon", "14832" }, + { "xoff", "14832" }, + { "size", "35000" }, + { "dynamic_th", "0" } }); + profileTable.set("egress_lossless_profile", { { "pool", "egress_lossless_pool" }, + { "size", "0" }, + { "dynamic_th", "7" } }); + + // Apply profile on PGs 3-4 all ports + auto appdbKey = firstPortName + ":3-4"; + auto cfgdbKey = firstPortName + "|3-4"; + pgTable.set(appdbKey, { { "profile", "ingress_lossless_profile" } }); + pgTableCfg.set(cfgdbKey, { { "profile", "ingress_lossless_profile" } }); + queueTable.set(appdbKey, { { "profile", "egress_lossless_profile" } }); + queueTableCfg.set(cfgdbKey, { { "profile", "egress_lossless_profile" } }); + } + + // Populate port table with SAI ports + for (const auto &it : ports) + { + portTable.set(it.first, it.second); + } + + // Set PortConfigDone + portTable.set("PortConfigDone", { { "count", to_string(ports.size()) } }); + // Populate send to ingresss port table + sendToIngressPortTable.set("SEND_TO_INGRESS", {{"NULL", "NULL"}}); + + // refill consumer + gPortsOrch->addExistingData(&portTable); + gBufferOrch->addExistingData(&pgTable); + gBufferOrch->addExistingData(&queueTable); + gBufferOrch->addExistingData(&poolTable); + gBufferOrch->addExistingData(&profileTable); + + // Apply configuration : + // create ports + static_cast(gBufferOrch)->doTask(); + static_cast(gPortsOrch)->doTask(); + + portTable.set("PortInitDone", { { "lanes", "0" } }); + gPortsOrch->addExistingData(&portTable); + + // Apply configuration + // configure buffers + // ports + static_cast(gPortsOrch)->doTask(); + + // Since init done is set now, apply buffers + static_cast(gBufferOrch)->doTask(); + + ASSERT_TRUE(gPortsOrch->allPortsReady()); + + // Enable and check counters + const std::vector values({ {FLEX_COUNTER_DELAY_STATUS_FIELD, "false"}, + {FLEX_COUNTER_STATUS_FIELD, "enable"} }); + flexCounterCfg.set("PG_WATERMARK", values); + flexCounterCfg.set("QUEUE_WATERMARK", values); + flexCounterCfg.set("QUEUE", values); + flexCounterCfg.set("PORT_BUFFER_DROP", values); + flexCounterCfg.set("PG_DROP", values); + flexCounterCfg.set("PORT", values); + flexCounterCfg.set("BUFFER_POOL_WATERMARK", values); + flexCounterCfg.set("PFCWD", values); + + auto flexCounterOrch = gDirectory.get(); + flexCounterOrch->addExistingData(&flexCounterCfg); + static_cast(flexCounterOrch)->doTask(); + + ASSERT_TRUE(checkFlexCounterGroup(BUFFER_POOL_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, + { + {POLL_INTERVAL_FIELD, "60000"}, + {STATS_MODE_FIELD, STATS_MODE_READ_AND_CLEAR}, + {FLEX_COUNTER_STATUS_FIELD, "enable"}, + {BUFFER_POOL_PLUGIN_FIELD, ""} + })); + ASSERT_TRUE(checkFlexCounterGroup(QUEUE_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, + { + {POLL_INTERVAL_FIELD, "60000"}, + {STATS_MODE_FIELD, STATS_MODE_READ_AND_CLEAR}, + {FLEX_COUNTER_STATUS_FIELD, "enable"}, + {QUEUE_PLUGIN_FIELD, ""} + })); + ASSERT_TRUE(checkFlexCounterGroup(PG_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, + { + {POLL_INTERVAL_FIELD, "60000"}, + {STATS_MODE_FIELD, STATS_MODE_READ_AND_CLEAR}, + {FLEX_COUNTER_STATUS_FIELD, "enable"}, + {PG_PLUGIN_FIELD, ""} + })); + ASSERT_TRUE(checkFlexCounterGroup(PORT_BUFFER_DROP_STAT_FLEX_COUNTER_GROUP, + { + {POLL_INTERVAL_FIELD, "60000"}, + {STATS_MODE_FIELD, STATS_MODE_READ}, + {FLEX_COUNTER_STATUS_FIELD, "enable"} + })); + ASSERT_TRUE(checkFlexCounterGroup(PG_DROP_STAT_COUNTER_FLEX_COUNTER_GROUP, + { + {POLL_INTERVAL_FIELD, "10000"}, + {STATS_MODE_FIELD, STATS_MODE_READ}, + {FLEX_COUNTER_STATUS_FIELD, "enable"} + })); + ASSERT_TRUE(checkFlexCounterGroup(PORT_STAT_COUNTER_FLEX_COUNTER_GROUP, + { + {POLL_INTERVAL_FIELD, "1000"}, + {STATS_MODE_FIELD, STATS_MODE_READ}, + {FLEX_COUNTER_STATUS_FIELD, "enable"}, + {PORT_PLUGIN_FIELD, ""} + })); + ASSERT_TRUE(checkFlexCounterGroup(QUEUE_STAT_COUNTER_FLEX_COUNTER_GROUP, + { + {POLL_INTERVAL_FIELD, "10000"}, + {STATS_MODE_FIELD, STATS_MODE_READ}, + {FLEX_COUNTER_STATUS_FIELD, "enable"}, + })); + + sai_object_id_t pool_oid; + pool_oid = (*BufferOrch::m_buffer_type_maps[APP_BUFFER_POOL_TABLE_NAME])["ingress_lossless_pool"].m_saiObjectId; + ASSERT_TRUE(checkFlexCounter(BUFFER_POOL_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, pool_oid, BUFFER_POOL_COUNTER_ID_LIST)); + Port firstPort; + gPortsOrch->getPort(firstPortName, firstPort); + auto pgOid = firstPort.m_priority_group_ids[3]; + ASSERT_TRUE(checkFlexCounter(PG_DROP_STAT_COUNTER_FLEX_COUNTER_GROUP, pgOid, + { + {PG_COUNTER_ID_LIST, + "SAI_INGRESS_PRIORITY_GROUP_STAT_DROPPED_PACKETS" + } + })); + ASSERT_TRUE(checkFlexCounter(PG_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, pgOid, + { + {PG_COUNTER_ID_LIST, + "SAI_INGRESS_PRIORITY_GROUP_STAT_XOFF_ROOM_WATERMARK_BYTES," + "SAI_INGRESS_PRIORITY_GROUP_STAT_SHARED_WATERMARK_BYTES" + } + })); + auto queueOid = firstPort.m_queue_ids[3]; + ASSERT_TRUE(checkFlexCounter(QUEUE_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, queueOid, + { + {QUEUE_COUNTER_ID_LIST, + "SAI_QUEUE_STAT_SHARED_WATERMARK_BYTES" + } + })); + ASSERT_TRUE(checkFlexCounter(QUEUE_STAT_COUNTER_FLEX_COUNTER_GROUP, queueOid, + { + {QUEUE_COUNTER_ID_LIST, + "SAI_QUEUE_STAT_DROPPED_BYTES,SAI_QUEUE_STAT_DROPPED_PACKETS," + "SAI_QUEUE_STAT_BYTES,SAI_QUEUE_STAT_PACKETS" + } + })); + auto oid = firstPort.m_port_id; + ASSERT_TRUE(checkFlexCounter(PORT_BUFFER_DROP_STAT_FLEX_COUNTER_GROUP, oid, + { + {PORT_COUNTER_ID_LIST, + "SAI_PORT_STAT_OUT_DROPPED_PKTS,SAI_PORT_STAT_IN_DROPPED_PKTS" + } + })); + // Do not check the content of port counter since it's large and varies among platforms. + ASSERT_TRUE(checkFlexCounter(PORT_STAT_COUNTER_FLEX_COUNTER_GROUP, oid, PORT_COUNTER_ID_LIST)); + + // create a routing interface + std::deque entries; + entries.push_back({firstPort.m_alias, "SET", { {"mtu", "9100"}}}); + auto consumer = dynamic_cast(gIntfsOrch->getExecutor(APP_INTF_TABLE_NAME)); + consumer->addToSync(entries); + static_cast(gIntfsOrch)->doTask(); + + // Check flex counter database + auto rifOid = gIntfsOrch->m_rifsToAdd[0].m_rif_id; + Table vid2rid = Table(m_asic_db.get(), "VIDTORID"); + if (gTraditionalFlexCounter) + { + const auto id = sai_serialize_object_id(rifOid); + vid2rid.set("", { {id, ""} }); + } + (gIntfsOrch)->doTask(*gIntfsOrch->m_updateMapsTimer); + ASSERT_TRUE(checkFlexCounter(RIF_STAT_COUNTER_FLEX_COUNTER_GROUP, rifOid, + { + {RIF_COUNTER_ID_LIST, + "SAI_ROUTER_INTERFACE_STAT_IN_PACKETS,SAI_ROUTER_INTERFACE_STAT_IN_OCTETS," + "SAI_ROUTER_INTERFACE_STAT_IN_ERROR_PACKETS,SAI_ROUTER_INTERFACE_STAT_IN_ERROR_OCTETS," + "SAI_ROUTER_INTERFACE_STAT_OUT_PACKETS,SAI_ROUTER_INTERFACE_STAT_OUT_OCTETS," + "SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS,SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_OCTETS," + } + })); + + // remove the dependency, expect delete and create a new one + entries.clear(); + entries.push_back({firstPort.m_alias, "DEL", { {} }}); + consumer->addToSync(entries); + static_cast(gIntfsOrch)->doTask(); + + // Check flex counter database + ASSERT_TRUE(checkFlexCounter(RIF_STAT_COUNTER_FLEX_COUNTER_GROUP, rifOid)); + + // PFC watchdog counter test + vector pfc_wd_tables = { + CFG_PFC_WD_TABLE_NAME + }; + + static const vector portStatIds = + { + SAI_PORT_STAT_PFC_0_RX_PAUSE_DURATION_US, + SAI_PORT_STAT_PFC_1_RX_PAUSE_DURATION_US, + SAI_PORT_STAT_PFC_2_RX_PAUSE_DURATION_US, + SAI_PORT_STAT_PFC_3_RX_PAUSE_DURATION_US, + SAI_PORT_STAT_PFC_4_RX_PAUSE_DURATION_US, + SAI_PORT_STAT_PFC_5_RX_PAUSE_DURATION_US, + SAI_PORT_STAT_PFC_6_RX_PAUSE_DURATION_US, + SAI_PORT_STAT_PFC_7_RX_PAUSE_DURATION_US, + SAI_PORT_STAT_PFC_0_RX_PKTS, + SAI_PORT_STAT_PFC_1_RX_PKTS, + SAI_PORT_STAT_PFC_2_RX_PKTS, + SAI_PORT_STAT_PFC_3_RX_PKTS, + SAI_PORT_STAT_PFC_4_RX_PKTS, + SAI_PORT_STAT_PFC_5_RX_PKTS, + SAI_PORT_STAT_PFC_6_RX_PKTS, + SAI_PORT_STAT_PFC_7_RX_PKTS, + }; + + static const vector queueStatIds = + { + SAI_QUEUE_STAT_PACKETS, + SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES, + }; + + static const vector queueAttrIds = + { + SAI_QUEUE_ATTR_PAUSE_STATUS, + }; + + gPfcwdOrch = new PfcWdSwOrch( + m_config_db.get(), + pfc_wd_tables, + portStatIds, + queueStatIds, + queueAttrIds, + 100); + gPfcwdOrch->m_platform = MLNX_PLATFORM_SUBSTRING; + + vector qos_tables = { + CFG_TC_TO_QUEUE_MAP_TABLE_NAME, + CFG_SCHEDULER_TABLE_NAME, + CFG_DSCP_TO_TC_MAP_TABLE_NAME, + CFG_MPLS_TC_TO_TC_MAP_TABLE_NAME, + CFG_DOT1P_TO_TC_MAP_TABLE_NAME, + CFG_QUEUE_TABLE_NAME, + CFG_PORT_QOS_MAP_TABLE_NAME, + CFG_WRED_PROFILE_TABLE_NAME, + CFG_TC_TO_PRIORITY_GROUP_MAP_TABLE_NAME, + CFG_PFC_PRIORITY_TO_PRIORITY_GROUP_MAP_TABLE_NAME, + CFG_PFC_PRIORITY_TO_QUEUE_MAP_TABLE_NAME, + CFG_DSCP_TO_FC_MAP_TABLE_NAME, + CFG_EXP_TO_FC_MAP_TABLE_NAME, + CFG_TC_TO_DSCP_MAP_TABLE_NAME + }; + gQosOrch = new QosOrch(m_config_db.get(), qos_tables); + entries.clear(); + entries.push_back({firstPort.m_alias, "SET", + { + {"pfc_enable", "3,4"}, + {"pfcwd_sw_enable", "3,4"} + }}); + auto portQosMapConsumer = dynamic_cast(gQosOrch->getExecutor(CFG_PORT_QOS_MAP_TABLE_NAME)); + portQosMapConsumer->addToSync(entries); + entries.clear(); + static_cast(gQosOrch)->doTask(); + + // create pfcwd entry for first port with drop action + entries.clear(); + entries.push_back({"GLOBAL", "SET", + { + {POLL_INTERVAL_FIELD, "200"}, + }}); + entries.push_back({firstPort.m_alias, "SET", + { + {"action", "drop"}, + {"detection_time", "200"}, + {"restoration_time", "200"} + }}); + + consumer = dynamic_cast(gPfcwdOrch->getExecutor(CFG_PFC_WD_TABLE_NAME)); + consumer->addToSync(entries); + entries.clear(); + + static_cast(gPfcwdOrch)->doTask(); + + ASSERT_TRUE(checkFlexCounterGroup(PFC_WD_FLEX_COUNTER_GROUP, + { + {POLL_INTERVAL_FIELD, "200"}, + {STATS_MODE_FIELD, STATS_MODE_READ}, + {FLEX_COUNTER_STATUS_FIELD, "enable"}, + {QUEUE_PLUGIN_FIELD, ""} + })); + + ASSERT_TRUE(checkFlexCounter(PFC_WD_FLEX_COUNTER_GROUP, firstPort.m_port_id, + { + {PORT_COUNTER_ID_LIST, "SAI_PORT_STAT_PFC_3_RX_PAUSE_DURATION_US,SAI_PORT_STAT_PFC_4_RX_PAUSE_DURATION_US,SAI_PORT_STAT_PFC_3_RX_PKTS,SAI_PORT_STAT_PFC_4_RX_PKTS"} + })); + + ASSERT_TRUE(checkFlexCounter(PFC_WD_FLEX_COUNTER_GROUP, firstPort.m_queue_ids[3], + { + {QUEUE_COUNTER_ID_LIST, "SAI_QUEUE_STAT_PACKETS,SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES"}, + {QUEUE_ATTR_ID_LIST, "SAI_QUEUE_ATTR_PAUSE_STATUS"} + })); + + entries.push_back({firstPort.m_alias, "DEL", { {}}}); + consumer->addToSync(entries); + entries.clear(); + static_cast(gPfcwdOrch)->doTask(); + ASSERT_TRUE(checkFlexCounter(PFC_WD_FLEX_COUNTER_GROUP, firstPort.m_port_id)); + ASSERT_TRUE(checkFlexCounter(PFC_WD_FLEX_COUNTER_GROUP, firstPort.m_queue_ids[3])); + + delete gPfcwdOrch; + gPfcwdOrch = nullptr; + std::vector pfcValues; + ASSERT_TRUE(checkFlexCounterGroup(PFC_WD_FLEX_COUNTER_GROUP, pfcValues)); + + if (create_only_config_db_buffers) + { + auto appdbKey = firstPortName + ":3-4"; + // Remove buffer PGs/queues + entries.push_back({appdbKey, "DEL", { {} }}); + consumer = dynamic_cast(gBufferOrch->getExecutor(APP_BUFFER_PG_TABLE_NAME)); + consumer->addToSync(entries); + consumer = dynamic_cast(gBufferOrch->getExecutor(APP_BUFFER_QUEUE_TABLE_NAME)); + consumer->addToSync(entries); + entries.clear(); + static_cast(gBufferOrch)->doTask(); + + ASSERT_TRUE(checkFlexCounter(PG_DROP_STAT_COUNTER_FLEX_COUNTER_GROUP, pgOid)); + ASSERT_TRUE(checkFlexCounter(PG_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, pgOid)); + ASSERT_TRUE(checkFlexCounter(QUEUE_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, queueOid)); + ASSERT_TRUE(checkFlexCounter(QUEUE_STAT_COUNTER_FLEX_COUNTER_GROUP, queueOid)); + + // Remove buffer profiles + entries.push_back({"ingress_lossless_profile", "DEL", { {} }}); + consumer = dynamic_cast(gBufferOrch->getExecutor(APP_BUFFER_PROFILE_TABLE_NAME)); + consumer->addToSync(entries); + entries.clear(); + static_cast(gBufferOrch)->doTask(); + } + + // Remove buffer pools + entries.push_back({"ingress_lossless_pool", "DEL", { {} }}); + consumer = dynamic_cast(gBufferOrch->getExecutor(APP_BUFFER_POOL_TABLE_NAME)); + consumer->addToSync(entries); + entries.clear(); + static_cast(gBufferOrch)->doTask(); + ASSERT_TRUE(checkFlexCounter(BUFFER_POOL_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, pool_oid)); + } + + INSTANTIATE_TEST_CASE_P( + FlexCounterTests, + FlexCounterTest, + ::testing::Values( + std::make_tuple(false, true), + std::make_tuple(false, false), + std::make_tuple(true, true), + std::make_tuple(true, false)) + ); +} diff --git a/tests/mock_tests/mock_orch_test.h b/tests/mock_tests/mock_orch_test.h index eefda42057..0f6163523d 100644 --- a/tests/mock_tests/mock_orch_test.h +++ b/tests/mock_tests/mock_orch_test.h @@ -193,6 +193,7 @@ namespace mock_orch_test APP_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME }; gBufferOrch = new BufferOrch(m_app_db.get(), m_config_db.get(), m_state_db.get(), buffer_tables); + ut_orch_list.push_back((Orch **)&gBufferOrch); TableConnector stateDbSwitchTable(m_state_db.get(), STATE_SWITCH_CAPABILITY_TABLE_NAME); TableConnector app_switch_table(m_app_db.get(), APP_SWITCH_TABLE_NAME); @@ -302,4 +303,4 @@ namespace mock_orch_test ut_helper::uninitSaiApi(); } }; -} \ No newline at end of file +} diff --git a/tests/mock_tests/mock_orchagent_main.cpp b/tests/mock_tests/mock_orchagent_main.cpp index e709824707..96d86018fa 100644 --- a/tests/mock_tests/mock_orchagent_main.cpp +++ b/tests/mock_tests/mock_orchagent_main.cpp @@ -16,6 +16,7 @@ string gMySwitchType = "switch"; int32_t gVoqMySwitchId = 0; string gMyHostName = "Linecard1"; string gMyAsicName = "Asic0"; +bool gTraditionalFlexCounter = false; VRFOrch *gVrfOrch; diff --git a/tests/mock_tests/mock_table.cpp b/tests/mock_tests/mock_table.cpp index df5e7e5753..7dc77d42ad 100644 --- a/tests/mock_tests/mock_table.cpp +++ b/tests/mock_tests/mock_table.cpp @@ -1,6 +1,8 @@ #include "table.h" #include "producerstatetable.h" +#include "producertable.h" #include +#include using TableDataT = std::map>; using TablesT = std::map; @@ -43,21 +45,9 @@ namespace swss existing_values.swap(new_values); } - bool Table::get(const std::string &key, std::vector &ovalues) - { - auto table = gDB[m_pipe->getDbId()][getTableName()]; - if (table.find(key) == table.end()) - { - return false; - } - - ovalues = table[key]; - return true; - } - - bool Table::hget(const std::string &key, const std::string &field, std::string &value) + bool _hget(int dbId, const std::string &tableName, const std::string &key, const std::string &field, std::string &value) { - auto table = gDB[m_pipe->getDbId()][getTableName()]; + auto table = gDB[dbId][tableName]; if (table.find(key) == table.end()) { return false; @@ -75,6 +65,23 @@ namespace swss return false; } + bool Table::get(const std::string &key, std::vector &ovalues) + { + auto table = gDB[m_pipe->getDbId()][getTableName()]; + if (table.find(key) == table.end()) + { + return false; + } + + ovalues = table[key]; + return true; + } + + bool Table::hget(const std::string &key, const std::string &field, std::string &value) + { + return _hget(m_pipe->getDbId(), getTableName(), key, field, value); + } + void Table::set(const std::string &key, const std::vector &values, const std::string &op, @@ -134,4 +141,43 @@ namespace swss auto &table = gDB[m_pipe->getDbId()][getTableName()]; table.erase(key); } + + std::shared_ptr DBConnector::hget(const std::string &key, const std::string &field) + { + std::string value; + if (_hget(getDbId(), key, "", field, value)) + { + std::shared_ptr ptr(new std::string(value)); + return ptr; + } + else + { + return std::shared_ptr(NULL); + } + } + + void ProducerTable::set(const std::string &key, + const std::vector &values, + const std::string &op, + const std::string &prefix) + { + auto &table = gDB[m_pipe->getDbId()][getTableName()]; + auto iter = table.find(key); + if (iter == table.end()) + { + table[key] = values; + } + else + { + merge_values(iter->second, values); + } + } + + void ProducerTable::del(const std::string &key, + const std::string &op, + const std::string &prefix) + { + auto &table = gDB[m_pipe->getDbId()][getTableName()]; + table.erase(key); + } } diff --git a/tests/mock_tests/qosorch_ut.cpp b/tests/mock_tests/qosorch_ut.cpp index 713238e9cd..72f50fc4fd 100644 --- a/tests/mock_tests/qosorch_ut.cpp +++ b/tests/mock_tests/qosorch_ut.cpp @@ -605,6 +605,9 @@ namespace qosorch_test delete gQosOrch; gQosOrch = nullptr; + delete gBufferOrch; + gBufferOrch = nullptr; + delete tunnel_decap_orch; tunnel_decap_orch = nullptr; diff --git a/tests/mock_tests/routeorch_ut.cpp b/tests/mock_tests/routeorch_ut.cpp index bd2108a683..6ea75c1bef 100644 --- a/tests/mock_tests/routeorch_ut.cpp +++ b/tests/mock_tests/routeorch_ut.cpp @@ -356,6 +356,9 @@ namespace routeorch_test delete gPortsOrch; gPortsOrch = nullptr; + delete gBufferOrch; + gBufferOrch = nullptr; + sai_route_api = pold_sai_route_api; ut_helper::uninitSaiApi(); } From c36333c3d7573a249991df5357955f0189ab4ada Mon Sep 17 00:00:00 2001 From: mint570 <70396898+mint570@users.noreply.github.com> Date: Wed, 15 May 2024 14:16:30 -0700 Subject: [PATCH 29/34] New p4orch development changes (#3066) * New p4orch development for performance. This is the first PR for upstreaming the recent P4Orch changes (has been a while since the last time). The main changes include: Add new status code SWSS_RC_NOT_EXECUTED Enable redis pipeline in response publisher for P4Orch (performance improvement) Enable background thread of write to db in response publisher for P4Orch (performance improvement) P4Orch writes to APPL DB instead of APPL STATE DB for responses (prepare for the zmq change, APPL DB will be used as APPL STATE DB in P4Orch for performance improvement) --- cfgmgr/Makefile.am | 2 +- orchagent/orch.h | 2 +- orchagent/p4orch/p4orch.cpp | 2 + orchagent/p4orch/p4orch.h | 3 + orchagent/p4orch/tests/return_code_test.cpp | 1 + orchagent/response_publisher.cpp | 120 +++- orchagent/response_publisher.h | 41 +- orchagent/return_code.h | 36 +- tests/mock_tests/fake_response_publisher.cpp | 5 +- .../response_publisher_ut.cpp | 4 +- tests/p4rt/test_l3.py | 585 ------------------ tests/p4rt/test_l3_admit.py | 47 -- tests/p4rt/test_p4rt_acl.py | 167 ----- tests/p4rt/test_p4rt_mirror.py | 37 -- tests/p4rt/test_viplb.py | 19 - tests/p4rt/util.py | 3 +- 16 files changed, 176 insertions(+), 898 deletions(-) diff --git a/cfgmgr/Makefile.am b/cfgmgr/Makefile.am index a8cbddb4e7..45afff7e9b 100644 --- a/cfgmgr/Makefile.am +++ b/cfgmgr/Makefile.am @@ -3,7 +3,7 @@ CFLAGS_SAI = -I /usr/include/sai LIBNL_CFLAGS = -I/usr/include/libnl3 LIBNL_LIBS = -lnl-genl-3 -lnl-route-3 -lnl-3 SAIMETA_LIBS = -lsaimeta -lsaimetadata -lzmq -COMMON_LIBS = -lswsscommon +COMMON_LIBS = -lswsscommon -lpthread bin_PROGRAMS = vlanmgrd teammgrd portmgrd intfmgrd buffermgrd vrfmgrd nbrmgrd vxlanmgrd sflowmgrd natmgrd coppmgrd tunnelmgrd macsecmgrd fabricmgrd diff --git a/orchagent/orch.h b/orchagent/orch.h index 6e4702ce3d..bdbecf5f5f 100644 --- a/orchagent/orch.h +++ b/orchagent/orch.h @@ -271,7 +271,7 @@ class Orch void addExecutor(Executor* executor); Executor *getExecutor(std::string executorName); - ResponsePublisher m_publisher; + ResponsePublisher m_publisher{"APPL_STATE_DB"}; private: void addConsumer(swss::DBConnector *db, std::string tableName, int pri = default_orch_pri); }; diff --git a/orchagent/p4orch/p4orch.cpp b/orchagent/p4orch/p4orch.cpp index f1e6bd4702..00e5ef6c4d 100644 --- a/orchagent/p4orch/p4orch.cpp +++ b/orchagent/p4orch/p4orch.cpp @@ -154,6 +154,8 @@ void P4Orch::doTask(Consumer &consumer) { manager->drain(); } + + m_publisher.flush(); } void P4Orch::doTask(swss::SelectableTimer &timer) diff --git a/orchagent/p4orch/p4orch.h b/orchagent/p4orch/p4orch.h index cc02052830..549aac17b2 100644 --- a/orchagent/p4orch/p4orch.h +++ b/orchagent/p4orch/p4orch.h @@ -83,5 +83,8 @@ class P4Orch : public Orch // Notification consumer for port state change swss::NotificationConsumer *m_portStatusNotificationConsumer; + // Sepcial publisher that writes to APPL DB instead of APPL STATE DB. + ResponsePublisher m_publisher{"APPL_DB", /*bool buffered=*/true, /*db_write_thread=*/true}; + friend class p4orch::test::WcmpManagerTest; }; diff --git a/orchagent/p4orch/tests/return_code_test.cpp b/orchagent/p4orch/tests/return_code_test.cpp index 7ab21121aa..6ee73b74f9 100644 --- a/orchagent/p4orch/tests/return_code_test.cpp +++ b/orchagent/p4orch/tests/return_code_test.cpp @@ -119,6 +119,7 @@ TEST(ReturnCodeTest, SaiCodeToReturnCodeMapping) {SAI_STATUS_TABLE_FULL, StatusCode::SWSS_RC_FULL}, {SAI_STATUS_NOT_IMPLEMENTED, StatusCode::SWSS_RC_UNIMPLEMENTED}, {SAI_STATUS_OBJECT_IN_USE, StatusCode::SWSS_RC_IN_USE}, + {SAI_STATUS_NOT_EXECUTED, StatusCode::SWSS_RC_NOT_EXECUTED}, {SAI_STATUS_FAILURE, StatusCode::SWSS_RC_UNKNOWN}, {SAI_STATUS_INVALID_ATTRIBUTE_0, StatusCode::SWSS_RC_INVALID_PARAM}, {SAI_STATUS_INVALID_ATTRIBUTE_10, StatusCode::SWSS_RC_INVALID_PARAM}, diff --git a/orchagent/response_publisher.cpp b/orchagent/response_publisher.cpp index d5b94a586d..f630ddf589 100644 --- a/orchagent/response_publisher.cpp +++ b/orchagent/response_publisher.cpp @@ -64,26 +64,45 @@ void RecordResponse(const std::string &response_channel, const std::string &key, } // namespace -ResponsePublisher::ResponsePublisher(bool buffered) - : m_db(std::make_unique("APPL_STATE_DB", 0)), - m_pipe(std::make_unique(m_db.get())), m_buffered(buffered) +ResponsePublisher::ResponsePublisher(const std::string &dbName, bool buffered, bool db_write_thread) + : m_db(std::make_unique(dbName, 0)), m_buffered(buffered) { + if (m_buffered) + { + m_ntf_pipe = std::make_unique(m_db.get()); + m_db_pipe = std::make_unique(m_db.get()); + } + else + { + m_ntf_pipe = std::make_unique(m_db.get(), 1); + m_db_pipe = std::make_unique(m_db.get(), 1); + } + if (db_write_thread) + { + m_update_thread = std::unique_ptr(new std::thread(&ResponsePublisher::dbUpdateThread, this)); + } } -void ResponsePublisher::publish(const std::string &table, const std::string &key, - const std::vector &intent_attrs, const ReturnCode &status, - const std::vector &state_attrs, bool replace) +ResponsePublisher::~ResponsePublisher() { - // Write to the DB only if: - // 1) A write operation is being performed and state attributes are specified. - // 2) A successful delete operation. - if ((intent_attrs.size() && state_attrs.size()) || (status.ok() && !intent_attrs.size())) + if (m_update_thread != nullptr) { - writeToDB(table, key, state_attrs, intent_attrs.size() ? SET_COMMAND : DEL_COMMAND, replace); + { + std::lock_guard lock(m_lock); + m_queue.emplace(/*table=*/"", /*key=*/"", /*values =*/std::vector{}, /*op=*/"", + /*replace=*/false, /*flush=*/false, /*shutdown=*/true); + } + m_signal.notify_one(); + m_update_thread->join(); } +} +void ResponsePublisher::publish(const std::string &table, const std::string &key, + const std::vector &intent_attrs, const ReturnCode &status, + const std::vector &state_attrs, bool replace) +{ std::string response_channel = "APPL_DB_" + table + "_RESPONSE_CHANNEL"; - swss::NotificationProducer notificationProducer{m_pipe.get(), response_channel, m_buffered}; + swss::NotificationProducer notificationProducer{m_ntf_pipe.get(), response_channel, m_buffered}; auto intent_attrs_copy = intent_attrs; // Add error message as the first field-value-pair. @@ -92,6 +111,14 @@ void ResponsePublisher::publish(const std::string &table, const std::string &key // Sends the response to the notification channel. notificationProducer.send(status.codeStr(), key, intent_attrs_copy); RecordResponse(response_channel, key, intent_attrs_copy, status.codeStr()); + + // Write to the DB only if: + // 1) A write operation is being performed and state attributes are specified. + // 2) A successful delete operation. + if ((intent_attrs.size() && state_attrs.size()) || (status.ok() && !intent_attrs.size())) + { + writeToDB(table, key, state_attrs, intent_attrs.size() ? SET_COMMAND : DEL_COMMAND, replace); + } } void ResponsePublisher::publish(const std::string &table, const std::string &key, @@ -113,7 +140,26 @@ void ResponsePublisher::publish(const std::string &table, const std::string &key void ResponsePublisher::writeToDB(const std::string &table, const std::string &key, const std::vector &values, const std::string &op, bool replace) { - swss::Table applStateTable{m_pipe.get(), table, m_buffered}; + if (m_update_thread != nullptr) + { + { + std::lock_guard lock(m_lock); + m_queue.emplace(table, key, values, op, replace, /*flush=*/false, /*shutdown=*/false); + } + m_signal.notify_one(); + } + else + { + writeToDBInternal(table, key, values, op, replace); + } + RecordDBWrite(table, key, values, op); +} + +void ResponsePublisher::writeToDBInternal(const std::string &table, const std::string &key, + const std::vector &values, const std::string &op, + bool replace) +{ + swss::Table applStateTable{m_db_pipe.get(), table, m_buffered}; auto attrs = values; if (op == SET_COMMAND) @@ -133,7 +179,6 @@ void ResponsePublisher::writeToDB(const std::string &table, const std::string &k if (!applStateTable.get(key, fv)) { applStateTable.set(key, attrs); - RecordDBWrite(table, key, attrs, op); return; } for (auto it = attrs.cbegin(); it != attrs.cend();) @@ -150,22 +195,63 @@ void ResponsePublisher::writeToDB(const std::string &table, const std::string &k if (attrs.size()) { applStateTable.set(key, attrs); - RecordDBWrite(table, key, attrs, op); } } else if (op == DEL_COMMAND) { applStateTable.del(key); - RecordDBWrite(table, key, {}, op); } } void ResponsePublisher::flush() { - m_pipe->flush(); + m_ntf_pipe->flush(); + if (m_update_thread != nullptr) + { + { + std::lock_guard lock(m_lock); + m_queue.emplace(/*table=*/"", /*key=*/"", /*values =*/std::vector{}, /*op=*/"", + /*replace=*/false, /*flush=*/true, /*shutdown=*/false); + } + m_signal.notify_one(); + } + else + { + m_db_pipe->flush(); + } } void ResponsePublisher::setBuffered(bool buffered) { m_buffered = buffered; } + +void ResponsePublisher::dbUpdateThread() +{ + while (true) + { + entry e; + { + std::unique_lock lock(m_lock); + while (m_queue.empty()) + { + m_signal.wait(lock); + } + + e = m_queue.front(); + m_queue.pop(); + } + if (e.shutdown) + { + break; + } + if (e.flush) + { + m_db_pipe->flush(); + } + else + { + writeToDBInternal(e.table, e.key, e.values, e.op, e.replace); + } + } +} diff --git a/orchagent/response_publisher.h b/orchagent/response_publisher.h index 985532e827..e859852e3f 100644 --- a/orchagent/response_publisher.h +++ b/orchagent/response_publisher.h @@ -1,7 +1,11 @@ #pragma once +#include #include +#include +#include #include +#include #include #include @@ -17,9 +21,9 @@ class ResponsePublisher : public ResponsePublisherInterface { public: - explicit ResponsePublisher(bool buffered = false); + explicit ResponsePublisher(const std::string &dbName, bool buffered = false, bool db_write_thread = false); - virtual ~ResponsePublisher() = default; + virtual ~ResponsePublisher(); // Intent attributes are the attributes sent in the notification into the // redis channel. @@ -57,8 +61,39 @@ class ResponsePublisher : public ResponsePublisherInterface void setBuffered(bool buffered); private: + struct entry + { + std::string table; + std::string key; + std::vector values; + std::string op; + bool replace; + bool flush; + bool shutdown; + + entry() + { + } + + entry(const std::string &table, const std::string &key, const std::vector &values, + const std::string &op, bool replace, bool flush, bool shutdown) + : table(table), key(key), values(values), op(op), replace(replace), flush(flush), shutdown(shutdown) + { + } + }; + + void dbUpdateThread(); + void writeToDBInternal(const std::string &table, const std::string &key, + const std::vector &values, const std::string &op, bool replace); + std::unique_ptr m_db; - std::unique_ptr m_pipe; + std::unique_ptr m_ntf_pipe; + std::unique_ptr m_db_pipe; bool m_buffered{false}; + // Thread to write to DB. + std::unique_ptr m_update_thread; + std::queue m_queue; + mutable std::mutex m_lock; + std::condition_variable m_signal; }; diff --git a/orchagent/return_code.h b/orchagent/return_code.h index ed154784b7..c9b404f5d7 100644 --- a/orchagent/return_code.h +++ b/orchagent/return_code.h @@ -177,7 +177,24 @@ class ReturnCode ReturnCode(const sai_status_t &status, const std::string &message = "") : stream_(std::ios_base::out | std::ios_base::ate), is_sai_(true) { - if (m_saiStatusCodeLookup.find(status) == m_saiStatusCodeLookup.end()) + // Non-ranged SAI codes that are not included in this lookup map will map to + // SWSS_RC_UNKNOWN. This includes the general SAI failure: + // SAI_STATUS_FAILURE. + static const auto *const saiStatusCodeLookup = new std::unordered_map({ + {SAI_STATUS_SUCCESS, StatusCode::SWSS_RC_SUCCESS}, + {SAI_STATUS_NOT_SUPPORTED, StatusCode::SWSS_RC_UNIMPLEMENTED}, + {SAI_STATUS_NO_MEMORY, StatusCode::SWSS_RC_NO_MEMORY}, + {SAI_STATUS_INSUFFICIENT_RESOURCES, StatusCode::SWSS_RC_FULL}, + {SAI_STATUS_INVALID_PARAMETER, StatusCode::SWSS_RC_INVALID_PARAM}, + {SAI_STATUS_ITEM_ALREADY_EXISTS, StatusCode::SWSS_RC_EXISTS}, + {SAI_STATUS_ITEM_NOT_FOUND, StatusCode::SWSS_RC_NOT_FOUND}, + {SAI_STATUS_TABLE_FULL, StatusCode::SWSS_RC_FULL}, + {SAI_STATUS_NOT_IMPLEMENTED, StatusCode::SWSS_RC_UNIMPLEMENTED}, + {SAI_STATUS_OBJECT_IN_USE, StatusCode::SWSS_RC_IN_USE}, + {SAI_STATUS_NOT_EXECUTED, StatusCode::SWSS_RC_NOT_EXECUTED}, + }); + + if (saiStatusCodeLookup->find(status) == saiStatusCodeLookup->end()) { // Check for ranged SAI codes. if (SAI_RANGED_STATUS_IS_INVALID_ATTRIBUTE(status)) @@ -207,7 +224,7 @@ class ReturnCode } else { - status_ = m_saiStatusCodeLookup[status]; + status_ = saiStatusCodeLookup->at(status); } stream_ << message; } @@ -298,21 +315,6 @@ class ReturnCode } private: - // Non-ranged SAI codes that are not included in this lookup map will map to - // SWSS_RC_UNKNOWN. This includes the general SAI failure: SAI_STATUS_FAILURE. - std::unordered_map m_saiStatusCodeLookup = { - {SAI_STATUS_SUCCESS, StatusCode::SWSS_RC_SUCCESS}, - {SAI_STATUS_NOT_SUPPORTED, StatusCode::SWSS_RC_UNIMPLEMENTED}, - {SAI_STATUS_NO_MEMORY, StatusCode::SWSS_RC_NO_MEMORY}, - {SAI_STATUS_INSUFFICIENT_RESOURCES, StatusCode::SWSS_RC_FULL}, - {SAI_STATUS_INVALID_PARAMETER, StatusCode::SWSS_RC_INVALID_PARAM}, - {SAI_STATUS_ITEM_ALREADY_EXISTS, StatusCode::SWSS_RC_EXISTS}, - {SAI_STATUS_ITEM_NOT_FOUND, StatusCode::SWSS_RC_NOT_FOUND}, - {SAI_STATUS_TABLE_FULL, StatusCode::SWSS_RC_FULL}, - {SAI_STATUS_NOT_IMPLEMENTED, StatusCode::SWSS_RC_UNIMPLEMENTED}, - {SAI_STATUS_OBJECT_IN_USE, StatusCode::SWSS_RC_IN_USE}, - }; - StatusCode status_; std::stringstream stream_; // Whether the ReturnCode is generated from a SAI status code or not. diff --git a/tests/mock_tests/fake_response_publisher.cpp b/tests/mock_tests/fake_response_publisher.cpp index 29a28d2360..5e6aa0f2a0 100644 --- a/tests/mock_tests/fake_response_publisher.cpp +++ b/tests/mock_tests/fake_response_publisher.cpp @@ -8,7 +8,10 @@ * when needed to test code that uses response publisher. */ std::unique_ptr gMockResponsePublisher; -ResponsePublisher::ResponsePublisher(bool buffered) : m_db(std::make_unique("APPL_STATE_DB", 0)), m_buffered(buffered) {} +ResponsePublisher::ResponsePublisher(const std::string& dbName, bool buffered, bool db_write_thread) : + m_db(std::make_unique(dbName, 0)), m_buffered(buffered) {} + +ResponsePublisher::~ResponsePublisher() {} void ResponsePublisher::publish( const std::string& table, const std::string& key, diff --git a/tests/mock_tests/response_publisher/response_publisher_ut.cpp b/tests/mock_tests/response_publisher/response_publisher_ut.cpp index 9e836bad04..ca4956fdcf 100644 --- a/tests/mock_tests/response_publisher/response_publisher_ut.cpp +++ b/tests/mock_tests/response_publisher/response_publisher_ut.cpp @@ -9,7 +9,7 @@ TEST(ResponsePublisher, TestPublish) DBConnector conn{"APPL_STATE_DB", 0}; Table stateTable{&conn, "SOME_TABLE"}; std::string value; - ResponsePublisher publisher{}; + ResponsePublisher publisher{"APPL_STATE_DB"}; publisher.publish("SOME_TABLE", "SOME_KEY", {{"field", "value"}}, ReturnCode(SAI_STATUS_SUCCESS)); ASSERT_TRUE(stateTable.hget("SOME_KEY", "field", value)); @@ -21,7 +21,7 @@ TEST(ResponsePublisher, TestPublishBuffered) DBConnector conn{"APPL_STATE_DB", 0}; Table stateTable{&conn, "SOME_TABLE"}; std::string value; - ResponsePublisher publisher{}; + ResponsePublisher publisher{"APPL_STATE_DB"}; publisher.setBuffered(true); diff --git a/tests/p4rt/test_l3.py b/tests/p4rt/test_l3.py index a16c8d3f03..0536e88b4f 100644 --- a/tests/p4rt/test_l3.py +++ b/tests/p4rt/test_l3.py @@ -59,11 +59,6 @@ def test_IPv4RouteWithNexthopAddUpdateDeletePass(self, dvs, testlog): "%s:%s" % (self._p4rt_route_obj.APP_DB_TBL_NAME, self._p4rt_route_obj.TBL_NAME), ), - ( - self._p4rt_route_obj.appl_state_db, - "%s:%s" - % (self._p4rt_route_obj.APP_DB_TBL_NAME, self._p4rt_route_obj.TBL_NAME), - ), (self._p4rt_route_obj.asic_db, self._p4rt_route_obj.ASIC_DB_TBL_NAME), ) self._p4rt_route_obj.get_original_redis_entries(db_list) @@ -145,24 +140,6 @@ def test_IPv4RouteWithNexthopAddUpdateDeletePass(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # Query application state database for route entries. - state_route_entries = util.get_keys( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME, - ) - assert len(state_route_entries) == ( - self._p4rt_route_obj.get_original_appl_state_db_entries_count() + 1 - ) - - # Query application state database for newly created route key. - (status, fvs) = util.get_key( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME, - route_key, - ) - assert status == True - util.verify_attr(fvs, attr_list) - # Query ASIC database for route entries. route_entries = util.get_keys( self._p4rt_route_obj.asic_db, self._p4rt_route_obj.ASIC_DB_TBL_NAME @@ -227,24 +204,6 @@ def test_IPv4RouteWithNexthopAddUpdateDeletePass(self, dvs, testlog): ] util.verify_attr(fvs, attr_list_appl_db) - # Query application state database for route entries. - state_route_entries = util.get_keys( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME, - ) - assert len(state_route_entries) == ( - self._p4rt_route_obj.get_original_appl_state_db_entries_count() + 1 - ) - - # Query application state database for the updated route key. - (status, fvs) = util.get_key( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME, - route_key, - ) - assert status == True - util.verify_attr(fvs, attr_list) - # Query ASIC database for route entries. route_entries = util.get_keys( self._p4rt_route_obj.asic_db, self._p4rt_route_obj.ASIC_DB_TBL_NAME @@ -295,37 +254,6 @@ def test_IPv4RouteWithNexthopAddUpdateDeletePass(self, dvs, testlog): route_key, ) assert status == True - attr_list_appl_db = [ - (self._p4rt_route_obj.ACTION_FIELD, "drop"), - ( - util.prepend_param_field( - self._p4rt_route_obj.NEXTHOP_ID_FIELD), - nexthop_id, - ), - ( - util.prepend_param_field( - self._p4rt_route_obj.ROUTE_METADATA_FIELD), - "2", - ), - ] - util.verify_attr(fvs, attr_list_appl_db) - - # Query application state database for route entries. - state_route_entries = util.get_keys( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME, - ) - assert len(state_route_entries) == ( - self._p4rt_route_obj.get_original_appl_state_db_entries_count() + 1 - ) - - # Query application state database for the updated route key. - (status, fvs) = util.get_key( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME, - route_key, - ) - assert status == True util.verify_attr(fvs, attr_list) # Query ASIC database for route entries. @@ -417,24 +345,6 @@ def test_IPv4RouteWithNexthopAddUpdateDeletePass(self, dvs, testlog): ) assert status == False - # Query application state database for route entries. - state_route_entries = util.get_keys( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME, - ) - assert len(state_route_entries) == ( - self._p4rt_route_obj.get_original_appl_state_db_entries_count() - ) - - # Verify that the route_key no longer exists in application state - # database. - (status, fsv) = util.get_key( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME, - route_key, - ) - assert status == False - # Query ASIC database for route entries. route_entries = util.get_keys( self._p4rt_route_obj.asic_db, self._p4rt_route_obj.ASIC_DB_TBL_NAME @@ -468,11 +378,6 @@ def test_IPv6WithWcmpRouteAddUpdateDeletePass(self, dvs, testlog): "%s:%s" % (self._p4rt_route_obj.APP_DB_TBL_NAME, self._p4rt_route_obj.TBL_NAME), ), - ( - self._p4rt_route_obj.appl_state_db, - "%s:%s" - % (self._p4rt_route_obj.APP_DB_TBL_NAME, self._p4rt_route_obj.TBL_NAME), - ), (self._p4rt_route_obj.asic_db, self._p4rt_route_obj.ASIC_DB_TBL_NAME), ) self._p4rt_route_obj.get_original_redis_entries(db_list) @@ -490,14 +395,6 @@ def test_IPv6WithWcmpRouteAddUpdateDeletePass(self, dvs, testlog): self._p4rt_wcmp_group_obj.TBL_NAME, ), ), - ( - self._p4rt_wcmp_group_obj.appl_state_db, - "%s:%s" - % ( - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, - self._p4rt_wcmp_group_obj.TBL_NAME, - ), - ), ( self._p4rt_wcmp_group_obj.asic_db, self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME, @@ -597,26 +494,6 @@ def test_IPv6WithWcmpRouteAddUpdateDeletePass(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # Query application state database for wcmp group entries. - state_wcmp_group_entries = util.get_keys( - self._p4rt_wcmp_group_obj.appl_state_db, - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME - + ":" - + self._p4rt_wcmp_group_obj.TBL_NAME, - ) - assert len(state_wcmp_group_entries) == ( - self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() + 1 - ) - - # Query application state database for newly created wcmp group key. - (status, fvs) = util.get_key( - self._p4rt_wcmp_group_obj.appl_state_db, - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, - wcmp_group_key, - ) - assert status == True - util.verify_attr(fvs, attr_list) - # Query ASIC database for wcmp group entries. wcmp_group_entries = util.get_keys( self._p4rt_wcmp_group_obj.asic_db, @@ -708,24 +585,6 @@ def test_IPv6WithWcmpRouteAddUpdateDeletePass(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # Query application state database for route entries. - state_route_entries = util.get_keys( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME, - ) - assert len(state_route_entries) == ( - self._p4rt_route_obj.get_original_appl_state_db_entries_count() + 1 - ) - - # Query application state database for newly created route key. - (status, fvs) = util.get_key( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME, - route_key, - ) - assert status == True - util.verify_attr(fvs, attr_list) - # Query ASIC database for route entries. route_entries = util.get_keys( self._p4rt_route_obj.asic_db, self._p4rt_route_obj.ASIC_DB_TBL_NAME @@ -776,32 +635,6 @@ def test_IPv6WithWcmpRouteAddUpdateDeletePass(self, dvs, testlog): route_key, ) assert status == True - attr_list_appl_db = [ - (self._p4rt_route_obj.ACTION_FIELD, "drop"), - ( - util.prepend_param_field( - self._p4rt_route_obj.WCMP_GROUP_ID_FIELD), - wcmp_group_id, - ), - ] - util.verify_attr(fvs, attr_list_appl_db) - - # Query application state database for route entries. - state_route_entries = util.get_keys( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME, - ) - assert len(state_route_entries) == ( - self._p4rt_route_obj.get_original_appl_state_db_entries_count() + 1 - ) - - # Query application state database for the updated route key. - (status, fvs) = util.get_key( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME, - route_key, - ) - assert status == True util.verify_attr(fvs, attr_list) # Query ASIC database for route entries. @@ -859,32 +692,6 @@ def test_IPv6WithWcmpRouteAddUpdateDeletePass(self, dvs, testlog): route_key, ) assert status == True - attr_list_appl_db = [ - (self._p4rt_route_obj.ACTION_FIELD, "trap"), - ( - util.prepend_param_field( - self._p4rt_route_obj.WCMP_GROUP_ID_FIELD), - wcmp_group_id, - ), - ] - util.verify_attr(fvs, attr_list_appl_db) - - # Query application state database for route entries. - state_route_entries = util.get_keys( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME, - ) - assert len(state_route_entries) == ( - self._p4rt_route_obj.get_original_appl_state_db_entries_count() + 1 - ) - - # Query application state database for the updated route key. - (status, fvs) = util.get_key( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME, - route_key, - ) - assert status == True util.verify_attr(fvs, attr_list) # Query ASIC database for route entries. @@ -988,24 +795,6 @@ def test_IPv6WithWcmpRouteAddUpdateDeletePass(self, dvs, testlog): ) assert status == False - # Query application state database for route entries. - state_route_entries = util.get_keys( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME, - ) - assert len(state_route_entries) == ( - self._p4rt_route_obj.get_original_appl_state_db_entries_count() - ) - - # Verify that the route_key no longer exists in application state - # database. - (status, fsv) = util.get_key( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME, - route_key, - ) - assert status == False - # Query ASIC database for route entries. route_entries = util.get_keys( self._p4rt_route_obj.asic_db, self._p4rt_route_obj.ASIC_DB_TBL_NAME @@ -1041,26 +830,6 @@ def test_IPv6WithWcmpRouteAddUpdateDeletePass(self, dvs, testlog): ) assert status == False - # Query application state database for wcmp group entries. - state_wcmp_group_entries = util.get_keys( - self._p4rt_wcmp_group_obj.appl_state_db, - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME - + ":" - + self._p4rt_wcmp_group_obj.TBL_NAME, - ) - assert len(state_wcmp_group_entries) == ( - self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() - ) - - # Verify that the wcmp_group_key no longer exists in application state - # database. - (status, fsv) = util.get_key( - self._p4rt_wcmp_group_obj.appl_state_db, - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, - wcmp_group_key, - ) - assert status == False - # Query ASIC database for wcmp group entries. wcmp_group_entries = util.get_keys( self._p4rt_wcmp_group_obj.asic_db, @@ -1114,14 +883,6 @@ def test_NexthopWithGreTunnelAddDeletePass(self, dvs, testlog): self._p4rt_nexthop_obj.TBL_NAME, ), ), - ( - self._p4rt_nexthop_obj.appl_state_db, - "%s:%s" - % ( - self._p4rt_nexthop_obj.APP_DB_TBL_NAME, - self._p4rt_nexthop_obj.TBL_NAME, - ), - ), (self._p4rt_nexthop_obj.asic_db, self._p4rt_nexthop_obj.ASIC_DB_TBL_NAME), ) @@ -1135,14 +896,6 @@ def test_NexthopWithGreTunnelAddDeletePass(self, dvs, testlog): self._p4rt_gre_tunnel_obj.TBL_NAME, ), ), - ( - self._p4rt_gre_tunnel_obj.appl_state_db, - "%s:%s" - % ( - self._p4rt_gre_tunnel_obj.APP_DB_TBL_NAME, - self._p4rt_gre_tunnel_obj.TBL_NAME, - ), - ), (self._p4rt_gre_tunnel_obj.asic_db, self._p4rt_gre_tunnel_obj.ASIC_DB_TBL_NAME), ) @@ -1215,25 +968,6 @@ def test_NexthopWithGreTunnelAddDeletePass(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # Query application state database for tunnel entries. - state_tunnel_entries = util.get_keys( - self._p4rt_gre_tunnel_obj.appl_state_db, - self._p4rt_gre_tunnel_obj.APP_DB_TBL_NAME + - ":" + self._p4rt_gre_tunnel_obj.TBL_NAME, - ) - assert len(state_tunnel_entries) == ( - self._p4rt_gre_tunnel_obj.get_original_appl_state_db_entries_count() + 1 - ) - - # Query application state database for newly created tunnel key. - (status, fvs) = util.get_key( - self._p4rt_gre_tunnel_obj.appl_state_db, - self._p4rt_gre_tunnel_obj.APP_DB_TBL_NAME, - tunnel_key, - ) - assert status == True - util.verify_attr(fvs, attr_list) - # Query ASIC database for tunnel entries. tunnel_entries = util.get_keys( self._p4rt_gre_tunnel_obj.asic_db, self._p4rt_gre_tunnel_obj.ASIC_DB_TBL_NAME @@ -1311,24 +1045,6 @@ def test_NexthopWithGreTunnelAddDeletePass(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # Query application state database for nexthop entries. - state_nexthop_entries = util.get_keys( - self._p4rt_nexthop_obj.appl_state_db, - self._p4rt_nexthop_obj.APP_DB_TBL_NAME + ":" + self._p4rt_nexthop_obj.TBL_NAME, - ) - assert len(state_nexthop_entries) == ( - self._p4rt_nexthop_obj.get_original_appl_state_db_entries_count() + 1 - ) - - # Query application state database for newly created nexthop key. - (status, fvs) = util.get_key( - self._p4rt_nexthop_obj.appl_state_db, - self._p4rt_nexthop_obj.APP_DB_TBL_NAME, - nexthop_key, - ) - assert status == True - util.verify_attr(fvs, attr_list) - # Query ASIC database for nexthop entries. nexthop_entries = util.get_keys( self._p4rt_nexthop_obj.asic_db, self._p4rt_nexthop_obj.ASIC_DB_TBL_NAME @@ -1418,24 +1134,6 @@ def test_NexthopWithGreTunnelAddDeletePass(self, dvs, testlog): ) assert status == False - # Query application state database for nexthop entries. - state_nexthop_entries = util.get_keys( - self._p4rt_nexthop_obj.appl_state_db, - self._p4rt_nexthop_obj.APP_DB_TBL_NAME + ":" + self._p4rt_nexthop_obj.TBL_NAME, - ) - assert len(state_nexthop_entries) == ( - self._p4rt_nexthop_obj.get_original_appl_state_db_entries_count() - ) - - # Verify that the nexthop_key no longer exists in application state - # database. - (status, fsv) = util.get_key( - self._p4rt_nexthop_obj.appl_state_db, - self._p4rt_nexthop_obj.APP_DB_TBL_NAME, - nexthop_key, - ) - assert status == False - # Query ASIC database for nexthop entries. nexthop_entries = util.get_keys( self._p4rt_nexthop_obj.asic_db, self._p4rt_nexthop_obj.ASIC_DB_TBL_NAME @@ -1470,25 +1168,6 @@ def test_NexthopWithGreTunnelAddDeletePass(self, dvs, testlog): ) assert status == False - # Query application state database for tunnel entries. - state_tunnel_entries = util.get_keys( - self._p4rt_gre_tunnel_obj.appl_state_db, - self._p4rt_gre_tunnel_obj.APP_DB_TBL_NAME + - ":" + self._p4rt_gre_tunnel_obj.TBL_NAME, - ) - assert len(state_tunnel_entries) == ( - self._p4rt_gre_tunnel_obj.get_original_appl_state_db_entries_count() - ) - - # Verify that the tunnel_key no longer exists in application state - # database. - (status, fsv) = util.get_key( - self._p4rt_gre_tunnel_obj.appl_state_db, - self._p4rt_gre_tunnel_obj.APP_DB_TBL_NAME, - tunnel_key, - ) - assert status == False - # Query ASIC database for tunnel entries. runnel_entries = util.get_keys( self._p4rt_gre_tunnel_obj.asic_db, self._p4rt_gre_tunnel_obj.ASIC_DB_TBL_NAME @@ -1524,11 +1203,6 @@ def test_IPv4RouteAddWithInvalidNexthopFail(self, dvs, testlog): "%s:%s" % (self._p4rt_route_obj.APP_DB_TBL_NAME, self._p4rt_route_obj.TBL_NAME), ), - ( - self._p4rt_route_obj.appl_state_db, - "%s:%s" - % (self._p4rt_route_obj.APP_DB_TBL_NAME, self._p4rt_route_obj.TBL_NAME), - ), (self._p4rt_route_obj.asic_db, self._p4rt_route_obj.ASIC_DB_TBL_NAME), ) self._p4rt_route_obj.get_original_redis_entries(db_list) @@ -1558,25 +1232,6 @@ def test_IPv4RouteAddWithInvalidNexthopFail(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # Query application database for route entries (no new route entry - # expected). - state_route_entries = util.get_keys( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME, - ) - assert len(state_route_entries) == ( - self._p4rt_route_obj.get_original_appl_state_db_entries_count() - ) - - # Verify that the newly added route key does not exist in application - # state db. - (status, fvs) = util.get_key( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME, - route_key, - ) - assert status == False - # Query ASIC database for route entries (no new ASIC DB entry should be # created for route entry). route_entries = util.get_keys( @@ -1612,11 +1267,6 @@ def test_IPv6RouteAddWithInvalidWcmpFail(self, dvs, testlog): "%s:%s" % (self._p4rt_route_obj.APP_DB_TBL_NAME, self._p4rt_route_obj.TBL_NAME), ), - ( - self._p4rt_route_obj.appl_state_db, - "%s:%s" - % (self._p4rt_route_obj.APP_DB_TBL_NAME, self._p4rt_route_obj.TBL_NAME), - ), (self._p4rt_route_obj.asic_db, self._p4rt_route_obj.ASIC_DB_TBL_NAME), ) self._p4rt_route_obj.get_original_redis_entries(db_list) @@ -1648,25 +1298,6 @@ def test_IPv6RouteAddWithInvalidWcmpFail(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # Query application state database for route entries (no new APPL STATE DB - # entry should be created for route entry). - state_route_entries = util.get_keys( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME, - ) - assert len(state_route_entries) == ( - self._p4rt_route_obj.get_original_appl_state_db_entries_count() - ) - - # Verify that newly created route key does not exist in application - # state db. - (status, fvs) = util.get_key( - self._p4rt_route_obj.appl_state_db, - self._p4rt_route_obj.APP_DB_TBL_NAME, - route_key, - ) - assert status == False - # Query ASIC database for route entries (no new ASIC DB entry should be # created for route entry). route_entries = util.get_keys( @@ -1699,14 +1330,6 @@ def test_PruneAndRestoreNextHop(self, dvs, testlog): self._p4rt_wcmp_group_obj.TBL_NAME, ), ), - ( - self._p4rt_wcmp_group_obj.appl_state_db, - "%s:%s" - % ( - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, - self._p4rt_wcmp_group_obj.TBL_NAME, - ), - ), ( self._p4rt_wcmp_group_obj.asic_db, self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME, @@ -1813,26 +1436,6 @@ def test_PruneAndRestoreNextHop(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # Query application state database for wcmp group entries. - state_wcmp_group_entries = util.get_keys( - self._p4rt_wcmp_group_obj.appl_state_db, - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME - + ":" - + self._p4rt_wcmp_group_obj.TBL_NAME, - ) - assert len(state_wcmp_group_entries) == ( - self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() + 1 - ) - - # Query application state database for newly created wcmp group key. - (status, fvs) = util.get_key( - self._p4rt_wcmp_group_obj.appl_state_db, - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, - wcmp_group_key, - ) - assert status == True - util.verify_attr(fvs, attr_list) - # Query ASIC database for wcmp group entries. wcmp_group_entries = util.get_keys( self._p4rt_wcmp_group_obj.asic_db, @@ -1898,15 +1501,6 @@ def test_PruneAndRestoreNextHop(self, dvs, testlog): self._p4rt_wcmp_group_obj.get_original_asic_db_member_entries_count() ) - # Check APPL STATE DB to verify no change. - (status, fvs) = util.get_key( - self._p4rt_wcmp_group_obj.appl_state_db, - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, - wcmp_group_key, - ) - assert status == True - util.verify_attr(fvs, attr_list) - # Force oper-up for associated port. util.set_interface_status(dvs, if_name, "up") @@ -1940,19 +1534,6 @@ def test_PruneAndRestoreNextHop(self, dvs, testlog): assert status == True assert len(fvs) == len(original_key_oid_info) + count - # Verify that APPL STATE DB is now updated. - state_wcmp_group_entries = util.get_keys( - self._p4rt_wcmp_group_obj.appl_state_db, - ( - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME - + ":" - + self._p4rt_wcmp_group_obj.TBL_NAME - ), - ) - assert len(state_wcmp_group_entries) == ( - self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() - ) - # Delete next hop. self._p4rt_nexthop_obj.remove_app_db_entry(nexthop_key) @@ -1994,14 +1575,6 @@ def test_PruneNextHopOnWarmBoot(self, dvs, testlog): self._p4rt_wcmp_group_obj.TBL_NAME, ), ), - ( - self._p4rt_wcmp_group_obj.appl_state_db, - "%s:%s" - % ( - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, - self._p4rt_wcmp_group_obj.TBL_NAME, - ), - ), ( self._p4rt_wcmp_group_obj.asic_db, self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME, @@ -2108,26 +1681,6 @@ def test_PruneNextHopOnWarmBoot(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # Query application state database for wcmp group entries. - state_wcmp_group_entries = util.get_keys( - self._p4rt_wcmp_group_obj.appl_state_db, - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME - + ":" - + self._p4rt_wcmp_group_obj.TBL_NAME, - ) - assert len(state_wcmp_group_entries) == ( - self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() + 1 - ) - - # Query application state database for newly created wcmp group key. - (status, fvs) = util.get_key( - self._p4rt_wcmp_group_obj.appl_state_db, - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, - wcmp_group_key, - ) - assert status == True - util.verify_attr(fvs, attr_list) - # Query ASIC database for wcmp group entries. wcmp_group_entries = util.get_keys( self._p4rt_wcmp_group_obj.asic_db, @@ -2219,19 +1772,6 @@ def test_PruneNextHopOnWarmBoot(self, dvs, testlog): assert status == True assert len(fvs) == len(original_key_oid_info) + count - # Verify that APPL STATE DB is updated. - state_wcmp_group_entries = util.get_keys( - self._p4rt_wcmp_group_obj.appl_state_db, - ( - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME - + ":" - + self._p4rt_wcmp_group_obj.TBL_NAME - ), - ) - assert len(state_wcmp_group_entries) == ( - self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() - ) - # Delete next hop. self._p4rt_nexthop_obj.remove_app_db_entry(nexthop_key) @@ -2273,14 +1813,6 @@ def test_CreateWcmpMemberForOperUpWatchportOnly(self, dvs, testlog): self._p4rt_wcmp_group_obj.TBL_NAME, ), ), - ( - self._p4rt_wcmp_group_obj.appl_state_db, - "%s:%s" - % ( - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, - self._p4rt_wcmp_group_obj.TBL_NAME, - ), - ), ( self._p4rt_wcmp_group_obj.asic_db, self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME, @@ -2387,26 +1919,6 @@ def test_CreateWcmpMemberForOperUpWatchportOnly(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # Query application state database for wcmp group entries. - state_wcmp_group_entries = util.get_keys( - self._p4rt_wcmp_group_obj.appl_state_db, - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME - + ":" - + self._p4rt_wcmp_group_obj.TBL_NAME, - ) - assert len(state_wcmp_group_entries) == ( - self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() + 1 - ) - - # Query application state database for newly created wcmp group key. - (status, fvs) = util.get_key( - self._p4rt_wcmp_group_obj.appl_state_db, - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, - wcmp_group_key, - ) - assert status == True - util.verify_attr(fvs, attr_list) - # Query ASIC database for wcmp group entries. wcmp_group_entries = util.get_keys( self._p4rt_wcmp_group_obj.asic_db, @@ -2496,19 +2008,6 @@ def test_CreateWcmpMemberForOperUpWatchportOnly(self, dvs, testlog): assert status == True assert len(fvs) == len(original_key_oid_info) + count - # Verify that APPL STATE DB is updated. - state_wcmp_group_entries = util.get_keys( - self._p4rt_wcmp_group_obj.appl_state_db, - ( - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME - + ":" - + self._p4rt_wcmp_group_obj.TBL_NAME - ), - ) - assert len(state_wcmp_group_entries) == ( - self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() - ) - # Delete next hop. self._p4rt_nexthop_obj.remove_app_db_entry(nexthop_key) @@ -2550,14 +2049,6 @@ def test_RemovePrunedWcmpGroupMember(self, dvs, testlog): self._p4rt_wcmp_group_obj.TBL_NAME, ), ), - ( - self._p4rt_wcmp_group_obj.appl_state_db, - "%s:%s" - % ( - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, - self._p4rt_wcmp_group_obj.TBL_NAME, - ), - ), ( self._p4rt_wcmp_group_obj.asic_db, self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME, @@ -2664,26 +2155,6 @@ def test_RemovePrunedWcmpGroupMember(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # Query application state database for wcmp group entries. - state_wcmp_group_entries = util.get_keys( - self._p4rt_wcmp_group_obj.appl_db, - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME - + ":" - + self._p4rt_wcmp_group_obj.TBL_NAME, - ) - assert len(state_wcmp_group_entries) == ( - self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() + 1 - ) - - # Query application state database for newly created wcmp group key. - (status, fvs) = util.get_key( - self._p4rt_wcmp_group_obj.appl_state_db, - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, - wcmp_group_key, - ) - assert status == True - util.verify_attr(fvs, attr_list) - # Query ASIC database for wcmp group entries. wcmp_group_entries = util.get_keys( self._p4rt_wcmp_group_obj.asic_db, @@ -2740,14 +2211,6 @@ def test_RemovePrunedWcmpGroupMember(self, dvs, testlog): assert status == True assert len(fvs) == len(original_key_oid_info) + count - # Verify that the next hop still exists in app state db. - (status, fvs) = util.get_key( - self._p4rt_nexthop_obj.appl_state_db, - self._p4rt_nexthop_obj.APP_DB_TBL_NAME, - nexthop_key, - ) - assert status == True - # Delete the pruned wcmp group member and try again. self._p4rt_wcmp_group_obj.remove_app_db_entry(wcmp_group_key) @@ -2757,19 +2220,6 @@ def test_RemovePrunedWcmpGroupMember(self, dvs, testlog): assert status == True assert len(fvs) == len(original_key_oid_info) + count - # Verify that APPL STATE DB is updated. - state_wcmp_group_entries = util.get_keys( - self._p4rt_wcmp_group_obj.appl_state_db, - ( - self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME - + ":" - + self._p4rt_wcmp_group_obj.TBL_NAME - ), - ) - assert len(state_wcmp_group_entries) == ( - self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() - ) - # Verify that ASIC DB is updated. wcmp_group_entries = util.get_keys( self._p4rt_wcmp_group_obj.asic_db, @@ -2828,14 +2278,6 @@ def test_NexthopWithGreTunnelCreationFailIfDependenciesAreMissing(self, dvs, tes self._p4rt_nexthop_obj.TBL_NAME, ), ), - ( - self._p4rt_nexthop_obj.appl_state_db, - "%s:%s" - % ( - self._p4rt_nexthop_obj.APP_DB_TBL_NAME, - self._p4rt_nexthop_obj.TBL_NAME, - ), - ), (self._p4rt_nexthop_obj.asic_db, self._p4rt_nexthop_obj.ASIC_DB_TBL_NAME), ) @@ -2849,14 +2291,6 @@ def test_NexthopWithGreTunnelCreationFailIfDependenciesAreMissing(self, dvs, tes self._p4rt_gre_tunnel_obj.TBL_NAME, ), ), - ( - self._p4rt_gre_tunnel_obj.appl_state_db, - "%s:%s" - % ( - self._p4rt_gre_tunnel_obj.APP_DB_TBL_NAME, - self._p4rt_gre_tunnel_obj.TBL_NAME, - ), - ), (self._p4rt_gre_tunnel_obj.asic_db, self._p4rt_gre_tunnel_obj.ASIC_DB_TBL_NAME), ) @@ -2893,16 +2327,6 @@ def test_NexthopWithGreTunnelCreationFailIfDependenciesAreMissing(self, dvs, tes self._p4rt_gre_tunnel_obj.get_original_appl_db_entries_count() + 1 ) - # Query application state database for tunnel entries. - state_tunnel_entries = util.get_keys( - self._p4rt_gre_tunnel_obj.appl_state_db, - self._p4rt_gre_tunnel_obj.APP_DB_TBL_NAME + - ":" + self._p4rt_gre_tunnel_obj.TBL_NAME, - ) - assert len(state_tunnel_entries) == ( - self._p4rt_gre_tunnel_obj.get_original_appl_state_db_entries_count() - ) - # Query ASIC database for tunnel entries. tunnel_entries = util.get_keys( self._p4rt_gre_tunnel_obj.asic_db, self._p4rt_gre_tunnel_obj.ASIC_DB_TBL_NAME @@ -2934,15 +2358,6 @@ def test_NexthopWithGreTunnelCreationFailIfDependenciesAreMissing(self, dvs, tes self._p4rt_nexthop_obj.get_original_appl_db_entries_count() + 1 ) - # Query application state database for nexthop entries. - state_nexthop_entries = util.get_keys( - self._p4rt_nexthop_obj.appl_state_db, - self._p4rt_nexthop_obj.APP_DB_TBL_NAME + ":" + self._p4rt_nexthop_obj.TBL_NAME, - ) - assert len(state_nexthop_entries) == ( - self._p4rt_nexthop_obj.get_original_appl_state_db_entries_count() - ) - # Query ASIC database for nexthop entries. nexthop_entries = util.get_keys( self._p4rt_nexthop_obj.asic_db, self._p4rt_nexthop_obj.ASIC_DB_TBL_NAME diff --git a/tests/p4rt/test_l3_admit.py b/tests/p4rt/test_l3_admit.py index 81ffdf884a..8fc3bbb8d4 100644 --- a/tests/p4rt/test_l3_admit.py +++ b/tests/p4rt/test_l3_admit.py @@ -29,11 +29,6 @@ def test_DefaultL3AdmitAddDeletePass(self, dvs, testlog): "%s:%s" % (self._p4rt_l3_admit_obj.APP_DB_TBL_NAME, self._p4rt_l3_admit_obj.TBL_NAME), ), - ( - self._p4rt_l3_admit_obj.appl_state_db, - "%s:%s" - % (self._p4rt_l3_admit_obj.APP_DB_TBL_NAME, self._p4rt_l3_admit_obj.TBL_NAME), - ), (self._p4rt_l3_admit_obj.asic_db, self._p4rt_l3_admit_obj.ASIC_DB_TBL_NAME), ) @@ -86,25 +81,6 @@ def test_DefaultL3AdmitAddDeletePass(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # Query application state database for l3 admit entries. - state_l3_admit_entries = util.get_keys( - self._p4rt_l3_admit_obj.appl_state_db, - self._p4rt_l3_admit_obj.APP_DB_TBL_NAME + - ":" + self._p4rt_l3_admit_obj.TBL_NAME, - ) - assert len(state_l3_admit_entries) == ( - self._p4rt_l3_admit_obj.get_original_appl_state_db_entries_count() + 1 - ) - - # Query application state database for newly created l3 admit key. - (status, fvs) = util.get_key( - self._p4rt_l3_admit_obj.appl_state_db, - self._p4rt_l3_admit_obj.APP_DB_TBL_NAME, - l3_admit_key, - ) - assert status == True - util.verify_attr(fvs, attr_list) - # Query ASIC database for my mac entries. asic_l3_admit_entries = util.get_keys( self._p4rt_l3_admit_obj.asic_db, self._p4rt_l3_admit_obj.ASIC_DB_TBL_NAME @@ -170,24 +146,6 @@ def test_DefaultL3AdmitAddDeletePass(self, dvs, testlog): ) assert status == False - # Query application database for route entries. - state_l3_admit_entries = util.get_keys( - self._p4rt_l3_admit_obj.appl_state_db, - self._p4rt_l3_admit_obj.APP_DB_TBL_NAME + - ":" + self._p4rt_l3_admit_obj.TBL_NAME, - ) - assert len(state_l3_admit_entries) == ( - self._p4rt_l3_admit_obj.get_original_appl_state_db_entries_count() - ) - - # Verify that the route_key no longer exists in application database. - (status, fsv) = util.get_key( - self._p4rt_l3_admit_obj.appl_state_db, - self._p4rt_l3_admit_obj.APP_DB_TBL_NAME, - l3_admit_key, - ) - assert status == False - # Query ASIC database for my mac entries. my_mac_entries = util.get_keys( self._p4rt_l3_admit_obj.asic_db, self._p4rt_l3_admit_obj.ASIC_DB_TBL_NAME @@ -216,11 +174,6 @@ def test_InvalidL3AdmitKeyFailsToCreate(self, dvs, testlog): "%s:%s" % (self._p4rt_l3_admit_obj.APP_DB_TBL_NAME, self._p4rt_l3_admit_obj.TBL_NAME), ), - ( - self._p4rt_l3_admit_obj.appl_state_db, - "%s:%s" - % (self._p4rt_l3_admit_obj.APP_DB_TBL_NAME, self._p4rt_l3_admit_obj.TBL_NAME), - ), (self._p4rt_l3_admit_obj.asic_db, self._p4rt_l3_admit_obj.ASIC_DB_TBL_NAME), ) diff --git a/tests/p4rt/test_p4rt_acl.py b/tests/p4rt/test_p4rt_acl.py index cfa1c0fb45..515354e101 100644 --- a/tests/p4rt/test_p4rt_acl.py +++ b/tests/p4rt/test_p4rt_acl.py @@ -81,12 +81,6 @@ def test_AclRulesAddUpdateDelPass(self, dvs, testlog): + ":" + self._p4rt_acl_table_definition_obj.TBL_NAME, ) - original_appl_state_acl_tables = util.get_keys( - self._p4rt_acl_table_definition_obj.appl_state_db, - self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME - + ":" - + self._p4rt_acl_table_definition_obj.TBL_NAME, - ) original_asic_acl_tables = util.get_keys( self._p4rt_acl_table_definition_obj.asic_db, self._p4rt_acl_table_definition_obj.ASIC_DB_TBL_NAME, @@ -241,26 +235,6 @@ def test_AclRulesAddUpdateDelPass(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # query application state database for ACL tables - state_acl_tables = util.get_keys( - self._p4rt_acl_table_definition_obj.appl_state_db, - self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME - + ":" - + self._p4rt_acl_table_definition_obj.TBL_NAME, - ) - assert len(state_acl_tables) == len(original_appl_state_acl_tables) + 1 - - # query application state database for newly created ACL table - (status, fvs) = util.get_key( - self._p4rt_acl_table_definition_obj.appl_state_db, - self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME - + ":" - + self._p4rt_acl_table_definition_obj.TBL_NAME, - table_name, - ) - assert status == True - util.verify_attr(fvs, attr_list) - asic_udf_matches = util.get_keys( self._p4rt_udf_match_obj.asic_db, self._p4rt_udf_match_obj.ASIC_DB_TBL_NAME ) @@ -422,10 +396,6 @@ def test_AclRulesAddUpdateDelPass(self, dvs, testlog): self._p4rt_acl_rule_obj.appl_db, self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, ) - original_appl_state_acl_rules = util.get_keys( - self._p4rt_acl_rule_obj.appl_state_db, - self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, - ) original_asic_acl_rules = util.get_keys( self._p4rt_acl_rule_obj.asic_db, self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME ) @@ -480,22 +450,6 @@ def test_AclRulesAddUpdateDelPass(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # query application state database for ACL rules - state_acl_rules = util.get_keys( - self._p4rt_acl_rule_obj.appl_state_db, - self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, - ) - assert len(state_acl_rules) == len(original_appl_state_acl_rules) + 1 - - # query application state database for newly created ACL rule - (status, fvs) = util.get_key( - self._p4rt_acl_rule_obj.appl_state_db, - self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME, - table_name_with_rule_key1, - ) - assert status == True - util.verify_attr(fvs, attr_list) - # query ASIC database for ACL counters acl_asic_counters = util.get_keys( self._p4rt_acl_counter_obj.asic_db, @@ -653,22 +607,6 @@ def test_AclRulesAddUpdateDelPass(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # query application state database for ACL rules - state_acl_rules = util.get_keys( - self._p4rt_acl_rule_obj.appl_state_db, - self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, - ) - assert len(state_acl_rules) == len(original_appl_state_acl_rules) + 1 - - # query application state database for updated ACL rule - (status, fvs) = util.get_key( - self._p4rt_acl_rule_obj.appl_state_db, - self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME, - table_name_with_rule_key1, - ) - assert status == True - util.verify_attr(fvs, attr_list) - # query ASIC database for ACL counters acl_asic_counters = util.get_keys( self._p4rt_acl_counter_obj.asic_db, @@ -827,22 +765,6 @@ def test_AclRulesAddUpdateDelPass(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # query application state database for ACL rules - state_acl_rules = util.get_keys( - self._p4rt_acl_rule_obj.appl_state_db, - self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, - ) - assert len(state_acl_rules) == len(original_appl_state_acl_rules) + 2 - - # query application state database for newly created ACL rule - (status, fvs) = util.get_key( - self._p4rt_acl_rule_obj.appl_state_db, - self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME, - table_name_with_rule_key2, - ) - assert status == True - util.verify_attr(fvs, attr_list) - # query ASIC database for ACL counters acl_asic_counters = util.get_keys( self._p4rt_acl_counter_obj.asic_db, @@ -1025,22 +947,6 @@ def test_AclRulesAddUpdateDelPass(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # query application state database for ACL rules - state_acl_rules = util.get_keys( - self._p4rt_acl_rule_obj.appl_state_db, - self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, - ) - assert len(state_acl_rules) == len(original_appl_state_acl_rules) + 3 - - # query application state database for newly created ACL rule - (status, fvs) = util.get_key( - self._p4rt_acl_rule_obj.appl_state_db, - self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME, - table_name_with_rule_key3, - ) - assert status == True - util.verify_attr(fvs, attr_list) - # query ASIC database for ACL counters acl_asic_counters = util.get_keys( self._p4rt_acl_counter_obj.asic_db, @@ -1136,21 +1042,6 @@ def test_AclRulesAddUpdateDelPass(self, dvs, testlog): ) assert status == False - # query application state database for ACL rules - state_acl_rules = util.get_keys( - self._p4rt_acl_rule_obj.appl_state_db, - self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, - ) - assert len(state_acl_rules) == len(original_appl_state_acl_rules) + 2 - - # verify that the ACL rule no longer exists in application state database - (status, fvs) = util.get_key( - self._p4rt_acl_rule_obj.appl_state_db, - self._p4rt_acl_rule_obj.APP_DB_TBL_NAME, - table_name_with_rule_key3, - ) - assert status == False - # query ASIC database for ACL rules acl_rules = util.get_keys( self._p4rt_acl_rule_obj.asic_db, self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME @@ -1194,21 +1085,6 @@ def test_AclRulesAddUpdateDelPass(self, dvs, testlog): ) assert status == False - # query application state database for ACL rules - state_acl_rules = util.get_keys( - self._p4rt_acl_rule_obj.appl_state_db, - self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, - ) - assert len(state_acl_rules) == len(original_appl_state_acl_rules) + 1 - - # verify that the ACL rule no longer exists in application state database - (status, fvs) = util.get_key( - self._p4rt_acl_rule_obj.appl_state_db, - self._p4rt_acl_rule_obj.APP_DB_TBL_NAME, - table_name_with_rule_key1, - ) - assert status == False - # query ASIC database for ACL rules acl_rules = util.get_keys( self._p4rt_acl_rule_obj.asic_db, self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME @@ -1260,21 +1136,6 @@ def test_AclRulesAddUpdateDelPass(self, dvs, testlog): ) assert status == False - # query application state database for ACL rules - state_acl_rules = util.get_keys( - self._p4rt_acl_rule_obj.appl_state_db, - self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, - ) - assert len(state_acl_rules) == len(original_appl_state_acl_rules) - - # verify that the ACL rule no longer exists in application state database - (status, fvs) = util.get_key( - self._p4rt_acl_rule_obj.appl_state_db, - self._p4rt_acl_rule_obj.APP_DB_TBL_NAME, - table_name_with_rule_key2, - ) - assert status == False - # query ASIC database for ACL rules acl_rules = util.get_keys( self._p4rt_acl_rule_obj.asic_db, self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME @@ -1333,23 +1194,6 @@ def test_AclRulesAddUpdateDelPass(self, dvs, testlog): ) assert status == False - # query application state database for ACL tables - state_acl_tables = util.get_keys( - self._p4rt_acl_table_definition_obj.appl_state_db, - self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME - + ":" - + self._p4rt_acl_table_definition_obj.TBL_NAME, - ) - assert len(state_acl_tables) == len(original_appl_state_acl_tables) - - # verify that the ACL table no longer exists in application state database - (status, fvs) = util.get_key( - self._p4rt_acl_table_definition_obj.appl_state_db, - self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME, - self._p4rt_acl_table_definition_obj.TBL_NAME + ":" + table_name, - ) - assert status == False - # query ASIC database for ACL tables acl_tables = util.get_keys( self._p4rt_acl_table_definition_obj.asic_db, @@ -1376,10 +1220,6 @@ def test_AclRuleAddWithoutTableDefinitionFails(self, dvs, testlog): self._p4rt_acl_rule_obj.appl_db, self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, ) - original_appl_state_acl_rules = util.get_keys( - self._p4rt_acl_rule_obj.appl_state_db, - self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, - ) original_asic_acl_rules = util.get_keys( self._p4rt_acl_rule_obj.asic_db, self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME ) @@ -1428,13 +1268,6 @@ def test_AclRuleAddWithoutTableDefinitionFails(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # query application state database for ACL rules - state_acl_rules = util.get_keys( - self._p4rt_acl_rule_obj.appl_state_db, - self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, - ) - assert len(state_acl_rules) == len(original_appl_state_acl_rules) - # query ASIC database for ACL rules acl_asic_rules = util.get_keys( self._p4rt_acl_rule_obj.asic_db, self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME diff --git a/tests/p4rt/test_p4rt_mirror.py b/tests/p4rt/test_p4rt_mirror.py index c1327370c3..1584d9961d 100644 --- a/tests/p4rt/test_p4rt_mirror.py +++ b/tests/p4rt/test_p4rt_mirror.py @@ -56,9 +56,6 @@ def test_MirrorSessionAddModifyAndDelete(self, dvs, testlog): original_appl_mirror_entries = util.get_keys( self._p4rt_mirror_session_wrapper.appl_db, self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME + ":" + self._p4rt_mirror_session_wrapper.TBL_NAME) - original_appl_state_mirror_entries = util.get_keys( - self._p4rt_mirror_session_wrapper.appl_state_db, - self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME + ":" + self._p4rt_mirror_session_wrapper.TBL_NAME) original_asic_mirror_entries = util.get_keys( self._p4rt_mirror_session_wrapper.asic_db, self._p4rt_mirror_session_wrapper.ASIC_DB_TBL_NAME) @@ -108,20 +105,6 @@ def test_MirrorSessionAddModifyAndDelete(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list_in_app_db) - # Query application state database for mirror entries - appl_state_mirror_entries = util.get_keys( - self._p4rt_mirror_session_wrapper.appl_state_db, - self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME + ":" + self._p4rt_mirror_session_wrapper.TBL_NAME) - assert len(appl_state_mirror_entries) == len( - original_appl_state_mirror_entries) + 1 - - # Query application state database for newly created mirror key - (status, fvs) = util.get_key(self._p4rt_mirror_session_wrapper.appl_state_db, - self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME, - mirror_session_key) - assert status == True - util.verify_attr(fvs, attr_list_in_app_db) - # Query ASIC database for mirror entries asic_mirror_entries = util.get_keys(self._p4rt_mirror_session_wrapper.asic_db, self._p4rt_mirror_session_wrapper.ASIC_DB_TBL_NAME) @@ -180,13 +163,6 @@ def test_MirrorSessionAddModifyAndDelete(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list_in_app_db) - # Query application state database for the modified mirror key - (status, fvs) = util.get_key(self._p4rt_mirror_session_wrapper.appl_state_db, - self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME, - mirror_session_key) - assert status == True - util.verify_attr(fvs, attr_list_in_app_db) - # Query ASIC DB about the modified mirror session. expected_attr_list_in_asic_db[9] = ( self._p4rt_mirror_session_wrapper.SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS, new_dst_mac) @@ -214,19 +190,6 @@ def test_MirrorSessionAddModifyAndDelete(self, dvs, testlog): mirror_session_key) assert status == False - # Query application state database for mirror entries - appl_state_mirror_entries = util.get_keys( - self._p4rt_mirror_session_wrapper.appl_state_db, - self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME + ":" + self._p4rt_mirror_session_wrapper.TBL_NAME) - assert len(appl_state_mirror_entries) == len( - original_appl_state_mirror_entries) - - # Query application state database for the deleted mirror key - (status, fvs) = util.get_key(self._p4rt_mirror_session_wrapper.appl_state_db, - self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME, - mirror_session_key) - assert status == False - # Query ASIC database for mirror entries asic_mirror_entries = util.get_keys(self._p4rt_mirror_session_wrapper.asic_db, self._p4rt_mirror_session_wrapper.ASIC_DB_TBL_NAME) diff --git a/tests/p4rt/test_viplb.py b/tests/p4rt/test_viplb.py index fbb51ea48d..fd5e90e05d 100644 --- a/tests/p4rt/test_viplb.py +++ b/tests/p4rt/test_viplb.py @@ -69,9 +69,6 @@ def test_VIPv4LBWithGoodNexthopAddUpdateDeletePass(self, dvs, testlog): db_list = ((self._p4rt_viplb_obj.appl_db, "%s:%s" % (self._p4rt_viplb_obj.APP_DB_TBL_NAME, self._p4rt_viplb_obj.TBL_NAME)), - (self._p4rt_viplb_obj.appl_state_db, - "%s:%s" % (self._p4rt_viplb_obj.APP_DB_TBL_NAME, - self._p4rt_viplb_obj.TBL_NAME)), (self._p4rt_viplb_obj.asic_db, self._p4rt_viplb_obj.ASIC_DB_TBL_NAME)) self._p4rt_viplb_obj.get_original_redis_entries(db_list) @@ -150,22 +147,6 @@ def test_VIPv4LBWithGoodNexthopAddUpdateDeletePass(self, dvs, testlog): assert status == True util.verify_attr(fvs, attr_list) - # Query application state database for viplb entries. - state_viplb_entries = util.get_keys( - self._p4rt_viplb_obj.appl_state_db, - self._p4rt_viplb_obj.APP_DB_TBL_NAME + ":" + self._p4rt_viplb_obj.TBL_NAME) - assert len(state_viplb_entries) == ( - self._p4rt_viplb_obj.get_original_appl_state_db_entries_count() + 1 - ) - - # Query application state database for newly created viplb key. - (status, fvs) = util.get_key(self._p4rt_viplb_obj.appl_state_db, - self._p4rt_viplb_obj.APP_DB_TBL_NAME, - viplb_key) - assert status == True - util.verify_attr(fvs, attr_list) - - # get programmable_object_oid of newly created viplb viplb_oid = self._p4rt_viplb_obj.get_newly_created_programmable_object_oid() assert viplb_oid is not None diff --git a/tests/p4rt/util.py b/tests/p4rt/util.py index ac46a48587..7959aecb50 100644 --- a/tests/p4rt/util.py +++ b/tests/p4rt/util.py @@ -49,7 +49,8 @@ def prepend_param_field(param_field): def verify_response(consumer, key, attr_list, status, err_message = "SWSS_RC_SUCCESS"): """ Verifies a response.""" - consumer.readData() + if consumer.peek() <= 0: + consumer.readData() (op, data, values) = consumer.pop() assert data == key assert op == status From 84ce1a7c9cf50bf6719d710f3ee3e5286998bf8b Mon Sep 17 00:00:00 2001 From: Rajkumar-Marvell <54936542+rajkumar38@users.noreply.github.com> Date: Thu, 16 May 2024 21:28:31 +0530 Subject: [PATCH 30/34] [mclag] Use port-isolation feature for Marvell platforms. (#3151) What I did MCLAG: Use port-isolation functionality instead of ACLs for Marvell platforms Why I did it Minimize the impact of ACL scaling in marvell platforms. --- mclagsyncd/mclaglink.cpp | 3 ++- mclagsyncd/mclaglink.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mclagsyncd/mclaglink.cpp b/mclagsyncd/mclaglink.cpp index b8040c1646..3cd224ce50 100644 --- a/mclagsyncd/mclaglink.cpp +++ b/mclagsyncd/mclaglink.cpp @@ -192,7 +192,8 @@ void MclagLink::setPortIsolate(char *msg) static const unordered_set supported { BRCM_PLATFORM_SUBSTRING, BFN_PLATFORM_SUBSTRING, - CTC_PLATFORM_SUBSTRING + CTC_PLATFORM_SUBSTRING, + MRVL_PLATFORM_SUBSTRING }; const char *platform = getenv("platform"); diff --git a/mclagsyncd/mclaglink.h b/mclagsyncd/mclaglink.h index 09129fd88f..1ff006968b 100644 --- a/mclagsyncd/mclaglink.h +++ b/mclagsyncd/mclaglink.h @@ -54,6 +54,7 @@ #define BRCM_PLATFORM_SUBSTRING "broadcom" #define BFN_PLATFORM_SUBSTRING "barefoot" #define CTC_PLATFORM_SUBSTRING "centec" +#define MRVL_PLATFORM_SUBSTRING "marvell" using namespace std; From 536f43a93900c4d684f9defea922d495b6157be9 Mon Sep 17 00:00:00 2001 From: Utpal <48428404+utpalkantpintoo@users.noreply.github.com> Date: Sat, 18 May 2024 22:09:00 +0530 Subject: [PATCH 31/34] [Orchagent] Recursive nexthop group enhancement (#3105) * What I did: Implemented recursive nexthop group enhancement in Orchagent (NhgOrch). They have been proposed in: https://github.com/sonic-net/SONiC/pull/1636 Why I did it: These changes are required to handle a new field - "nexthop_group" in the App DB NEXT_HOP_GROUP_TABLE. Such nexthop groups are called recursive nexthop groups. This field contains the list of member (singleton) nexthop groups. Such recursive nexthop groups are represented by NEXT_HOP_GROUP objects. * What I did: Implemented recursive nexthop group enhancement in Orchagent (NhgOrch). They have been proposed in: https://github.com/sonic-net/SONiC/pull/1636 Why I did it: These changes are required to handle a new field - "nexthop_group" in the App DB NEXT_HOP_GROUP_TABLE. Such nexthop groups are called recursive nexthop groups. This field contains the list of member (singleton) nexthop groups. Such recursive nexthop groups are represented by NEXT_HOP_GROUP objects. * What I did: Implemented recursive nexthop group enhancement in Orchagent (NhgOrch). They have been proposed in: https://github.com/sonic-net/SONiC/pull/1636 Why I did it: These changes are required to handle a new field - "nexthop_group" in the App DB NEXT_HOP_GROUP_TABLE. Such nexthop groups are called recursive nexthop groups. This field contains the list of member (singleton) nexthop groups. Such recursive nexthop groups are represented by NEXT_HOP_GROUP objects. * What I did: Implemented recursive nexthop group enhancement in Orchagent (NhgOrch). They have been proposed in: https://github.com/sonic-net/SONiC/pull/1636 Why I did it: These changes are required to handle a new field - "nexthop_group" in the App DB NEXT_HOP_GROUP_TABLE. Such nexthop groups are called recursive nexthop groups. This field contains the list of member (singleton) nexthop groups. Such recursive nexthop groups are represented by NEXT_HOP_GROUP objects. * Addressed review comments --- orchagent/nhgorch.cpp | 190 +++++++++++++++++++++++++++++++++++++----- orchagent/nhgorch.h | 9 +- tests/test_nhg.py | 78 ++++++++++++++++- 3 files changed, 253 insertions(+), 24 deletions(-) diff --git a/orchagent/nhgorch.cpp b/orchagent/nhgorch.cpp index cefc2efbb1..1e62547b41 100644 --- a/orchagent/nhgorch.cpp +++ b/orchagent/nhgorch.cpp @@ -8,6 +8,7 @@ extern sai_object_id_t gSwitchId; +extern IntfsOrch *gIntfsOrch; extern NeighOrch *gNeighOrch; extern RouteOrch *gRouteOrch; extern NhgOrch *gNhgOrch; @@ -58,6 +59,8 @@ void NhgOrch::doTask(Consumer& consumer) string aliases; string weights; string mpls_nhs; + string nhgs; + bool is_recursive = false; /* Get group's next hop IPs and aliases */ for (auto i : kfvFieldsValues(t)) @@ -73,24 +76,102 @@ void NhgOrch::doTask(Consumer& consumer) if (fvField(i) == "mpls_nh") mpls_nhs = fvValue(i); - } - /* Split ips and alaises strings into vectors of tokens. */ + if (fvField(i) == "nexthop_group") + { + nhgs = fvValue(i); + if (!nhgs.empty()) + is_recursive = true; + } + } + /* A NHG should not have both regular(ip/alias) and recursive fields */ + if (is_recursive && (!ips.empty() || !aliases.empty())) + { + SWSS_LOG_ERROR("Nexthop group %s has both regular(ip/alias) and recursive fields", index.c_str()); + it = consumer.m_toSync.erase(it); + continue; + } + /* Split ips and aliases strings into vectors of tokens. */ vector ipv = tokenize(ips, ','); vector alsv = tokenize(aliases, ','); vector mpls_nhv = tokenize(mpls_nhs, ','); + vector nhgv = tokenize(nhgs, NHG_DELIMITER); /* Create the next hop group key. */ string nhg_str; - for (uint32_t i = 0; i < ipv.size(); i++) + /* Keeps track of any non-existing member of a recursive nexthop group */ + bool non_existent_member = false; + + if (is_recursive) { - if (i) nhg_str += NHG_DELIMITER; - if (!mpls_nhv.empty() && mpls_nhv[i] != "na") + SWSS_LOG_INFO("Adding recursive nexthop group %s with %s", index.c_str(), nhgs.c_str()); + + /* Reset the "nexthop_group" field and update it with only the existing members */ + nhgs = ""; + + /* Check if any of the members are a recursive or temporary nexthop group */ + bool invalid_member = false; + + for (auto& nhgm : nhgv) + { + const auto& nhgm_it = m_syncdNextHopGroups.find(nhgm); + if (nhgm_it == m_syncdNextHopGroups.end()) + { + SWSS_LOG_INFO("Member nexthop group %s in parent nhg %s not ready", + nhgm.c_str(), index.c_str()); + + non_existent_member = true; + continue; + } + if ((nhgm_it->second.nhg) && + (nhgm_it->second.nhg->isRecursive() || nhgm_it->second.nhg->isTemp())) + { + SWSS_LOG_ERROR("Invalid member nexthop group %s in parent nhg %s", + nhgm.c_str(), index.c_str()); + + invalid_member = true; + break; + } + /* Keep only the members which exist in the local cache */ + if (nhgs.empty()) + nhgs = nhgm; + else + nhgs += NHG_DELIMITER + nhgm; + } + if (invalid_member) { - nhg_str += mpls_nhv[i] + LABELSTACK_DELIMITER; + it = consumer.m_toSync.erase(it); + continue; + } + /* If no members are present */ + if (nhgs.empty()) + { + it++; + continue; + } + + /* Form nexthopgroup key with the nexthopgroup keys of available members */ + nhgv = tokenize(nhgs, NHG_DELIMITER); + + for (uint32_t i = 0; i < nhgv.size(); i++) + { + if (i) nhg_str += NHG_DELIMITER; + + nhg_str += m_syncdNextHopGroups.at(nhgv[i]).nhg->getKey().to_string(); + } + } + else + { + for (uint32_t i = 0; i < ipv.size(); i++) + { + if (i) nhg_str += NHG_DELIMITER; + if (!mpls_nhv.empty() && mpls_nhv[i] != "na") + { + nhg_str += mpls_nhv[i] + LABELSTACK_DELIMITER; + } + nhg_str += ipv[i] + NH_DELIMITER + alsv[i]; } - nhg_str += ipv[i] + NH_DELIMITER + alsv[i]; } NextHopGroupKey nhg_key = NextHopGroupKey(nhg_str, weights); @@ -98,6 +179,8 @@ void NhgOrch::doTask(Consumer& consumer) /* If the group does not exist, create one. */ if (nhg_it == m_syncdNextHopGroups.end()) { + SWSS_LOG_INFO("Create nexthop group %s with %s", index.c_str(), nhg_str.c_str()); + /* * If we've reached the NHG limit, we're going to create a temporary * group, represented by one of it's NH only until we have @@ -133,10 +216,21 @@ void NhgOrch::doTask(Consumer& consumer) else { auto nhg = std::make_unique(nhg_key, false); - success = nhg->sync(); + /* + * Mark the nexthop group as recursive so as to create a + * nexthop group object even if it has just one available path + */ + nhg->setRecursive(is_recursive); + + success = nhg->sync(); if (success) { + /* Keep the msg in loop if any member path is not available yet */ + if (is_recursive && non_existent_member) + { + success = false; + } m_syncdNextHopGroups.emplace(index, NhgEntry(std::move(nhg))); } } @@ -144,6 +238,8 @@ void NhgOrch::doTask(Consumer& consumer) /* If the group exists, update it. */ else { + SWSS_LOG_INFO("Update nexthop group %s with %s", index.c_str(), nhg_str.c_str()); + const auto& nhg_ptr = nhg_it->second.nhg; /* @@ -216,6 +312,12 @@ void NhgOrch::doTask(Consumer& consumer) else { success = nhg_ptr->update(nhg_key); + + /* Keep the msg in loop if any member path is not available yet */ + if (is_recursive && non_existent_member) + { + success = false; + } } } } @@ -367,7 +469,11 @@ sai_object_id_t NextHopGroupMember::getNhId() const sai_object_id_t nh_id = SAI_NULL_OBJECT_ID; - if (gNeighOrch->hasNextHop(m_key)) + if (m_key.isIntfNextHop()) + { + nh_id = gIntfsOrch->getRouterIntfsId(m_key.alias); + } + else if (gNeighOrch->hasNextHop(m_key)) { nh_id = gNeighOrch->getNextHopId(m_key); } @@ -484,7 +590,7 @@ NextHopGroupMember::~NextHopGroupMember() * Params: IN key - The next hop group's key. * Returns: Nothing. */ -NextHopGroup::NextHopGroup(const NextHopGroupKey& key, bool is_temp) : NhgCommon(key), m_is_temp(is_temp) +NextHopGroup::NextHopGroup(const NextHopGroupKey& key, bool is_temp) : NhgCommon(key), m_is_temp(is_temp), m_is_recursive(false) { SWSS_LOG_ENTER(); @@ -506,6 +612,7 @@ NextHopGroup& NextHopGroup::operator=(NextHopGroup&& nhg) SWSS_LOG_ENTER(); m_is_temp = nhg.m_is_temp; + m_is_recursive = nhg.m_is_recursive; NhgCommon::operator=(std::move(nhg)); @@ -532,11 +639,8 @@ bool NextHopGroup::sync() return true; } - /* - * If the group is temporary, the group ID will be the only member's NH - * ID. - */ - if (m_is_temp) + /* If the group is non-recursive with single member, the group ID will be the only member's NH ID */ + if (!isRecursive() && (m_members.size() == 1)) { const NextHopGroupMember& nhgm = m_members.begin()->second; sai_object_id_t nhid = nhgm.getNhId(); @@ -549,6 +653,12 @@ bool NextHopGroup::sync() else { m_id = nhid; + + auto nh_key = nhgm.getKey(); + if (nh_key.isIntfNextHop()) + gIntfsOrch->increaseRouterIntfsRefCount(nh_key.alias); + else + gNeighOrch->increaseNextHopRefCount(nh_key); } } else @@ -663,9 +773,21 @@ bool NextHopGroup::remove() { SWSS_LOG_ENTER(); - // If the group is temporary, there is nothing to be done - just reset the ID. - if (m_is_temp) + if (!isSynced()) { + return true; + } + // If the group is temporary or non-recursive, update the neigh or rif ref-count and reset the ID. + if (m_is_temp || + (!isRecursive() && m_members.size() == 1)) + { + const NextHopGroupMember& nhgm = m_members.begin()->second; + auto nh_key = nhgm.getKey(); + if (nh_key.isIntfNextHop()) + gIntfsOrch->decreaseRouterIntfsRefCount(nh_key.alias); + else + gNeighOrch->decreaseNextHopRefCount(nh_key); + m_id = SAI_NULL_OBJECT_ID; return true; } @@ -687,6 +809,9 @@ bool NextHopGroup::syncMembers(const std::set& nh_keys) { SWSS_LOG_ENTER(); + /* This method should not be called for single-membered non-recursive nexthop groups */ + assert(isRecursive() || (m_members.size() > 1)); + ObjectBulker nextHopGroupMemberBulker(sai_next_hop_group_api, gSwitchId, gMaxBulkSize); /* @@ -776,6 +901,23 @@ bool NextHopGroup::update(const NextHopGroupKey& nhg_key) { SWSS_LOG_ENTER(); + if (!isSynced() || + (!isRecursive() && (m_members.size() == 1 || nhg_key.getSize() == 1))) + { + bool was_synced = isSynced(); + bool was_temp = isTemp(); + *this = NextHopGroup(nhg_key, false); + + /* + * For temporary nexthop group being updated, set the recursive flag + * as it is expected to get promoted to multiple NHG + */ + setRecursive(was_temp); + + /* Sync the group only if it was synced before. */ + return (was_synced ? sync() : true); + } + /* Update the key. */ m_key = nhg_key; @@ -891,7 +1033,12 @@ bool NextHopGroup::validateNextHop(const NextHopKey& nh_key) { SWSS_LOG_ENTER(); - return syncMembers({nh_key}); + if (isRecursive() || (m_members.size() > 1)) + { + return syncMembers({nh_key}); + } + + return true; } /* @@ -905,5 +1052,10 @@ bool NextHopGroup::invalidateNextHop(const NextHopKey& nh_key) { SWSS_LOG_ENTER(); - return removeMembers({nh_key}); + if (isRecursive() || (m_members.size() > 1)) + { + return removeMembers({nh_key}); + } + + return true; } diff --git a/orchagent/nhgorch.h b/orchagent/nhgorch.h index 225d3ffaf2..d8a92e6131 100644 --- a/orchagent/nhgorch.h +++ b/orchagent/nhgorch.h @@ -54,7 +54,7 @@ class NextHopGroup : public NhgCommon& nh_keys) override; diff --git a/tests/test_nhg.py b/tests/test_nhg.py index 6647a8d0de..b9e125f760 100644 --- a/tests/test_nhg.py +++ b/tests/test_nhg.py @@ -84,6 +84,8 @@ def get_nhg_map_id(self, nhg_map_index): # Create a NHG fvs = swsscommon.FieldValuePairs([('nexthop', '10.0.0.1'), ('ifname', 'Ethernet0')]) + nhg_ps.set('_testnhg', fvs) + fvs = swsscommon.FieldValuePairs([('nexthop_group', '_testnhg')]) nhg_ps.set('testnhg', fvs) # Add a CBF NHG pointing to the given map @@ -98,6 +100,7 @@ def get_nhg_map_id(self, nhg_map_index): # Remove the added NHGs cbf_nhg_ps._del('testcbfnhg') nhg_ps._del('testnhg') + nhg_ps._del('_testnhg') self.asic_db.wait_for_n_keys(self.ASIC_NHG_STR, asic_nhgs_count) return None @@ -111,6 +114,7 @@ def get_nhg_map_id(self, nhg_map_index): # Remove the added NHGs cbf_nhg_ps._del('testcbfnhg') nhg_ps._del('testnhg') + nhg_ps._del('_testnhg') self.asic_db.wait_for_n_keys(self.ASIC_NHG_STR, asic_nhgs_count) return nhg_map_id @@ -1546,6 +1550,67 @@ def create_route_inexistent_nhg_test(): self.asic_db.wait_for_n_keys(self.ASIC_NHGM_STR, self.asic_nhgms_count) def test_nhgorch_nh_group(self, dvs, testlog): + # Test scenario: + # - create recursive nhg - rec_grp1 with two members - grp1 and grp2 only one of which exists + # - create singleton nhg grp2 and check if the rec_grp1 is updated with both the members + # - create a recursive nhg - rec_grp2 with another recursive nhg - rec_grp1 as member. Assert that the nhg is not created. + def create_recursive_nhg_test(): + # create next hop group in APPL DB + fvs = swsscommon.FieldValuePairs([('nexthop', '10.0.0.1'), ('ifname', 'Ethernet0')]) + self.nhg_ps.set("grp1", fvs) + + # create a recursive nexthop group with two members + fvs = swsscommon.FieldValuePairs([('nexthop_group', 'grp1,grp2')]) + self.nhg_ps.set("rec_grp1", fvs) + + # check if group was propagated to ASIC DB with the existing member + self.asic_db.wait_for_n_keys(self.ASIC_NHG_STR, self.asic_nhgs_count + 1) + assert self.nhg_exists('rec_grp1') + + # check if the existing member was propagated to ASIC DB + self.asic_db.wait_for_n_keys(self.ASIC_NHGM_STR, self.asic_nhgms_count + 1) + assert len(self.get_nhgm_ids('rec_grp1')) == 1 + + # add another singleton nexthop group - grp2 + fvs = swsscommon.FieldValuePairs([('nexthop', '10.0.0.3'), ('ifname', 'Ethernet4')]) + self.nhg_ps.set("grp2", fvs) + + # check if both the members were propagated to ASIC DB + self.asic_db.wait_for_n_keys(self.ASIC_NHGM_STR, self.asic_nhgms_count + 2) + assert len(self.get_nhgm_ids('rec_grp1')) == 2 + + # update the recursive nexthop group with another member not yet existing + fvs = swsscommon.FieldValuePairs([('nexthop_group', 'grp1,grp2,grp3')]) + self.nhg_ps.set("rec_grp1", fvs) + + # check if only two members were propagated to ASIC DB + self.asic_db.wait_for_n_keys(self.ASIC_NHGM_STR, self.asic_nhgms_count + 2) + assert len(self.get_nhgm_ids('rec_grp1')) == 2 + + # add another singleton nexthop group - grp3 + fvs = swsscommon.FieldValuePairs([('nexthop', '10.0.0.5'), ('ifname', 'Ethernet8')]) + self.nhg_ps.set("grp3", fvs) + + # check if all members were propagated to ASIC DB + self.asic_db.wait_for_n_keys(self.ASIC_NHGM_STR, self.asic_nhgms_count + 3) + assert len(self.get_nhgm_ids('rec_grp1')) == 3 + + # create a recursive nhg with another recursive nhg as member + fvs = swsscommon.FieldValuePairs([('nexthop_group', 'rec_grp1')]) + self.nhg_ps.set("rec_grp2", fvs) + + # check that the group was not propagated to ASIC DB + self.asic_db.wait_for_n_keys(self.ASIC_NHG_STR, self.asic_nhgs_count + 1) + assert not self.nhg_exists('rec_grp2') + + self.nhg_ps._del("rec_grp2") + self.nhg_ps._del("rec_grp1") + self.nhg_ps._del("grp1") + self.nhg_ps._del("grp2") + self.nhg_ps._del("grp3") + self.asic_db.wait_for_n_keys(self.ASIC_NHG_STR, self.asic_nhgs_count) + self.asic_db.wait_for_n_keys(self.ASIC_NHGM_STR, self.asic_nhgms_count) + # Test scenario: # - create NHG 'group1' and assert it is being added to ASIC DB along with its members def create_nhg_test(): @@ -1705,8 +1770,8 @@ def update_nhgm_count_test(): # Update the group to one NH only fvs = swsscommon.FieldValuePairs([('nexthop', '10.0.0.1'), ("ifname", "Ethernet0")]) self.nhg_ps.set("group1", fvs) - self.asic_db.wait_for_n_keys(self.ASIC_NHGM_STR, self.asic_nhgms_count + 1) - assert len(self.get_nhgm_ids('group1')) == 1 + self.asic_db.wait_for_n_keys(self.ASIC_NHGM_STR, self.asic_nhgms_count) + assert len(self.get_nhgm_ids('group1')) == 0 # Update the group to 2 NHs fvs = swsscommon.FieldValuePairs([('nexthop', '10.0.0.1,10.0.0.3'), ("ifname", "Ethernet0,Ethernet4")]) @@ -1716,6 +1781,7 @@ def update_nhgm_count_test(): self.init_test(dvs, 4) + create_recursive_nhg_test() create_nhg_test() create_route_nhg_test() link_flap_test() @@ -1838,9 +1904,11 @@ def data_validation_test(): # - update the CBF NHG reordering the members and assert the new details match def update_cbf_nhg_members_test(): # Create a NHG with a single next hop - fvs = swsscommon.FieldValuePairs([('nexthop', '10.0.0.1'), - ("ifname", "Ethernet0")]) + fvs = swsscommon.FieldValuePairs([('nexthop', '10.0.0.1'), ('ifname', 'Ethernet0')]) + self.nhg_ps.set("_group3", fvs) + fvs = swsscommon.FieldValuePairs([('nexthop_group','_group3')]) self.nhg_ps.set("group3", fvs) + self.asic_db.wait_for_n_keys(self.ASIC_NHG_STR, self.asic_nhgs_count + 3) # Create a CBF NHG @@ -2035,6 +2103,8 @@ def create_cbf_invalid_nhg_map_test(): self.cbf_nhg_ps._del('cbfgroup1') self.nhg_ps._del('group2') self.nhg_ps._del('group3') + self.nhg_ps._del('_group3') + self.asic_db.wait_for_n_keys(self.ASIC_NHG_STR, self.asic_nhgs_count) self.asic_db.wait_for_n_keys(self.ASIC_NHGM_STR, self.asic_nhgms_count) From 9e80dc821fbbc4f41056edf1abbefcd0ba3cb92b Mon Sep 17 00:00:00 2001 From: noaOrMlnx <58519608+noaOrMlnx@users.noreply.github.com> Date: Mon, 20 May 2024 18:49:15 +0300 Subject: [PATCH 32/34] Update setHostTxReady() to receive Port instead of portId (#3133) What I did Update the call to setHostTxReady() to receive Port instead of port_id. Why I did it So we won't need to call getPort() inside the function, and we will be able to call setHostTxReady from within port initialization. --- orchagent/portsorch.cpp | 40 +++++++++++++++++++--------------------- orchagent/portsorch.h | 2 +- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 429fb3d198..09e80ec651 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -1459,7 +1459,7 @@ void PortsOrch::initHostTxReadyState(Port &port) if (hostTxReady.empty()) { - setHostTxReady(port.m_port_id, "false"); + setHostTxReady(port, "false"); SWSS_LOG_NOTICE("initialize host_tx_ready as false for port %s", port.m_alias.c_str()); } @@ -1479,7 +1479,7 @@ bool PortsOrch::setPortAdminStatus(Port &port, bool state) /* Update the host_tx_ready to false before setting admin_state, when admin state is false */ if (!state && !m_cmisModuleAsicSyncSupported) { - setHostTxReady(port.m_port_id, "false"); + setHostTxReady(port, "false"); SWSS_LOG_NOTICE("Set admin status DOWN host_tx_ready to false for port %s", port.m_alias.c_str()); } @@ -1493,7 +1493,7 @@ bool PortsOrch::setPortAdminStatus(Port &port, bool state) if (!m_cmisModuleAsicSyncSupported) { - setHostTxReady(port.m_port_id, "false"); + setHostTxReady(port, "false"); } task_process_status handle_status = handleSaiSetStatus(SAI_API_PORT, status); if (handle_status != task_success) @@ -1505,7 +1505,7 @@ bool PortsOrch::setPortAdminStatus(Port &port, bool state) bool gbstatus = setGearboxPortsAttr(port, SAI_PORT_ATTR_ADMIN_STATE, &state); if (gbstatus != true && !m_cmisModuleAsicSyncSupported) { - setHostTxReady(port.m_port_id, "false"); + setHostTxReady(port, "false"); SWSS_LOG_NOTICE("Set host_tx_ready to false as gbstatus is false " "for port %s", port.m_alias.c_str()); } @@ -1513,7 +1513,7 @@ bool PortsOrch::setPortAdminStatus(Port &port, bool state) /* Update the state table for host_tx_ready*/ if (state && (gbstatus == true) && (status == SAI_STATUS_SUCCESS) && !m_cmisModuleAsicSyncSupported) { - setHostTxReady(port.m_port_id, "true"); + setHostTxReady(port, "true"); SWSS_LOG_NOTICE("Set admin status UP host_tx_ready to true for port %s", port.m_alias.c_str()); } @@ -1521,18 +1521,10 @@ bool PortsOrch::setPortAdminStatus(Port &port, bool state) return true; } -void PortsOrch::setHostTxReady(sai_object_id_t portId, const std::string &status) +void PortsOrch::setHostTxReady(Port port, const std::string &status) { - Port p; - - if (!getPort(portId, p)) - { - SWSS_LOG_ERROR("Failed to get port object for port id 0x%" PRIx64, portId); - return; - } - - SWSS_LOG_NOTICE("Setting host_tx_ready status = %s, alias = %s, port_id = 0x%" PRIx64, status.c_str(), p.m_alias.c_str(), portId); - m_portStateTable.hset(p.m_alias, "host_tx_ready", status); + SWSS_LOG_NOTICE("Setting host_tx_ready status = %s, alias = %s, port_id = 0x%" PRIx64, status.c_str(), port.m_alias.c_str(), port.m_port_id); + m_portStateTable.hset(port.m_alias, "host_tx_ready", status); } bool PortsOrch::getPortAdminStatus(sai_object_id_t id, bool &up) @@ -3105,7 +3097,7 @@ void PortsOrch::updateDbPortFlapCount(Port& port, sai_port_oper_status_t pstatus vector tuples; FieldValueTuple tuple("flap_count", std::to_string(port.m_flap_count)); tuples.push_back(tuple); - + auto now = std::chrono::system_clock::now(); std::time_t now_c = std::chrono::system_clock::to_time_t(now); if (pstatus == SAI_PORT_OPER_STATUS_DOWN) @@ -3115,8 +3107,8 @@ void PortsOrch::updateDbPortFlapCount(Port& port, sai_port_oper_status_t pstatus std::strftime(buffer, sizeof(buffer), "%a %b %d %H:%M:%S %Y", std::gmtime(&now_c)); FieldValueTuple tuple("last_down_time", buffer); tuples.push_back(tuple); - } - else if (pstatus == SAI_PORT_OPER_STATUS_UP) + } + else if (pstatus == SAI_PORT_OPER_STATUS_UP) { char buffer[32]; // Format: Www Mmm dd hh:mm:ss yyyy @@ -5467,7 +5459,7 @@ bool PortsOrch::initializePort(Port &port) string hostTxReadyStr = hostTxReadyVal ? "true" : "false"; SWSS_LOG_DEBUG("Received host_tx_ready current status: port_id: 0x%" PRIx64 " status: %s", port.m_port_id, hostTxReadyStr.c_str()); - setHostTxReady(port.m_port_id, hostTxReadyStr); + setHostTxReady(port, hostTxReadyStr); } /* @@ -7646,7 +7638,13 @@ void PortsOrch::doTask(NotificationConsumer &consumer) sai_deserialize_port_host_tx_ready_ntf(data, switch_id, port_id, host_tx_ready_status); SWSS_LOG_DEBUG("Recieved host_tx_ready notification for port 0x%" PRIx64, port_id); - setHostTxReady(port_id, host_tx_ready_status == SAI_PORT_HOST_TX_READY_STATUS_READY ? "true" : "false"); + Port p; + if (!getPort(port_id, p)) + { + SWSS_LOG_ERROR("Failed to get port object for port id 0x%" PRIx64, port_id); + return; + } + setHostTxReady(p, host_tx_ready_status == SAI_PORT_HOST_TX_READY_STATUS_READY ? "true" : "false"); } } diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index b79c23530c..689d2c0dda 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -410,7 +410,7 @@ class PortsOrch : public Orch, public Subject bool setSaiHostTxSignal(const Port &port, bool enable); - void setHostTxReady(sai_object_id_t portId, const std::string &status); + void setHostTxReady(Port port, const std::string &status); // Get supported speeds on system side bool isSpeedSupported(const std::string& alias, sai_object_id_t port_id, sai_uint32_t speed); void getPortSupportedSpeeds(const std::string& alias, sai_object_id_t port_id, PortSupportedSpeeds &supported_speeds); From 1ff616022aaaa79a9756950dcb62315870858d0f Mon Sep 17 00:00:00 2001 From: Liu Shilong Date: Tue, 21 May 2024 23:51:51 +0800 Subject: [PATCH 33/34] revert requests from 2.32.0 to 2.31.0 (#3154) What I did Use requests 2.31.0 instead of latest 2.32.0 Why I did it requests 2.32.0 breaks Test stage. --- .azure-pipelines/test-docker-sonic-vs-template.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.azure-pipelines/test-docker-sonic-vs-template.yml b/.azure-pipelines/test-docker-sonic-vs-template.yml index dbddd64077..b17dd59584 100644 --- a/.azure-pipelines/test-docker-sonic-vs-template.yml +++ b/.azure-pipelines/test-docker-sonic-vs-template.yml @@ -107,7 +107,7 @@ jobs: # install packages for vs test sudo apt-get install -y net-tools bridge-utils vlan sudo apt-get install -y python3-pip - sudo pip3 install pytest==4.6.2 attrs==19.1.0 exabgp==4.0.10 distro==1.5.0 docker>=4.4.1 redis==3.3.4 flaky==3.7.0 + sudo pip3 install pytest==4.6.2 attrs==19.1.0 exabgp==4.0.10 distro==1.5.0 docker>=4.4.1 redis==3.3.4 flaky==3.7.0 requests==2.31.0 sudo pip3 install lcov_cobertura displayName: "Install dependencies" From a280e367564cce6d8138fe39a0ce031b516c5699 Mon Sep 17 00:00:00 2001 From: Sudharsan Dhamal Gopalarathnam Date: Tue, 21 May 2024 09:53:27 -0700 Subject: [PATCH 34/34] [COPP]Fix coppmgr when there are multiple features using same trap (#3144) What I did Fix coppmgr when there are multiple feature tables using same trap. In addition fixed the following issues When a new feature is added which is not present during the init, the copp entry will not get programmed. When a copp trap attribute is set, it overrides the other existing attributes --- cfgmgr/coppmgr.cpp | 13 +++++++------ orchagent/copporch.cpp | 2 +- tests/test_copp.py | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/cfgmgr/coppmgr.cpp b/cfgmgr/coppmgr.cpp index 9b2c3ee4d7..65c154349b 100644 --- a/cfgmgr/coppmgr.cpp +++ b/cfgmgr/coppmgr.cpp @@ -183,14 +183,13 @@ bool CoppMgr::isTrapIdDisabled(string trap_id) { return false; } - break; + if (isFeatureEnabled(trap_name)) + { + return false; + } } } - if (isFeatureEnabled(trap_name)) - { - return false; - } return true; } @@ -941,7 +940,9 @@ void CoppMgr::doFeatureTask(Consumer &consumer) { if (m_featuresCfgTable.find(key) == m_featuresCfgTable.end()) { - m_featuresCfgTable.emplace(key, kfvFieldsValues(t)); + // Init with empty feature state which will be updated in setFeatureTrapIdsStatus + FieldValueTuple fv("state", ""); + m_featuresCfgTable[key].push_back(fv); } for (auto i : kfvFieldsValues(t)) { diff --git a/orchagent/copporch.cpp b/orchagent/copporch.cpp index 56f2cb4db2..749a8aae7e 100644 --- a/orchagent/copporch.cpp +++ b/orchagent/copporch.cpp @@ -632,7 +632,7 @@ task_process_status CoppOrch::processCoppRule(Consumer& consumer) if (!trap_id_attribs.empty()) { vector group_trap_ids; - TrapIdAttribs trap_attr; + TrapIdAttribs trap_attr = m_trap_group_trap_id_attrs[trap_group_name]; getTrapIdsFromTrapGroup(m_trap_group_map[trap_group_name], group_trap_ids); for (auto trap_id : group_trap_ids) diff --git a/tests/test_copp.py b/tests/test_copp.py index 5885a489b5..4163300a31 100644 --- a/tests/test_copp.py +++ b/tests/test_copp.py @@ -841,3 +841,38 @@ def test_disabled_feature_always_enabled_trap(self, dvs, testlog): self.feature_tbl.set("lldp", fvs) assert table_found == False + + def test_multi_feature_trap_add(self, dvs, testlog): + self.setup_copp(dvs) + global copp_trap + traps = "eapol" + fvs = swsscommon.FieldValuePairs([("state", "disbled")]) + self.feature_tbl.set("macsec", fvs) + fvs = swsscommon.FieldValuePairs([("state", "enabled")]) + self.feature_tbl.set("pac", fvs) + fvs = swsscommon.FieldValuePairs([("trap_group", "queue4_group1"),("trap_ids", traps)]) + self.trap_ctbl.set("pac", fvs) + + + copp_trap["eapol"] = [traps, copp_group_queue4_group1] + time.sleep(2) + + trap_keys = self.trap_atbl.getKeys() + trap_ids = traps.split(",") + trap_group = copp_group_queue4_group1 + for trap_id in trap_ids: + trap_type = traps_to_trap_type[trap_id] + trap_found = False + trap_group_oid = "" + for key in trap_keys: + (status, fvs) = self.trap_atbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_HOSTIF_TRAP_ATTR_TRAP_TYPE": + if fv[1] == trap_type: + trap_found = True + if trap_found: + self.validate_trap_group(key,trap_group) + break + if trap_id not in disabled_traps: + assert trap_found == True