From fd1292ccc63981ab2459675c504de97b35ae830b Mon Sep 17 00:00:00 2001 From: Mirza Baig Date: Sun, 1 Dec 2024 16:40:31 -0500 Subject: [PATCH 1/2] bfdorch changes to support software bfd sessions --- orchagent/bfdorch.cpp | 52 ++++++++++- orchagent/bfdorch.h | 5 +- tests/test_soft_bfd.py | 192 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 246 insertions(+), 3 deletions(-) create mode 100644 tests/test_soft_bfd.py diff --git a/orchagent/bfdorch.cpp b/orchagent/bfdorch.cpp index 6c435cdddb..8f2b25b45a 100644 --- a/orchagent/bfdorch.cpp +++ b/orchagent/bfdorch.cpp @@ -7,6 +7,7 @@ #include "sai_serialize.h" #include "directory.h" #include "notifications.h" +#include "schema.h" using namespace std; using namespace swss; @@ -21,12 +22,17 @@ using namespace swss; #define BFD_SRCPORTMAX 65536 #define NUM_BFD_SRCPORT_RETRIES 3 +//TODO: remove once this definition is committed in swss-common schema +#define STATE_BFD_SOFTWARE_SESSION_TABLE_NAME "SOFTWARE_BFD_SESSION_TABLE" + extern sai_bfd_api_t* sai_bfd_api; extern sai_object_id_t gSwitchId; extern sai_object_id_t gVirtualRouterId; extern PortsOrch* gPortsOrch; extern sai_switch_api_t* sai_switch_api; extern Directory gDirectory; +extern string gMySwitchType; + const map session_type_map = { @@ -62,16 +68,29 @@ BfdOrch::BfdOrch(DBConnector *db, string tableName, TableConnector stateDbBfdSes m_bfdStateNotificationConsumer = new swss::NotificationConsumer(notificationsDb, "NOTIFICATIONS"); auto bfdStateNotificatier = new Notifier(m_bfdStateNotificationConsumer, this, "BFD_STATE_NOTIFICATIONS"); - // Clean up state database BFD entries + m_stateDbConnector = std::make_unique("STATE_DB", 0); + m_stateSoftBfdSessionTable = std::make_unique(m_stateDbConnector.get(), STATE_BFD_SOFTWARE_SESSION_TABLE_NAME); + + SWSS_LOG_NOTICE("Switch type is: %s", gMySwitchType.c_str()); + vector keys; + // Clean up state database BFD entries m_stateBfdSessionTable.getKeys(keys); - for (auto alias : keys) { m_stateBfdSessionTable.del(alias); } + // Clean up state database software BFD entries + if (gMySwitchType == "dpu") { + m_stateSoftBfdSessionTable->getKeys(keys); + for (auto alias : keys) + { + m_stateSoftBfdSessionTable->del(alias); + } + } + Orch::addExecutor(bfdStateNotificatier); register_state_change_notif = false; } @@ -81,6 +100,21 @@ BfdOrch::~BfdOrch(void) SWSS_LOG_ENTER(); } +std::string BfdOrch::replaceFirstTwoColons(const std::string &input) { + std::string result = input; + size_t pos = result.find(':'); // Find the first colon + if (pos != std::string::npos) { + result[pos] = '|'; // Replace the first colon with '|' + + // Find the second colon + pos = result.find(':', pos + 1); + if (pos != std::string::npos) { + result[pos] = '|'; // Replace the second colon with '|' + } + } + return result; +} + void BfdOrch::doTask(Consumer &consumer) { SWSS_LOG_ENTER(); @@ -101,6 +135,13 @@ void BfdOrch::doTask(Consumer &consumer) if (op == SET_COMMAND) { + if (gMySwitchType == "dpu") { + //program entry in software BFD table + m_stateSoftBfdSessionTable->set(replaceFirstTwoColons(key), data); + it = consumer.m_toSync.erase(it); + continue; + } + bool tsa_shutdown_enabled = false; for (auto i : data) { @@ -142,6 +183,13 @@ void BfdOrch::doTask(Consumer &consumer) } else if (op == DEL_COMMAND) { + if (gMySwitchType == "dpu") { + //delete entry from software BFD table + m_stateSoftBfdSessionTable->del(replaceFirstTwoColons(key)); + it = consumer.m_toSync.erase(it); + continue; + } + if (bfd_session_cache.find(key) != bfd_session_cache.end() ) { bfd_session_cache.erase(key); diff --git a/orchagent/bfdorch.h b/orchagent/bfdorch.h index 31e0e4c930..656c94709e 100644 --- a/orchagent/bfdorch.h +++ b/orchagent/bfdorch.h @@ -31,16 +31,19 @@ class BfdOrch: public Orch, public Subject bool register_bfd_state_change_notification(void); void update_port_number(std::vector &attrs); sai_status_t retry_create_bfd_session(sai_object_id_t &bfd_session_id, vector attrs); + std::string replaceFirstTwoColons(const std::string &input); std::map bfd_session_map; std::map bfd_session_lookup; swss::Table m_stateBfdSessionTable; + std::unique_ptr m_stateDbConnector; + std::unique_ptr m_stateSoftBfdSessionTable; + swss::NotificationConsumer* m_bfdStateNotificationConsumer; bool register_state_change_notif; std::map> bfd_session_cache; - }; class BgpGlobalStateOrch : public Orch diff --git a/tests/test_soft_bfd.py b/tests/test_soft_bfd.py new file mode 100644 index 0000000000..43e762662e --- /dev/null +++ b/tests/test_soft_bfd.py @@ -0,0 +1,192 @@ +import pytest +import time + +from swsscommon import swsscommon + +#Replace with swsscommon.SOFTWARE_BFD_SESSION_STATE_TABLE once those changes are in master +#SOFT_BFD__STATE_TABLE = swsscommon.STATE_BFD_SOFTWARE_SESSION_TABLE_NAME +SOFT_BFD__STATE_TABLE = "SOFTWARE_BFD_SESSION_TABLE" + +class TestSoftBfd(object): + def setup_db(self, dvs): + dvs.setup_db() + self.pdb = dvs.get_app_db() + self.sdb = dvs.get_state_db() + self.cdb = dvs.get_config_db() + + self.cdb.db_connection.hset('DEVICE_METADATA|localhost', "switch_type", "dpu") + + #Restart swss to pick up new switch type + dvs.stop_swss() + dvs.start_swss() + + def get_exist_bfd_session(self): + return set(self.sdb.get_keys(SOFTWARE_BFD_SESSION_STATE_TABLE)) + + def create_bfd_session(self, key, pairs): + tbl = swsscommon.ProducerStateTable(self.pdb.db_connection, "BFD_SESSION_TABLE") + fvs = swsscommon.FieldValuePairs(list(pairs.items())) + tbl.set(key, fvs) + + def remove_bfd_session(self, key): + tbl = swsscommon.ProducerStateTable(self.pdb.db_connection, "BFD_SESSION_TABLE") + tbl._del(key) + + def check_state_bfd_session_value(self, key, expected_values): + #Key format is different in STATE_DB compared to APP_DB + key = key.replace(":", "|", 2) + fvs = self.sdb.get_entry(SOFTWARE_BFD_SESSION_STATE_TABLE, key) + for k, v in expected_values.items(): + assert fvs[k] == v + + def test_addRemoveBfdSession(self, dvs): + self.setup_db(dvs) + bfd_session_key = "default:default:10.0.0.2" + bfdSessions = self.get_exist_bfd_session() + + # Create BFD session + fieldValues = {"local_addr": "10.0.0.1", "tos": "64", "multiplier": "5", "tx_interval": "3 +00", + "rx_interval": "500"} + self.create_bfd_session(bfd_session_key, fieldValues) + self.sdb.wait_for_n_keys(SOFTWARE_BFD_SESSION_STATE_TABLE, len(bfdSessions) + 1) + + # Check created BFD session in STATE_DB + createdSessions = self.get_exist_bfd_session() - bfdSessions + assert len(createdSessions) == 1 + + session = createdSessions.pop() + + # Check STATE_DB entry related to the BFD session + self.check_state_bfd_session_value(bfd_session_key, fieldValues) + + # Remove the BFD session + self.remove_bfd_session(bfd_session_key) + self.sdb.wait_for_deleted_entry(SOFTWARE_BFD_SESSION_STATE_TABLE, session) + + def test_addRemoveBfdSession_ipv6(self, dvs): + self.setup_db(dvs) + bfd_session_key = "default:default:2000::2" + bfdSessions = self.get_exist_bfd_session() + + # Create BFD session + fieldValues = {"local_addr": "2000::1", "multihop": "true", "multiplier": "3", "tx_interva +l": "400", + "rx_interval": "200"} + self.create_bfd_session(bfd_session_key, fieldValues) + self.sdb.wait_for_n_keys(SOFTWARE_BFD_SESSION_STATE_TABLE, len(bfdSessions) + 1) + + # Check created BFD session in STATE_DB + createdSessions = self.get_exist_bfd_session() - bfdSessions + assert len(createdSessions) == 1 + + session = createdSessions.pop() + + # Check STATE_DB entry related to the BFD session + self.check_state_bfd_session_value(bfd_session_key, fieldValues) + + # Remove the BFD session + self.remove_bfd_session(bfd_session_key) + self.sdb.wait_for_deleted_entry(SOFTWARE_BFD_SESSION_STATE_TABLE, session) + + def test_addRemoveBfdSession_interface(self, dvs): + self.setup_db(dvs) + bfd_session_key = "default:Ethernet0:10.0.0.2" + bfdSessions = self.get_exist_bfd_session() + + # Create BFD session + fieldValues = {"local_addr": "10.0.0.1", "dst_mac": "00:02:03:04:05:06", "type": "async_pa +ssive"} + self.create_bfd_session("default:Ethernet0:10.0.0.2", fieldValues) + self.sdb.wait_for_n_keys(SOFTWARE_BFD_SESSION_STATE_TABLE, len(bfdSessions) + 1) + + # Check created BFD session in STATE_DB + createdSessions = self.get_exist_bfd_session() - bfdSessions + assert len(createdSessions) == 1 + + session = createdSessions.pop() + + # Check STATE_DB entry related to the BFD session + self.check_state_bfd_session_value(bfd_session_key, fieldValues) + + # Remove the BFD session + self.remove_bfd_session(bfd_session_key) + self.sdb.wait_for_deleted_entry(SOFTWARE_BFD_SESSION_STATE_TABLE, session) + + def test_multipleBfdSessions(self, dvs): + self.setup_db(dvs) + bfdSessions = self.get_exist_bfd_session() + + # Create BFD session 1 + key1 = "default:default:10.0.0.2" + fieldValues = {"local_addr": "10.0.0.1"} + self.create_bfd_session(key1, fieldValues) + self.sdb.wait_for_n_keys(SOFTWARE_BFD_SESSION_STATE_TABLE, len(bfdSessions) + 1) + + # Checked BFD session 1 in STATE_DB + createdSessions = self.get_exist_bfd_session() - bfdSessions + bfdSessions = self.get_exist_bfd_session() + assert len(createdSessions) == 1 + + session1 = createdSessions.pop() + + # Check STATE_DB entry related to the BFD session + self.check_state_bfd_session_value(key1, fieldValues) + + # Create BFD session 2 + key2 = "default:default:10.0.1.2" + fieldValues = {"local_addr": "10.0.0.1", "tx_interval": "300", "rx_interval": "500"} + self.create_bfd_session(key2, fieldValues) + self.sdb.wait_for_n_keys(SOFTWARE_BFD_SESSION_STATE_TABLE, len(bfdSessions) + 1) + + # Check BFD session 2 in STATE_DB + createdSessions = self.get_exist_bfd_session() - bfdSessions + bfdSessions = self.get_exist_bfd_session() + assert len(createdSessions) == 1 + + session2 = createdSessions.pop() + + # Check STATE_DB entry related to the BFD session + self.check_state_bfd_session_value(key2, fieldValues) + + # Create BFD session 3 + key3 = "default:default:2000::2" + fieldValues = {"local_addr": "2000::1", "type": "demand_active"} + self.create_bfd_session(key3, fieldValues) + self.sdb.wait_for_n_keys(SOFTWARE_BFD_SESSION_STATE_TABLE, len(bfdSessions) + 1) + + # Check BFD session 3 in STATE_DB + createdSessions = self.get_exist_bfd_session() - bfdSessions + bfdSessions = self.get_exist_bfd_session() + assert len(createdSessions) == 1 + + session3 = createdSessions.pop() + + # Check STATE_DB entry related to the BFD session + self.check_state_bfd_session_value(key3, fieldValues) + + # Create BFD session 4 + key4 = "default:default:3000::2" + fieldValues = {"local_addr": "3000::1"} + self.create_bfd_session(key4, fieldValues) + self.sdb.wait_for_n_keys(SOFTWARE_BFD_SESSION_STATE_TABLE, len(bfdSessions) + 1) + + # Check BFD session 3 in STATE_DB + createdSessions = self.get_exist_bfd_session() - bfdSessions + bfdSessions = self.get_exist_bfd_session() + assert len(createdSessions) == 1 + + session4 = createdSessions.pop() + + # Check STATE_DB entry related to the BFD session + self.check_state_bfd_session_value(key4, fieldValues) + + # Remove the BFD sessions + self.remove_bfd_session(key1) + self.sdb.wait_for_deleted_entry(SOFTWARE_BFD_SESSION_STATE_TABLE, session1) + self.remove_bfd_session(key2) + self.sdb.wait_for_deleted_entry(SOFTWARE_BFD_SESSION_STATE_TABLE, session2) + self.remove_bfd_session(key3) + self.sdb.wait_for_deleted_entry(SOFTWARE_BFD_SESSION_STATE_TABLE, session3) + self.remove_bfd_session(key4) + self.sdb.wait_for_deleted_entry(SOFTWARE_BFD_SESSION_STATE_TABLE, session4) From 63a2fa6201b745c197ab2d63b74a5e513c474276 Mon Sep 17 00:00:00 2001 From: Mirza Baig Date: Sun, 1 Dec 2024 23:26:59 -0500 Subject: [PATCH 2/2] fixed syntax errors in the test script --- tests/test_soft_bfd.py | 47 ++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/tests/test_soft_bfd.py b/tests/test_soft_bfd.py index 43e762662e..3da7dbe3ba 100644 --- a/tests/test_soft_bfd.py +++ b/tests/test_soft_bfd.py @@ -5,7 +5,7 @@ #Replace with swsscommon.SOFTWARE_BFD_SESSION_STATE_TABLE once those changes are in master #SOFT_BFD__STATE_TABLE = swsscommon.STATE_BFD_SOFTWARE_SESSION_TABLE_NAME -SOFT_BFD__STATE_TABLE = "SOFTWARE_BFD_SESSION_TABLE" +SOFT_BFD_STATE_TABLE = "SOFTWARE_BFD_SESSION_TABLE" class TestSoftBfd(object): def setup_db(self, dvs): @@ -21,7 +21,7 @@ def setup_db(self, dvs): dvs.start_swss() def get_exist_bfd_session(self): - return set(self.sdb.get_keys(SOFTWARE_BFD_SESSION_STATE_TABLE)) + return set(self.sdb.get_keys(SOFT_BFD_STATE_TABLE)) def create_bfd_session(self, key, pairs): tbl = swsscommon.ProducerStateTable(self.pdb.db_connection, "BFD_SESSION_TABLE") @@ -35,7 +35,7 @@ def remove_bfd_session(self, key): def check_state_bfd_session_value(self, key, expected_values): #Key format is different in STATE_DB compared to APP_DB key = key.replace(":", "|", 2) - fvs = self.sdb.get_entry(SOFTWARE_BFD_SESSION_STATE_TABLE, key) + fvs = self.sdb.get_entry(SOFT_BFD_STATE_TABLE, key) for k, v in expected_values.items(): assert fvs[k] == v @@ -45,11 +45,10 @@ def test_addRemoveBfdSession(self, dvs): bfdSessions = self.get_exist_bfd_session() # Create BFD session - fieldValues = {"local_addr": "10.0.0.1", "tos": "64", "multiplier": "5", "tx_interval": "3 -00", - "rx_interval": "500"} + fieldValues = {"local_addr": "10.0.0.1", "tos": "64", "multiplier": "5", "tx_interval": "300", + "rx_interval": "500"} self.create_bfd_session(bfd_session_key, fieldValues) - self.sdb.wait_for_n_keys(SOFTWARE_BFD_SESSION_STATE_TABLE, len(bfdSessions) + 1) + self.sdb.wait_for_n_keys(SOFT_BFD_STATE_TABLE, len(bfdSessions) + 1) # Check created BFD session in STATE_DB createdSessions = self.get_exist_bfd_session() - bfdSessions @@ -62,7 +61,7 @@ def test_addRemoveBfdSession(self, dvs): # Remove the BFD session self.remove_bfd_session(bfd_session_key) - self.sdb.wait_for_deleted_entry(SOFTWARE_BFD_SESSION_STATE_TABLE, session) + self.sdb.wait_for_deleted_entry(SOFT_BFD_STATE_TABLE, session) def test_addRemoveBfdSession_ipv6(self, dvs): self.setup_db(dvs) @@ -70,11 +69,10 @@ def test_addRemoveBfdSession_ipv6(self, dvs): bfdSessions = self.get_exist_bfd_session() # Create BFD session - fieldValues = {"local_addr": "2000::1", "multihop": "true", "multiplier": "3", "tx_interva -l": "400", - "rx_interval": "200"} + fieldValues = {"local_addr": "2000::1", "multihop": "true", "multiplier": "3", "tx_interval": "400", + "rx_interval": "200"} self.create_bfd_session(bfd_session_key, fieldValues) - self.sdb.wait_for_n_keys(SOFTWARE_BFD_SESSION_STATE_TABLE, len(bfdSessions) + 1) + self.sdb.wait_for_n_keys(SOFT_BFD_STATE_TABLE, len(bfdSessions) + 1) # Check created BFD session in STATE_DB createdSessions = self.get_exist_bfd_session() - bfdSessions @@ -87,7 +85,7 @@ def test_addRemoveBfdSession_ipv6(self, dvs): # Remove the BFD session self.remove_bfd_session(bfd_session_key) - self.sdb.wait_for_deleted_entry(SOFTWARE_BFD_SESSION_STATE_TABLE, session) + self.sdb.wait_for_deleted_entry(SOFT_BFD_STATE_TABLE, session) def test_addRemoveBfdSession_interface(self, dvs): self.setup_db(dvs) @@ -95,10 +93,9 @@ def test_addRemoveBfdSession_interface(self, dvs): bfdSessions = self.get_exist_bfd_session() # Create BFD session - fieldValues = {"local_addr": "10.0.0.1", "dst_mac": "00:02:03:04:05:06", "type": "async_pa -ssive"} + fieldValues = {"local_addr": "10.0.0.1", "dst_mac": "00:02:03:04:05:06", "type": "async_passive"} self.create_bfd_session("default:Ethernet0:10.0.0.2", fieldValues) - self.sdb.wait_for_n_keys(SOFTWARE_BFD_SESSION_STATE_TABLE, len(bfdSessions) + 1) + self.sdb.wait_for_n_keys(SOFT_BFD_STATE_TABLE, len(bfdSessions) + 1) # Check created BFD session in STATE_DB createdSessions = self.get_exist_bfd_session() - bfdSessions @@ -111,7 +108,7 @@ def test_addRemoveBfdSession_interface(self, dvs): # Remove the BFD session self.remove_bfd_session(bfd_session_key) - self.sdb.wait_for_deleted_entry(SOFTWARE_BFD_SESSION_STATE_TABLE, session) + self.sdb.wait_for_deleted_entry(SOFT_BFD_STATE_TABLE, session) def test_multipleBfdSessions(self, dvs): self.setup_db(dvs) @@ -121,7 +118,7 @@ def test_multipleBfdSessions(self, dvs): key1 = "default:default:10.0.0.2" fieldValues = {"local_addr": "10.0.0.1"} self.create_bfd_session(key1, fieldValues) - self.sdb.wait_for_n_keys(SOFTWARE_BFD_SESSION_STATE_TABLE, len(bfdSessions) + 1) + self.sdb.wait_for_n_keys(SOFT_BFD_STATE_TABLE, len(bfdSessions) + 1) # Checked BFD session 1 in STATE_DB createdSessions = self.get_exist_bfd_session() - bfdSessions @@ -137,7 +134,7 @@ def test_multipleBfdSessions(self, dvs): key2 = "default:default:10.0.1.2" fieldValues = {"local_addr": "10.0.0.1", "tx_interval": "300", "rx_interval": "500"} self.create_bfd_session(key2, fieldValues) - self.sdb.wait_for_n_keys(SOFTWARE_BFD_SESSION_STATE_TABLE, len(bfdSessions) + 1) + self.sdb.wait_for_n_keys(SOFT_BFD_STATE_TABLE, len(bfdSessions) + 1) # Check BFD session 2 in STATE_DB createdSessions = self.get_exist_bfd_session() - bfdSessions @@ -153,7 +150,7 @@ def test_multipleBfdSessions(self, dvs): key3 = "default:default:2000::2" fieldValues = {"local_addr": "2000::1", "type": "demand_active"} self.create_bfd_session(key3, fieldValues) - self.sdb.wait_for_n_keys(SOFTWARE_BFD_SESSION_STATE_TABLE, len(bfdSessions) + 1) + self.sdb.wait_for_n_keys(SOFT_BFD_STATE_TABLE, len(bfdSessions) + 1) # Check BFD session 3 in STATE_DB createdSessions = self.get_exist_bfd_session() - bfdSessions @@ -169,7 +166,7 @@ def test_multipleBfdSessions(self, dvs): key4 = "default:default:3000::2" fieldValues = {"local_addr": "3000::1"} self.create_bfd_session(key4, fieldValues) - self.sdb.wait_for_n_keys(SOFTWARE_BFD_SESSION_STATE_TABLE, len(bfdSessions) + 1) + self.sdb.wait_for_n_keys(SOFT_BFD_STATE_TABLE, len(bfdSessions) + 1) # Check BFD session 3 in STATE_DB createdSessions = self.get_exist_bfd_session() - bfdSessions @@ -183,10 +180,10 @@ def test_multipleBfdSessions(self, dvs): # Remove the BFD sessions self.remove_bfd_session(key1) - self.sdb.wait_for_deleted_entry(SOFTWARE_BFD_SESSION_STATE_TABLE, session1) + self.sdb.wait_for_deleted_entry(SOFT_BFD_STATE_TABLE, session1) self.remove_bfd_session(key2) - self.sdb.wait_for_deleted_entry(SOFTWARE_BFD_SESSION_STATE_TABLE, session2) + self.sdb.wait_for_deleted_entry(SOFT_BFD_STATE_TABLE, session2) self.remove_bfd_session(key3) - self.sdb.wait_for_deleted_entry(SOFTWARE_BFD_SESSION_STATE_TABLE, session3) + self.sdb.wait_for_deleted_entry(SOFT_BFD_STATE_TABLE, session3) self.remove_bfd_session(key4) - self.sdb.wait_for_deleted_entry(SOFTWARE_BFD_SESSION_STATE_TABLE, session4) + self.sdb.wait_for_deleted_entry(SOFT_BFD_STATE_TABLE, session4)