From 3524229deaf2dafd22232f1be505b3ae00afd69a Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Wed, 24 Jun 2020 08:23:26 -0700 Subject: [PATCH 01/54] Mclag enhacements support code changes. --- orchagent/Makefile.am | 4 +- orchagent/fdborch.cpp | 969 ++++++++++++++++++++++++++----- orchagent/fdborch.h | 78 ++- orchagent/isolationgrouporch.cpp | 956 ++++++++++++++++++++++++++++++ orchagent/isolationgrouporch.h | 153 +++++ orchagent/mlagorch.cpp | 579 ++++++++++++++++++ orchagent/mlagorch.h | 81 +++ orchagent/observer.h | 2 + orchagent/orchdaemon.cpp | 17 + orchagent/orchdaemon.h | 1 + orchagent/saihelper.cpp | 2 + tests/test_mclag.py | 111 ++++ tests/test_mclag_fdb.py | 511 ++++++++++++++++ 13 files changed, 3317 insertions(+), 147 deletions(-) create mode 100644 orchagent/isolationgrouporch.cpp create mode 100644 orchagent/isolationgrouporch.h create mode 100644 orchagent/mlagorch.cpp create mode 100644 orchagent/mlagorch.h create mode 100644 tests/test_mclag.py create mode 100644 tests/test_mclag_fdb.py diff --git a/orchagent/Makefile.am b/orchagent/Makefile.am index d431557b5c..be0dea5731 100644 --- a/orchagent/Makefile.am +++ b/orchagent/Makefile.am @@ -56,7 +56,9 @@ orchagent_SOURCES = \ sfloworch.cpp \ chassisorch.cpp \ debugcounterorch.cpp \ - natorch.cpp + natorch.cpp \ + mlagorch.cpp \ + isolationgrouporch.cpp orchagent_SOURCES += flex_counter/flex_counter_manager.cpp flex_counter/flex_counter_stat_manager.cpp orchagent_SOURCES += debug_counter/debug_counter.cpp debug_counter/drop_counter.cpp diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index 9a54ba98f1..b006aa802e 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -11,29 +11,41 @@ #include "crmorch.h" #include "notifier.h" #include "sai_serialize.h" +#include "neighorch.h" +#include "mlagorch.h" +#include "directory.h" extern sai_fdb_api_t *sai_fdb_api; extern sai_object_id_t gSwitchId; extern PortsOrch* gPortsOrch; +extern NeighOrch* gNeighOrch; extern CrmOrch * gCrmOrch; +extern MlagOrch* gMlagOrch; +extern Directory gDirectory; -const int fdborch_pri = 20; +const int FdbOrch::fdborch_pri = 20; -FdbOrch::FdbOrch(TableConnector applDbConnector, TableConnector stateDbConnector, PortsOrch *port) : - Orch(applDbConnector.first, applDbConnector.second, fdborch_pri), +FdbOrch::FdbOrch(DBConnector* applDbConnector, vector appFdbTables, TableConnector stateDbFdbConnector, PortsOrch *port) : + Orch(applDbConnector, appFdbTables), m_portsOrch(port), - m_table(applDbConnector.first, applDbConnector.second), - m_fdbStateTable(stateDbConnector.first, stateDbConnector.second) + m_fdbStateTable(stateDbFdbConnector.first, stateDbFdbConnector.second) { + + for(auto it: appFdbTables) + { + m_appTables.push_back(new Table(applDbConnector, it.first)); + } + m_portsOrch->attach(this); - m_flushNotificationsConsumer = new NotificationConsumer(applDbConnector.first, "FLUSHFDBREQUEST"); + m_flushNotificationsConsumer = new NotificationConsumer(applDbConnector, "FLUSHFDBREQUEST"); auto flushNotifier = new Notifier(m_flushNotificationsConsumer, this, "FLUSHFDBREQUEST"); Orch::addExecutor(flushNotifier); /* Add FDB notifications support from ASIC */ - DBConnector *notificationsDb = new DBConnector("ASIC_DB", 0); - m_fdbNotificationConsumer = new swss::NotificationConsumer(notificationsDb, "NOTIFICATIONS"); + DBConnector *notificationsDb = new DBConnector("ASIC_DB", 0); + m_fdbNotificationConsumer = new swss::NotificationConsumer(notificationsDb, "NOTIFICATIONS"); + auto fdbNotifier = new Notifier(m_fdbNotificationConsumer, this, "FDB_NOTIFICATIONS"); Orch::addExecutor(fdbNotifier); } @@ -54,9 +66,27 @@ bool FdbOrch::bake() return true; } +//used for ICCPd FDB entries only for now. +void FdbOrch::neighborOrchFdbUnregister(const MacAddress &mac, unsigned int vlan_id) +{ + fdb_mac_cache fdbmac; + memset(&fdbmac, 0, sizeof(fdb_mac_cache)); + fdbmac.mac = mac; + fdbmac.fdid = vlan_id; + + if (gNeighOrch->delFdbNeighCache(fdbmac, FDB_SYNCD_MAC)) + SWSS_LOG_NOTICE(" MAC Un-Register with NeighOrch Success: " + "Mac: %s Vlan: %d ", fdbmac.mac.to_string().c_str(), fdbmac.fdid); + else + SWSS_LOG_NOTICE(" MAC Un-Register with NeighOrch Failed: " + "Mac: %s Vlan: %d ", fdbmac.mac.to_string().c_str(), fdbmac.fdid); +} + bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) { const FdbEntry& entry = update.entry; + FdbData fdbdata; + FdbData oldFdbData; const Port& port = update.port; const MacAddress& mac = entry.mac; string portName = port.m_alias; @@ -64,7 +94,7 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) if (!m_portsOrch->getPort(entry.bv_id, vlan)) { - SWSS_LOG_NOTICE("FdbOrch notification: Failed to locate vlan port from bv_id 0x%" PRIx64, entry.bv_id); + SWSS_LOG_DEBUG("FdbOrch notification: Failed to locate vlan port from bv_id 0x%" PRIx64, entry.bv_id); return false; } @@ -73,38 +103,82 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) if (update.add) { - auto inserted = m_entries.insert(entry); + bool mac_move=false; + auto it = m_entries.find(entry); + if(it != m_entries.end()) + { + /* This block is specifically added for MAC_MOVE event + and not expected to be executed for LEARN event + */ + if(port.m_bridge_port_id == it->second.bridge_port_id) + { + if (it->second.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + { + mac_move=true; + oldFdbData = it->second; + } + else + { + SWSS_LOG_INFO("FdbOrch notification: mac %s is duplicate", entry.mac.to_string().c_str()); + return false; + } + } - SWSS_LOG_DEBUG("FdbOrch notification: mac %s was inserted into bv_id 0x%" PRIx64, + mac_move=true; + oldFdbData = it->second; + } + + fdbdata.bridge_port_id = update.port.m_bridge_port_id; + fdbdata.type = update.type; + fdbdata.origin = FDB_ORIGIN_LEARN; + fdbdata.origin_sources = FDB_ORIGIN_LEARN; + + m_entries[entry] = fdbdata; + SWSS_LOG_NOTICE("FdbOrch notification: mac %s was inserted into bv_id 0x%" PRIx64, entry.mac.to_string().c_str(), entry.bv_id); + SWSS_LOG_NOTICE("m_entries size=%lu mac=%s port=%lx", m_entries.size(), + entry.mac.to_string().c_str(), m_entries[entry].bridge_port_id); - if (!inserted.second) + if (mac_move && (oldFdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED)) { - SWSS_LOG_INFO("FdbOrch notification: mac %s is duplicate", entry.mac.to_string().c_str()); - return false; + // un-register with NeighborOrch. + neighborOrchFdbUnregister(entry.mac, vlan.m_vlan_info.vlan_id); } // Write to StateDb std::vector fvs; fvs.push_back(FieldValueTuple("port", portName)); - fvs.push_back(FieldValueTuple("type", "dynamic")); + fvs.push_back(FieldValueTuple("type", update.type)); m_fdbStateTable.set(key, fvs); - gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); + if(!mac_move) + { + gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); + } + return true; } else { + auto it= m_entries.find(entry); + if(it != m_entries.end()) + { + oldFdbData = it->second; + } + size_t erased = m_entries.erase(entry); - SWSS_LOG_DEBUG("FdbOrch notification: mac %s was removed from bv_id 0x%" PRIx64, entry.mac.to_string().c_str(), entry.bv_id); + SWSS_LOG_NOTICE("FdbOrch notification: mac %s was removed from bv_id 0x%" PRIx64, entry.mac.to_string().c_str(), entry.bv_id); if (erased == 0) { return false; } - // Remove in StateDb - m_fdbStateTable.del(key); + if (oldFdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + { + // un-register with NeighborOrch. + neighborOrchFdbUnregister(entry.mac, vlan.m_vlan_info.vlan_id); + } gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); return true; @@ -118,10 +192,21 @@ void FdbOrch::update(sai_fdb_event_t type, const sai_fdb_entry_t* entry, sai_obj FdbUpdate update; update.entry.mac = entry->mac_address; update.entry.bv_id = entry->bv_id; + update.type = "dynamic"; + Port vlan; switch (type) { case SAI_FDB_EVENT_LEARNED: + { + SWSS_LOG_INFO"Received LEARN event for bvid=%lx mac=%s port=%lx", entry->bv_id, update.entry.mac.to_string().c_str(), bridge_port_id); + + if (!m_portsOrch->getPort(entry->bv_id, vlan)) + { + SWSS_LOG_ERROR("FdbOrch LEARN notification: Failed to locate vlan port from bv_id 0x%lx", entry->bv_id); + return; + } + if (!m_portsOrch->getPortByBridgePortId(bridge_port_id, update.port)) { SWSS_LOG_ERROR("Failed to get port by bridge port ID 0x%" PRIx64, bridge_port_id); @@ -129,74 +214,261 @@ void FdbOrch::update(sai_fdb_event_t type, const sai_fdb_entry_t* entry, sai_obj } // we already have such entries - if (m_entries.find(update.entry) != m_entries.end()) + auto existing_entry = m_entries.find(update.entry); + if (existing_entry != m_entries.end()) { - SWSS_LOG_INFO("FdbOrch notification: mac %s is already in bv_id 0x%" PRIx64, - update.entry.mac.to_string().c_str(), entry->bv_id); - break; + SWSS_LOG_INFO("FdbOrch LEARN notification: mac %s with origin %d is already in bv_id 0x%lx with different BP existing-bp 0x%lx new-bp:0x%lx", + update.entry.mac.to_string().c_str(), existing_entry->second.origin, entry->bv_id, existing_entry->second.bridge_port_id, bridge_port_id); + + if (existing_entry->second.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + { + // If the bp is different MOVE the MAC entry. + if (existing_entry->second.bridge_port_id != bridge_port_id) + { + Port port; + SWSS_LOG_NOTICE("FdbOrch LEARN notification: mac %s is already in bv_id 0x%lx with different existing-bp 0x%lx new-bp:0x%lx", + update.entry.mac.to_string().c_str(), entry->bv_id, existing_entry->second.bridge_port_id, bridge_port_id); + if (!m_portsOrch->getPortByBridgePortId(existing_entry->second.bridge_port_id, port)) + { + SWSS_LOG_NOTICE("FdbOrch LEARN notification: Failed to get port by bridge port ID 0x%lx", existing_entry->second.bridge_port_id); + return; + } + else + { + port.m_fdb_count--; + m_portsOrch->setPort(port.m_alias, port); + vlan.m_fdb_count--; + m_portsOrch->setPort(vlan.m_alias, vlan); + } + + // Continue to add (update/move) the MAC + } + else + { + SWSS_LOG_NOTICE("FdbOrch LEARN notification: mac %s is already in bv_id 0x%lx with same bp 0x%lx ", + update.entry.mac.to_string().c_str(), entry->bv_id, existing_entry->second.bridge_port_id); + // Continue to move the MAC as local. + + // Existing MAC entry is on same VLAN, Port with Origin MCLAG(remote), its possible after the local learn MAC in + //the HW is updated to remote from FdbOrch, Update the MAC back to local in HW so that FdbOrch and HW is Sync and aging enabled. + sai_status_t status; + sai_fdb_entry_t fdb_entry; + fdb_entry.switch_id = gSwitchId; + memcpy(fdb_entry.mac_address, entry->mac_address, sizeof(sai_mac_t)); + fdb_entry.bv_id = entry->bv_id; + sai_attribute_t attr; + vector attrs; + + attr.id = SAI_FDB_ENTRY_ATTR_TYPE; + attr.value.s32 = SAI_FDB_ENTRY_TYPE_DYNAMIC; + attrs.push_back(attr); + + attr.id = SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID; + attr.value.oid = existing_entry->second.bridge_port_id; + attrs.push_back(attr); + + for(auto itr : attrs) + { + status = sai_fdb_api->set_fdb_entry_attribute(&fdb_entry, &itr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("macUpdate-Failed for MCLAG mac attr.id=0x%x for FDB %s in 0x%lx on %s, rv:%d", + itr.id, update.entry.mac.to_string().c_str(), entry->bv_id, update.port.m_alias.c_str(), status); + } + } + update.add = true; + update.type = "dynamic"; + storeFdbEntryState(update); + notify(SUBJECT_TYPE_FDB_CHANGE, &update); + + return; + } + } + else + { + SWSS_LOG_NOTICE("FdbOrch LEARN notification: mac %s is already in bv_id 0x%lx existing-bp 0x%lx new-bp:0x%lx ", + update.entry.mac.to_string().c_str(), entry->bv_id, existing_entry->second.bridge_port_id, bridge_port_id); + break; + } } update.add = true; + update.type = "dynamic"; + update.port.m_fdb_count++; + m_portsOrch->setPort(update.port.m_alias, update.port); + vlan.m_fdb_count++; + m_portsOrch->setPort(vlan.m_alias, vlan); + storeFdbEntryState(update); - for (auto observer: m_observers) + notify(SUBJECT_TYPE_FDB_CHANGE, &update); + + break; + } + case SAI_FDB_EVENT_AGED: + { + SWSS_LOG_NOTICE("Received AGE event for bvid=%lx mac=%s port=%lx", entry->bv_id, update.entry.mac.to_string().c_str(), bridge_port_id); + + if (!m_portsOrch->getPort(entry->bv_id, vlan)) { - observer->update(SUBJECT_TYPE_FDB_CHANGE, &update); + SWSS_LOG_DEBUG("FdbOrch AGE notification: Failed to locate vlan port from bv_id 0x%lx", entry->bv_id); + return; } - break; + auto existing_entry = m_entries.find(update.entry); + // we don't have such entries + if (existing_entry == m_entries.end()) + { + SWSS_LOG_DEBUG("FdbOrch AGE notification: mac %s is not present in bv_id 0x%lx bp 0x%lx", + update.entry.mac.to_string().c_str(), entry->bv_id, bridge_port_id); + break; + } + + if (!m_portsOrch->getPortByBridgePortId(bridge_port_id, update.port)) + { + SWSS_LOG_DEBUG("FdbOrch AGE notification: Failed to get port by bridge port ID 0x%lx", bridge_port_id); + return; + } + + if (existing_entry->second.bridge_port_id != bridge_port_id) + { + SWSS_LOG_DEBUG("FdbOrch AGE notification: Stale aging event received for mac-bv_id %s-0x%lx with bp=0x%lx existing bp=0x%lx", update.entry.mac.to_string().c_str(), entry->bv_id, bridge_port_id, existing_entry->second.bridge_port_id); + Port port = update.port; + // We need to get the port for bridge-port in existing fdb + if (!m_portsOrch->getPortByBridgePortId(existing_entry->second.bridge_port_id, update.port)) + { + SWSS_LOG_DEBUG("FdbOrch AGE notification: Failed to get port by bridge port ID 0x%lx", existing_entry->second.bridge_port_id); + } + + // dont return, let it delete just to bring SONiC and SAI in sync + // return; + } + + if (existing_entry->second.type == "static") + { + if (existing_entry->second.type == "static") + { + update.type = "static"; + } + if (vlan.m_members.find(update.port.m_alias) == vlan.m_members.end()) + { + SWSS_LOG_NOTICE("add mac to saved fdb %s FDB %s in %s on %s", + existing_entry->second.type.c_str(), update.entry.mac.to_string().c_str(), + vlan.m_alias.c_str(), update.port.m_alias.c_str()); + saved_fdb_entries[update.port.m_alias].push_back({existing_entry->first.mac, + vlan.m_vlan_info.vlan_id, update.type, + existing_entry->second.origin}); + } + } - case SAI_FDB_EVENT_AGED: - case SAI_FDB_EVENT_MOVE: update.add = false; + update.port.m_fdb_count--; + m_portsOrch->setPort(update.port.m_alias, update.port); + vlan.m_fdb_count--; + m_portsOrch->setPort(vlan.m_alias, vlan); + storeFdbEntryState(update); - for (auto observer: m_observers) + notify(SUBJECT_TYPE_FDB_CHANGE, &update); + + break; + } + + case SAI_FDB_EVENT_MOVE: + { + Port port_old; + auto existing_entry = m_entries.find(update.entry); + + SWSS_LOG_INFO("Received MOVE event for bvid=%lx mac=%s port=%lx", entry->bv_id, update.entry.mac.to_string().c_str(), bridge_port_id); + + if (!m_portsOrch->getPort(entry->bv_id, vlan)) { - observer->update(SUBJECT_TYPE_FDB_CHANGE, &update); + SWSS_LOG_NOTICE("FdbOrch MOVE notification: Failed to locate vlan port from bv_id 0x%lx", entry->bv_id); + return; } - break; + if (!m_portsOrch->getPortByBridgePortId(bridge_port_id, update.port)) + { + SWSS_LOG_ERROR("FdbOrch MOVE notification: Failed to get port by bridge port ID 0x%lx", bridge_port_id); + return; + } + // We should already have such entry + if (existing_entry == m_entries.end()) + { + SWSS_LOG_INFO("FdbOrch MOVE notification: mac %s is not found in bv_id 0x%lx", + update.entry.mac.to_string().c_str(), entry->bv_id); + break; + } + if (!m_portsOrch->getPortByBridgePortId(existing_entry->second.bridge_port_id, port_old)) + { + SWSS_LOG_ERROR("FdbOrch MOVE notification: Failed to get port by bridge port ID 0x%lx", existing_entry->second.bridge_port_id); + return; + } + + update.add = true; + + port_old.m_fdb_count--; + m_portsOrch->setPort(port_old.m_alias, port_old); + update.port.m_fdb_count++; + m_portsOrch->setPort(update.port.m_alias, update.port); + + storeFdbEntryState(update); + + notify(SUBJECT_TYPE_FDB_CHANGE, &update); + + break; + } case SAI_FDB_EVENT_FLUSHED: - if (bridge_port_id == SAI_NULL_OBJECT_ID && entry->bv_id == SAI_NULL_OBJECT_ID) + SWSS_LOG_INFO("Received FLUSH event for bvid=%lx mac=%s port=%lx", entry->bv_id, update.entry.mac.to_string().c_str(), bridge_port_id); + for (auto itr = m_entries.begin(); itr != m_entries.end();) { - for (auto itr = m_entries.begin(); itr != m_entries.end();) + if (itr->second.type == "static") { - /* - TODO: here should only delete the dynamic fdb entries, - but unfortunately in structure FdbEntry currently have - no member to indicate the fdb entry type, - if there is static mac added, here will have issue. - */ - update.entry.mac = itr->mac; - update.entry.bv_id = itr->bv_id; - update.add = false; itr++; + continue; + } - storeFdbEntryState(update); + if (((bridge_port_id == SAI_NULL_OBJECT_ID) && (entry->bv_id == SAI_NULL_OBJECT_ID)) // Flush all DYNAMIC + || ((bridge_port_id == itr->second.bridge_port_id) && (entry->bv_id == SAI_NULL_OBJECT_ID)) // flush all DYN on a port + || ((bridge_port_id == SAI_NULL_OBJECT_ID) && (entry->bv_id == itr->first.bv_id))) // flush all DYN on a vlan + { - SWSS_LOG_DEBUG("FdbOrch notification: mac %s was removed", update.entry.mac.to_string().c_str()); + if (!m_portsOrch->getPortByBridgePortId(itr->second.bridge_port_id, update.port)) + { + SWSS_LOG_ERROR("FdbOrch FLUSH notification: Failed to get port by bridge port ID 0x%lx", itr->second.bridge_port_id); + itr++; + continue; + } - for (auto observer: m_observers) + if (!m_portsOrch->getPort(itr->first.bv_id, vlan)) { - observer->update(SUBJECT_TYPE_FDB_CHANGE, &update); + itr++; + continue; } + + update.entry.mac = itr->first.mac; + update.entry.bv_id = itr->first.bv_id; + update.add = false; + itr++; + + + update.port.m_fdb_count--; + m_portsOrch->setPort(update.port.m_alias, update.port); + vlan.m_fdb_count--; + m_portsOrch->setPort(vlan.m_alias, vlan); + + /* This will invalidate the current iterator hence itr++ is done before */ + storeFdbEntryState(update); + + SWSS_LOG_DEBUG("FdbOrch FLUSH notification: mac %s was removed", update.entry.mac.to_string().c_str()); + + notify(SUBJECT_TYPE_FDB_CHANGE, &update); + } + else + { + itr++; } - } - else if (bridge_port_id && entry->bv_id == SAI_NULL_OBJECT_ID) - { - /*this is a placeholder for flush port fdb case, not supported yet.*/ - SWSS_LOG_ERROR("FdbOrch notification: not supported flush port fdb action, port_id = 0x%" PRIx64 ", bv_id = 0x%" PRIx64 ".", bridge_port_id, entry->bv_id); - } - else if (bridge_port_id == SAI_NULL_OBJECT_ID && entry->bv_id != SAI_NULL_OBJECT_ID) - { - /*this is a placeholder for flush vlan fdb case, not supported yet.*/ - SWSS_LOG_ERROR("FdbOrch notification: not supported flush vlan fdb action, port_id = 0x%" PRIx64 ", bv_id = 0x%" PRIx64 ".", bridge_port_id, entry->bv_id); - } - else - { - SWSS_LOG_ERROR("FdbOrch notification: not supported flush fdb action, port_id = 0x%" PRIx64 ", bv_id = 0x%" PRIx64 ".", bridge_port_id, entry->bv_id); } break; } @@ -226,6 +498,7 @@ void FdbOrch::update(SubjectType type, void *cntx) bool FdbOrch::getPort(const MacAddress& mac, uint16_t vlan, Port& port) { + sai_object_id_t bridge_port_id; SWSS_LOG_ENTER(); if (!m_portsOrch->getVlanByVlanId(vlan, port)) @@ -234,6 +507,7 @@ bool FdbOrch::getPort(const MacAddress& mac, uint16_t vlan, Port& port) return false; } +#if 0 sai_fdb_entry_t entry; entry.switch_id = gSwitchId; memcpy(entry.mac_address, mac.getMac(), sizeof(sai_mac_t)); @@ -249,10 +523,24 @@ bool FdbOrch::getPort(const MacAddress& mac, uint16_t vlan, Port& port) mac.to_string().c_str(), status); return false; } - - if (!m_portsOrch->getPortByBridgePortId(attr.value.oid, port)) + bridge_port_id = attr.value.oid; +#else + FdbEntry entry; + entry.bv_id = port.m_vlan_info.vlan_oid; + entry.mac = mac; + auto it= m_entries.find(entry); + if(it != m_entries.end()) + { + bridge_port_id = it->second.bridge_port_id; + } + else + { + return false; + } +#endif + if (!m_portsOrch->getPortByBridgePortId(bridge_port_id, port)) { - SWSS_LOG_ERROR("Failed to get port by bridge port ID 0x%" PRIx64, attr.value.oid); + SWSS_LOG_ERROR("Failed to get port by bridge port ID 0x%lx", bridge_port_id); return false; } @@ -268,6 +556,15 @@ void FdbOrch::doTask(Consumer& consumer) return; } + FdbOrigin origin = FDB_ORIGIN_PROVISIONED; + + string table_name = consumer.getTableName(); + + if (table_name == APP_MCLAG_FDB_TABLE_NAME) + { + origin = FDB_ORIGIN_MCLAG_ADVERTIZED; + } + auto it = consumer.m_toSync.begin(); while (it != consumer.m_toSync.end()) { @@ -276,12 +573,30 @@ void FdbOrch::doTask(Consumer& consumer) /* format: : */ vector keys = tokenize(kfvKey(t), ':', 1); string op = kfvOp(t); + unsigned short vlan_id; Port vlan; if (!m_portsOrch->getPort(keys[0], vlan)) { SWSS_LOG_INFO("Failed to locate %s", keys[0].c_str()); - it++; + + if(op == DEL_COMMAND) + { + /* Delete if it is in saved_fdb_entry */ + try { + vlan_id = (unsigned short) stoi(keys[0].substr(4)); + } catch(exception &e) { + it = consumer.m_toSync.erase(it); + continue; + } + deleteFdbEntryFromSavedFDB(MacAddress(keys[1]), vlan_id, origin, ""); + + it = consumer.m_toSync.erase(it); + } + else + { + it++; + } continue; } @@ -291,8 +606,9 @@ void FdbOrch::doTask(Consumer& consumer) if (op == SET_COMMAND) { - string port; - string type; + string port = ""; + string type = "dynamic"; + string sticky = ""; for (auto i : kfvFieldsValues(t)) { @@ -305,31 +621,50 @@ void FdbOrch::doTask(Consumer& consumer) { type = fvValue(i); } + } /* FDB type is either dynamic or static */ - assert(type == "dynamic" || type == "static"); - if (addFdbEntry(entry, port, type)) + if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + assert(type == "dynamic" || type == "dynamic_local" || type == "static" ); + else + assert(type == "dynamic" || type == "static" ); + + if (addFdbEntry(entry, port, type, origin)) + { + if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + { + if (type == "dynamic_local") + { + //Un-Register with NeighborOrch. + neighborOrchFdbUnregister(entry.mac, vlan.m_vlan_info.vlan_id); + + SWSS_LOG_NOTICE("do Task Add: Delete ICCP FDB found in cache: " + "Mac: %s Vlan: %d port:%s type:%s",entry.mac.to_string().c_str(), + vlan.m_vlan_info.vlan_id, it->second.port.c_str(), it->second.type.c_str()); + } + } + it = consumer.m_toSync.erase(it); + } else it++; - - /* Remove corresponding APP_DB entry if type is 'dynamic' */ - // FIXME: The modification of table is not thread safe. - // Uncomment this after this issue is fixed. - // if (type == "dynamic") - // { - // m_table.del(kfvKey(t)); - // } } else if (op == DEL_COMMAND) { - if (removeFdbEntry(entry)) + if (removeFdbEntry(entry, origin)) + { + if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + { + //Un-Register with NeighborOrch. + neighborOrchFdbUnregister(entry.mac, vlan.m_vlan_info.vlan_id); + } + it = consumer.m_toSync.erase(it); + } else it++; - } else { @@ -338,6 +673,9 @@ void FdbOrch::doTask(Consumer& consumer) } } } +extern volatile bool g_record; +extern void recordLine(std::string s); +extern std::string joinFieldValues(_In_ const std::vector &values); void FdbOrch::doTask(NotificationConsumer& consumer) { @@ -348,15 +686,14 @@ void FdbOrch::doTask(NotificationConsumer& consumer) return; } - sai_status_t status; std::string op; std::string data; std::vector values; - consumer.pop(op, data, values); - if (&consumer == m_flushNotificationsConsumer) { + consumer.pop(op, data, values); + if (op == "ALL") { /* @@ -389,43 +726,75 @@ void FdbOrch::doTask(NotificationConsumer& consumer) return; } } - else if (&consumer == m_fdbNotificationConsumer && op == "fdb_event") + else if (&consumer == m_fdbNotificationConsumer) { - uint32_t count; - sai_fdb_event_notification_data_t *fdbevent = nullptr; - - sai_deserialize_fdb_event_ntf(data, count, &fdbevent); - - for (uint32_t i = 0; i < count; ++i) + SWSS_LOG_NOTICE("FDBNotification: START"); + size_t batch_size=0; + while((consumer.peek()==1) && (batch_size++ <= DEFAULT_NC_POP_BATCH_SIZE)) { - sai_object_id_t oid = SAI_NULL_OBJECT_ID; + uint32_t count; + sai_fdb_event_notification_data_t *fdbevent = nullptr; + extern void handle_fdb_event(_In_ const std::string &data); - for (uint32_t j = 0; j < fdbevent[i].attr_count; ++j) + consumer.pop(op, data, values); + if(op == "fdb_event") { - if (fdbevent[i].attr[j].id == SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID) + if (g_record) { - oid = fdbevent[i].attr[j].value.oid; - break; + recordLine("n|" + op + "|" + data + "|" + joinFieldValues(values)); } - } - this->update(fdbevent[i].event_type, &fdbevent[i].fdb_entry, oid); - } + /* The sai_redis fdb handling is moved here so that both + * reference count updates (sai_redis and portsOrch) + * happen in same context to avoid any mismatch. + */ + handle_fdb_event(data); - sai_deserialize_free_fdb_event_ntf(count, fdbevent); + sai_deserialize_fdb_event_ntf(data, count, &fdbevent); + + for (uint32_t i = 0; i < count; ++i) + { + sai_object_id_t oid = SAI_NULL_OBJECT_ID; + + for (uint32_t j = 0; j < fdbevent[i].attr_count; ++j) + { + if (fdbevent[i].attr[j].id == SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID) + { + oid = fdbevent[i].attr[j].value.oid; + break; + } + } + + this->update(fdbevent[i].event_type, &fdbevent[i].fdb_entry, oid); + } + + sai_deserialize_free_fdb_event_ntf(count, fdbevent); + } + } + SWSS_LOG_NOTICE("FDBNotification: Processed %lu notifications", batch_size); } } void FdbOrch::updateVlanMember(const VlanMemberUpdate& update) { + Port port; + + string port_name = update.member.m_alias; + string vlan_name = update.vlan.m_alias; + SWSS_LOG_ENTER(); + if (!m_portsOrch->getPort(port_name, port)) + { + SWSS_LOG_ERROR("could not locate port from alias %s", port_name.c_str()); + return; + } + if (!update.add) { - return; // we need additions only + return; } - string port_name = update.member.m_alias; auto fdb_list = std::move(saved_fdb_entries[port_name]); if(!fdb_list.empty()) { @@ -433,94 +802,355 @@ void FdbOrch::updateVlanMember(const VlanMemberUpdate& update) { // try to insert an FDB entry. If the FDB entry is not ready to be inserted yet, // it would be added back to the saved_fdb_entries structure by addFDBEntry() - (void)addFdbEntry(fdb.entry, port_name, fdb.type); + if(fdb.vlanId == update.vlan.m_vlan_info.vlan_id) + { + FdbEntry entry; + entry.mac = fdb.mac; + entry.bv_id = update.vlan.m_vlan_info.vlan_oid; + (void)addFdbEntry(entry, port_name, fdb.type, fdb.origin); + } + else + { + saved_fdb_entries[port_name].push_back(fdb); + } } } } -bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const string& type) +bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const string& type, FdbOrigin origin) { - SWSS_LOG_ENTER(); + Port vlan; + Port port; - sai_fdb_entry_t fdb_entry; + SWSS_LOG_ENTER(); + SWSS_LOG_NOTICE("mac=%s bv_id=0x%lx port_name=%s type=%s origin=%d", entry.mac.to_string().c_str(), entry.bv_id, port_name.c_str(), type.c_str(), origin); - fdb_entry.switch_id = gSwitchId; - memcpy(fdb_entry.mac_address, entry.mac.getMac(), sizeof(sai_mac_t)); - fdb_entry.bv_id = entry.bv_id; + if (!m_portsOrch->getPort(entry.bv_id, vlan)) + { + SWSS_LOG_NOTICE("addFdbEntry: Failed to locate vlan port from bv_id 0x%lx", entry.bv_id); + return false; + } - Port port; /* Retry until port is created */ - if (!m_portsOrch->getPort(port_name, port)) + if (!m_portsOrch->getPort(port_name, port) || (port.m_bridge_port_id == SAI_NULL_OBJECT_ID)) { - SWSS_LOG_DEBUG("Saving a fdb entry until port %s becomes active", port_name.c_str()); - saved_fdb_entries[port_name].push_back({entry, type}); + SWSS_LOG_NOTICE("Saving the fdb entry until port %s becomes active", port_name.c_str()); + saved_fdb_entries[port_name].push_back({entry.mac, + vlan.m_vlan_info.vlan_id, type, origin}); return true; } - /* Retry until port is added to the VLAN */ - if (!port.m_bridge_port_id) + /* Retry until port is member of vlan*/ + if (vlan.m_members.find(port_name) == vlan.m_members.end()) { - SWSS_LOG_DEBUG("Saving a fdb entry until port %s has got a bridge port ID", port_name.c_str()); - saved_fdb_entries[port_name].push_back({entry, type}); + SWSS_LOG_NOTICE("Saving the fdb entry until port %s becomes vlan %s member", port_name.c_str(), vlan.m_alias.c_str()); + if (type != "dynamic_local") + saved_fdb_entries[port_name].push_back({entry.mac, + vlan.m_vlan_info.vlan_id, type, origin}); return true; } + sai_status_t status; + sai_fdb_entry_t fdb_entry; + fdb_entry.switch_id = gSwitchId; + memcpy(fdb_entry.mac_address, entry.mac.getMac(), sizeof(sai_mac_t)); + fdb_entry.bv_id = entry.bv_id; + + Port oldPort; + string oldType; + FdbOrigin oldOrigin = FDB_ORIGIN_INVALID ; + bool macUpdate = false; + auto it = m_entries.find(entry); + if(it != m_entries.end()) + { + oldType = it->second.type; + oldOrigin = it->second.origin; + + /* get existing port and type */ + if (!m_portsOrch->getPortByBridgePortId(it->second.bridge_port_id, oldPort)) + { + SWSS_LOG_ERROR("Existing port 0x%lx details not found", it->second.bridge_port_id); + return false; + } + + if((oldOrigin == origin) && (oldType == type) && (port.m_bridge_port_id == it->second.bridge_port_id)) + { + /* Duplicate Mac */ + SWSS_LOG_NOTICE("FdbOrch: mac=%s %s port=%s type=%s origin=%d is duplicate", entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str(), type.c_str(), origin); + return true; + } + else if(origin != oldOrigin) + { + /* Mac origin has changed */ + if((oldType == "static") && (oldOrigin == FDB_ORIGIN_PROVISIONED)) + { + /* old mac was static and provisioned, it can not be changed by Remote Mac */ + SWSS_LOG_NOTICE("Already existing static MAC:%s in Vlan:%d. " + "Received same MAC from peer:%s; " + "Peer mac ignored", + entry.mac.to_string().c_str(), vlan.m_vlan_info.vlan_id, + remote_ip.c_str()); + + return true; + } + else if ((oldOrigin == FDB_ORIGIN_LEARN) && (origin == FDB_ORIGIN_MCLAG_ADVERTIZED)) + { + if ((port.m_bridge_port_id == it->second.bridge_port_id) && (oldType == "dynamic") && (type == "dynamic_local")) + { + SWSS_LOG_NOTICE("FdbOrch: mac=%s %s port=%s type=%s origin=%d old_origin=%d" + " old_type=%s local mac exists," + " received dynamic_local from iccpd, ignore update", + entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str(), + type.c_str(), origin, oldOrigin, oldType.c_str()); + + return true; + } + } + } + else /* (origin == oldOrigin) */ + { + /* Mac origin is same, all changes are allowed */ + /* Allowed + * Bridge-port is changed or/and + * Sticky bit from remote is modified or + * provisioned mac is converted from static<-->dynamic + */ + } + + macUpdate = true; + } + sai_attribute_t attr; vector attrs; attr.id = SAI_FDB_ENTRY_ATTR_TYPE; - attr.value.s32 = (type == "dynamic") ? SAI_FDB_ENTRY_TYPE_DYNAMIC : SAI_FDB_ENTRY_TYPE_STATIC; + if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + { + if (type == "dynamic_local") + attr.value.s32 = SAI_FDB_ENTRY_TYPE_DYNAMIC; + else + attr.value.s32 = (type == "dynamic") ? SAI_FDB_ENTRY_TYPE_STATIC_MACMOVE : SAI_FDB_ENTRY_TYPE_STATIC; + } + else + { + attr.value.s32 = (type == "dynamic") ? SAI_FDB_ENTRY_TYPE_DYNAMIC : SAI_FDB_ENTRY_TYPE_STATIC; + } attrs.push_back(attr); attr.id = SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID; attr.value.oid = port.m_bridge_port_id; attrs.push_back(attr); + /* PACKET ACTION is FORWARD by default; no need to set it */ + /** attr.id = SAI_FDB_ENTRY_ATTR_PACKET_ACTION; attr.value.s32 = SAI_PACKET_ACTION_FORWARD; attrs.push_back(attr); + */ - if (m_entries.count(entry) != 0) // we already have such entries + if(macUpdate) + { + SWSS_LOG_NOTICE("MAC-Update FDB %s in %s on from-%s:to-%s from-%s:to-%s origin-%d-to-%d", + entry.mac.to_string().c_str(), vlan.m_alias.c_str(), oldPort.m_alias.c_str(), + port_name.c_str(), oldType.c_str(), type.c_str(), oldOrigin, origin); + for(auto itr : attrs) + { + status = sai_fdb_api->set_fdb_entry_attribute(&fdb_entry, &itr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("macUpdate-Failed for attr.id=0x%x for FDB %s in %s on %s, rv:%d", + itr.id, entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str(), status); + return false; + } + } + if (oldPort.m_bridge_port_id != port.m_bridge_port_id) + { + oldPort.m_fdb_count--; + m_portsOrch->setPort(oldPort.m_alias, oldPort); + port.m_fdb_count++; + m_portsOrch->setPort(port.m_alias, port); + } + } + else { - removeFdbEntry(entry); + SWSS_LOG_NOTICE("MAC-Create %s FDB %s in %s on %s", type.c_str(), entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str()); + + status = sai_fdb_api->create_fdb_entry(&fdb_entry, (uint32_t)attrs.size(), attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create %s FDB %s in %s on %s, rv:%d", + type.c_str(), entry.mac.to_string().c_str(), + vlan.m_alias.c_str(), port_name.c_str(), status); + return false; //FIXME: it should be based on status. Some could be retried, some not + } + port.m_fdb_count++; + m_portsOrch->setPort(port.m_alias, port); + vlan.m_fdb_count++; + m_portsOrch->setPort(vlan.m_alias, vlan); } - sai_status_t status = sai_fdb_api->create_fdb_entry(&fdb_entry, (uint32_t)attrs.size(), attrs.data()); - if (status != SAI_STATUS_SUCCESS) + FdbData fdbData; + fdbData.bridge_port_id = port.m_bridge_port_id; + fdbData.type = type; + fdbData.origin = origin; + fdbData.origin_sources = origin; + + // overwrite the type and origin + if ((origin == FDB_ORIGIN_MCLAG_ADVERTIZED) && (type == "dynamic_local")) { - SWSS_LOG_ERROR("Failed to create %s FDB %s on %s, rv:%d", - type.c_str(), entry.mac.to_string().c_str(), port_name.c_str(), status); - return false; //FIXME: it should be based on status. Some could be retried, some not + //If the MAC is dynamic_local change the origin accordingly + //MAC is added/updated as dynamic to allow aging. + fdbData.origin = FDB_ORIGIN_LEARN; + fdbData.type = "dynamic"; } - SWSS_LOG_NOTICE("Create %s FDB %s on %s", type.c_str(), entry.mac.to_string().c_str(), port_name.c_str()); + // If updating the advertised MAC save old learn information. + if (macUpdate && ((oldOrigin == FDB_ORIGIN_MCLAG_ADVERTIZED) && type != "dynamic_local")) + fdbData.origin_sources |= oldOrigin; - (void) m_entries.insert(entry); + m_entries[entry] = fdbData; - gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); + string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string(); - FdbUpdate update = {entry, port, true}; - for (auto observer: m_observers) + if ( (type == "dynamic_local") || (origin != FDB_ORIGIN_MCLAG_ADVERTIZED)) { - observer->update(SUBJECT_TYPE_FDB_CHANGE, &update); + /* State-DB is updated only for Local Mac addresses */ + // Write to StateDb + std::vector fvs; + fvs.push_back(FieldValueTuple("port", port_name)); + if (type == "dynamic_local") + fvs.push_back(FieldValueTuple("type", "dynamic")); + else + fvs.push_back(FieldValueTuple("type", type)); + m_fdbStateTable.set(key, fvs); + } + else if (macUpdate && (oldOrigin != FDB_ORIGIN_MCLAG_ADVERTIZED)) + { + /* origin is FDB_ORIGIN_ADVERTIZED and it is mac-update + * so delete from StateDb since we only keep local fdbs + * in state-db + */ + m_fdbStateTable.del(key); } + //register with NeighborOrch for ICCP learned MAC addresses + if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED && (type != "dynamic_local")) + { + //Register with NeighborOrch. + fdb_mac_cache fdbmac; + memset(&fdbmac, 0, sizeof(fdb_mac_cache)); + fdbmac.mac = entry.mac; + fdbmac.fdid = vlan.m_vlan_info.vlan_id; + fdbmac.alias = port_name; + fdbmac.type = type; + fdbmac.origin = origin; + + if (gNeighOrch->addFdbNeighCache(fdbmac, FDB_SYNCD_MAC)) + SWSS_LOG_NOTICE("AddFdbEntry: Register ICCP MAC with NeighOrch Success: " + "Mac: %s Vlan: %d port:%s type:%s", entry.mac.to_string().c_str(), + fdbmac.fdid, port_name.c_str(), type.c_str()); + else + SWSS_LOG_NOTICE("AddFdbEntry: Register ICCP MAC with NeighOrch Failed: " + "Mac: %s Vlan: %d port:%s type:%s", entry.mac.to_string().c_str(), + fdbmac.fdid, port_name.c_str(), type.c_str()); + } + else if (macUpdate && (oldOrigin == FDB_ORIGIN_MCLAG_ADVERTIZED) && + (origin != FDB_ORIGIN_MCLAG_ADVERTIZED)) + { + //UnRegister with NeighborOrch as MAC moved from iccp to non-iccp + neighborOrchFdbUnregister(entry.mac, vlan.m_vlan_info.vlan_id); + } + + if(!macUpdate) + { + gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); + } + + FdbUpdate update; + update.entry = entry; + update.port = port; + update.type = type; + update.add = true; + + // overwrite the type to dynamic. + if (type == "dynamic_local") + update.type = "dynamic"; + + notify(SUBJECT_TYPE_FDB_CHANGE, &update); + return true; } -bool FdbOrch::removeFdbEntry(const FdbEntry& entry) +bool FdbOrch::removeFdbEntry(const FdbEntry& entry, FdbOrigin origin) { + Port vlan; + Port port; + SWSS_LOG_ENTER(); - if (m_entries.count(entry) == 0) + SWSS_LOG_NOTICE("FdbOrch RemoveFDBEntry: mac=%s bv_id=0x%lx origin %d", entry.mac.to_string().c_str(), entry.bv_id, origin); + if (!m_portsOrch->getPort(entry.bv_id, vlan)) { - SWSS_LOG_ERROR("FDB entry isn't found. mac=%s bv_id=0x%" PRIx64, entry.mac.to_string().c_str(), entry.bv_id); + SWSS_LOG_DEBUG("FdbOrch notification: Failed to locate vlan port from bv_id 0x%lx", entry.bv_id); + return false; + } + + auto it= m_entries.find(entry); + if(it == m_entries.end()) + { + SWSS_LOG_NOTICE("FdbOrch RemoveFDBEntry: FDB entry isn't found. mac=%s bv_id=0x%lx", entry.mac.to_string().c_str(), entry.bv_id); + + /* check whether the entry is in the saved fdb, if so delete it from there. */ + deleteFdbEntryFromSavedFDB(entry.mac, vlan.m_vlan_info.vlan_id, origin, ""); return true; } - sai_status_t status; + FdbData fdbData = it->second; + + if (!m_portsOrch->getPortByBridgePortId(fdbData.bridge_port_id, port)) + { + SWSS_LOG_NOTICE("FdbOrch RemoveFDBEntry: Failed to locate port from bridge_port_id 0x%lx", fdbData.bridge_port_id); + return false; + } + + SWSS_LOG_NOTICE("FdbOrch RemoveFDBEntry: mac=%s bv_id=0x%lx existing origin %d, port oper_status: %s , is malg interface: %s", + entry.mac.to_string().c_str(), entry.bv_id, fdbData.origin, (port.m_oper_status == SAI_PORT_OPER_STATUS_DOWN) ? "DOWN":"UP", + gMlagOrch->isMlagInterface(port.m_alias) ? "true":"false"); + if(fdbData.origin != origin) + { + if ((origin == FDB_ORIGIN_MCLAG_ADVERTIZED) && (fdbData.origin == FDB_ORIGIN_LEARN) && + (port.m_oper_status == SAI_PORT_OPER_STATUS_DOWN) && (gMlagOrch->isMlagInterface(port.m_alias))) + { + //check if the local MCLAG port is down, if yes then continue delete the local MAC + origin = FDB_ORIGIN_LEARN; + SWSS_LOG_NOTICE("FdbOrch RemoveFDBEntry: mac=%s fdb del origin is MCLAG; delete local mac as port %s is down", + entry.mac.to_string().c_str(), port.m_alias.c_str()); + } + else + { + // delete origin from learn sources. + fdbData.origin_sources &= ~origin; + m_entries[entry] = fdbData; + SWSS_LOG_NOTICE("FdbOrch RemoveFDBEntry: mac=%s fdb origin is different; found_origin:%d delete_origin:%d", + entry.mac.to_string().c_str(), fdbData.origin, origin); + + /* We may still have the mac in saved-fdb probably due to unavailability + * of bridge-port. check whether the entry is in the saved fdb, + * if so delete it from there. */ + deleteFdbEntryFromSavedFDB(entry.mac, vlan.m_vlan_info.vlan_id, origin, ""); + + return true; + } + } + + //unset the current origin flag. + fdbData.origin_sources &= ~origin; + + string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string(); + + sai_status_t status = SAI_STATUS_SUCCESS; sai_fdb_entry_t fdb_entry; fdb_entry.switch_id = gSwitchId; memcpy(fdb_entry.mac_address, entry.mac.getMac(), sizeof(sai_mac_t)); @@ -534,18 +1164,79 @@ bool FdbOrch::removeFdbEntry(const FdbEntry& entry) return true; //FIXME: it should be based on status. Some could be retried. some not } - (void)m_entries.erase(entry); + SWSS_LOG_NOTICE("Removed mac=%s bv_id=0x%lx port:%s", + entry.mac.to_string().c_str(), entry.bv_id, port.m_alias.c_str()); - gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); + port.m_fdb_count--; + m_portsOrch->setPort(port.m_alias, port); + vlan.m_fdb_count--; + m_portsOrch->setPort(vlan.m_alias, vlan); + (void)m_entries.erase(entry); - Port port; - m_portsOrch->getPortByBridgePortId(entry.bv_id, port); - FdbUpdate update = {entry, port, false}; - for (auto observer: m_observers) + // Remove in StateDb + if (fdbData.origin != FDB_ORIGIN_MCLAG_ADVERTIZED) { - observer->update(SUBJECT_TYPE_FDB_CHANGE, &update); + m_fdbStateTable.del(key); } + gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); + + FdbUpdate update; + update.entry = entry; + update.port = port; + update.type = fdbData.type; + update.add = false; + + notify(SUBJECT_TYPE_FDB_CHANGE, &update); + return true; } + +void FdbOrch::deleteFdbEntryFromSavedFDB(const MacAddress &mac, + const unsigned short &vlanId, FdbOrigin origin, const string portName) +{ + bool found=false; + SavedFdbEntry entry; + entry.mac = mac; + entry.vlanId = vlanId; + entry.type = "static"; + /* Below members are unused during delete compare */ + entry.origin = origin; + + for (auto& itr: saved_fdb_entries) + { + if(portName.empty() || (portName == itr.first)) + { + auto iter = saved_fdb_entries[itr.first].begin(); + while(iter != saved_fdb_entries[itr.first].end()) + { + if (*iter == entry) + { + if(iter->origin == origin) + { + SWSS_LOG_NOTICE("FDB entry found in saved fdb. deleting..." + "mac=%s vlan_id=0x%x origin:%d port:%s", + mac.to_string().c_str(), vlanId, origin, + itr.first.c_str()); + saved_fdb_entries[itr.first].erase(iter); + + found=true; + break; + } + else + { + SWSS_LOG_NOTICE("FDB entry found in saved fdb, but Origin is " + "different mac=%s vlan_id=0x%x reqOrigin:%d " + "foundOrigin:%d port:%s, IGNORED", + mac.to_string().c_str(), vlanId, origin, + iter->origin, itr.first.c_str()); + } + } + iter++; + } + } + if(found) + break; + } +} diff --git a/orchagent/fdborch.h b/orchagent/fdborch.h index 3125b3112d..4e504a5b89 100644 --- a/orchagent/fdborch.h +++ b/orchagent/fdborch.h @@ -5,6 +5,14 @@ #include "observer.h" #include "portsorch.h" +enum FdbOrigin +{ + FDB_ORIGIN_INVALID = 0, + FDB_ORIGIN_LEARN = 1, + FDB_ORIGIN_PROVISIONED = 2, + FDB_ORIGIN_MCLAG_ADVERTIZED = 8 +}; + struct FdbEntry { MacAddress mac; @@ -14,28 +22,76 @@ struct FdbEntry { return tie(mac, bv_id) < tie(other.mac, other.bv_id); } + bool operator==(const FdbEntry& other) const + { + return tie(mac, bv_id) == tie(other.mac, other.bv_id); + } +}; + +struct VlanFdbEntry +{ + MacAddress mac; + unsigned short vlan_id; + + bool operator<(const VlanFdbEntry& other) const + { + return tie(mac, vlan_id) < tie(other.mac, other.vlan_id); + } + bool operator==(const VlanFdbEntry& other) const + { + return tie(mac, vlan_id) == tie(other.mac, other.vlan_id); + } }; struct FdbUpdate { FdbEntry entry; Port port; + string type; bool add; }; +struct FdbData +{ + sai_object_id_t bridge_port_id; + string type; + FdbOrigin origin; + unsigned int origin_sources; // stores all origins MAC is learned from. + /** + {"dynamic", FDB_ORIGIN_LEARN} => dynamically learnt + {"dynamic", FDB_ORIGIN_PROVISIONED} => provisioned dynamic with swssconfig in APPDB + {"dynamic", FDB_ORIGIN_ADVERTIZED} => synced from remote device e.g. BGP MAC route + {"static", FDB_ORIGIN_LEARN} => Invalid + {"static", FDB_ORIGIN_PROVISIONED} => statically provisioned + {"static", FDB_ORIGIN_ADVERTIZED} => sticky synced from remote device + */ +}; + +struct MclagFdbData +{ + string port; + string type; +}; + struct SavedFdbEntry { - FdbEntry entry; + MacAddress mac; + unsigned short vlanId; string type; + FdbOrigin origin; + bool operator==(const SavedFdbEntry& other) const + { + return tie(mac, vlanId) == tie(other.mac, other.vlanId); + } }; typedef unordered_map> fdb_entries_by_port_t; -class FdbOrch: public Orch, public Subject, public Observer +class FdbOrch: public Orch, public Subject, public Observer, public DebugDump { public: - FdbOrch(TableConnector applDbConnector, TableConnector stateDbConnector, PortsOrch *port); + FdbOrch(DBConnector* applDbConnector, vector appFdbTables, TableConnector stateDbFdbConnector, PortsOrch *port); ~FdbOrch() { @@ -46,12 +102,18 @@ class FdbOrch: public Orch, public Subject, public Observer void update(sai_fdb_event_t, const sai_fdb_entry_t *, sai_object_id_t); void update(SubjectType type, void *cntx); bool getPort(const MacAddress&, uint16_t, Port&); + int flushFdbByPort(const string &, bool flush_static, bool flush_mclag); + bool debugdumpCLI(KeyOpFieldsValuesTuple t); + bool removeFdbEntry(const FdbEntry& entry, FdbOrigin origin=FDB_ORIGIN_PROVISIONED); + + static const int fdborch_pri; private: PortsOrch *m_portsOrch; - set m_entries; + map m_entries; + map m_iccpEntries; fdb_entries_by_port_t saved_fdb_entries; - Table m_table; + vector m_appTables; Table m_fdbStateTable; NotificationConsumer* m_flushNotificationsConsumer; NotificationConsumer* m_fdbNotificationConsumer; @@ -60,10 +122,12 @@ class FdbOrch: public Orch, public Subject, public Observer void doTask(NotificationConsumer& consumer); void updateVlanMember(const VlanMemberUpdate&); - bool addFdbEntry(const FdbEntry&, const string&, const string&); - bool removeFdbEntry(const FdbEntry&); + bool addFdbEntry(const FdbEntry&, const string&, const string&, FdbOrigin origin); + void deleteFdbEntryFromSavedFDB(const MacAddress &mac, const unsigned short + &vlanId, FdbOrigin origin=FDB_ORIGIN_PROVISIONED, const string portName=""); bool storeFdbEntryState(const FdbUpdate& update); + }; #endif /* SWSS_FDBORCH_H */ diff --git a/orchagent/isolationgrouporch.cpp b/orchagent/isolationgrouporch.cpp new file mode 100644 index 0000000000..618f2a3995 --- /dev/null +++ b/orchagent/isolationgrouporch.cpp @@ -0,0 +1,956 @@ +/* + * Copyright 2019 Broadcom. The term "Broadcom" refers to Broadcom Inc. + * and/or its subsidiaries. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "isolationgrouporch.h" +#include "converter.h" +#include "tokenize.h" +#include "portsorch.h" + +extern sai_object_id_t gSwitchId; +extern PortsOrch *gPortsOrch; +extern sai_isolation_group_api_t* sai_isolation_group_api; +extern sai_bridge_api_t *sai_bridge_api; +extern sai_port_api_t *sai_port_api; +extern IsoGrpOrch *gIsoGrpOrch; + +IsoGrpOrch::IsoGrpOrch(vector &connectors) : Orch(connectors) +{ + SWSS_LOG_ENTER(); + this->installDebugClis(); + gPortsOrch->attach(this); +} + +IsoGrpOrch::~IsoGrpOrch() +{ + SWSS_LOG_ENTER(); +} + +shared_ptr +IsoGrpOrch::getIsolationGroup(string name) +{ + SWSS_LOG_ENTER(); + + shared_ptr ret = nullptr; + + auto grp = m_isolationGrps.find(name); + if (grp != m_isolationGrps.end()) + { + ret = grp->second; + } + + return ret; +} + +void +IsoGrpOrch::doTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + + if (!gPortsOrch->allPortsReady()) + { + return; + } + + string table_name = consumer.getTableName(); + if (table_name == APP_ISOLATION_GROUP_TABLE_NAME) + { + doIsoGrpTblTask(consumer); + } + else + { + SWSS_LOG_ERROR("Invalid table %s", table_name.c_str()); + } +} + +void +IsoGrpOrch::doIsoGrpTblTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + isolation_group_status_t status = ISO_GRP_STATUS_SUCCESS; + + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + KeyOpFieldsValuesTuple t = it->second; + string op = kfvOp(t); + string key = kfvKey(t); + + size_t sep_loc = key.find(consumer.getConsumerTable()->getTableNameSeparator().c_str()); + string name = key.substr(0, sep_loc); + + SWSS_LOG_DEBUG("Op:%s IsoGrp:%s", op.c_str(), name.c_str()); + + if (op == SET_COMMAND) + { + isolation_group_type_t type = ISOLATION_GROUP_TYPE_INVALID; + string descr(""); + string bind_ports(""); + string mem_ports(""); + + for (auto itp : kfvFieldsValues(t)) + { + string attr_name = to_upper(fvField(itp)); + string attr_value = fvValue(itp); + + if (attr_name == ISOLATION_GRP_DESCRIPTION) + { + descr = attr_value; + } + else if (attr_name == ISOLATION_GRP_TYPE) + { + if (ISOLATION_GRP_TYPE_PORT == attr_value) + { + type = ISOLATION_GROUP_TYPE_PORT; + } + else if (ISOLATION_GRP_TYPE_BRIDGE_PORT == attr_value) + { + type = ISOLATION_GROUP_TYPE_BRIDGE_PORT; + } + } + else if (attr_name == ISOLATION_GRP_PORTS) + { + bind_ports = attr_value; + } + else if (attr_name == ISOLATION_GRP_MEMBERS) + { + mem_ports = attr_value; + } + } + + status = addIsolationGroup(name, type, descr, bind_ports, mem_ports); + if (ISO_GRP_STATUS_SUCCESS == status) + { + auto grp = getIsolationGroup(name); + if (!grp->isObserver(this)) + { + IsolationGroupUpdate update = {grp.get(), true}; + grp->notifyObservers(SUBJECT_TYPE_ISOLATION_GROUP_CHANGE, &update); + + grp->attach(this); + } + } + } + else + { + auto grp = getIsolationGroup(name); + if (grp) + { + grp->detach(this); + + /* Send a notification and see if observers want to detach */ + IsolationGroupUpdate update = {grp.get(), false}; + grp->notifyObservers(SUBJECT_TYPE_ISOLATION_GROUP_CHANGE, &update); + } + + // Finally delete it if it + status = delIsolationGroup(name); + } + + if (status != ISO_GRP_STATUS_RETRY) + { + it = consumer.m_toSync.erase(it); + } + else + { + it++; + } + } +} + +isolation_group_status_t +IsoGrpOrch::addIsolationGroup(string name, isolation_group_type_t type, string descr, string bindPorts, string memPorts) +{ + SWSS_LOG_ENTER(); + + isolation_group_status_t status = ISO_GRP_STATUS_SUCCESS; + + // Add Or Update + auto grp = getIsolationGroup(name); + if (!grp) + { + // Add Case + auto grp = make_shared(name, type, descr); + + status = grp->create(); + if (ISO_GRP_STATUS_SUCCESS != status) + { + return status; + } + grp->setMembers(memPorts); + grp->setBindPorts(bindPorts); + this->m_isolationGrps[name] = grp; + } + else if ((grp) && (grp->getType() == type)) + { + grp->m_description = descr; + grp->setMembers(memPorts); + grp->setBindPorts(bindPorts); + } + else + { + SWSS_LOG_ERROR("Isolation group type update to %d not permitted", type); + status = ISO_GRP_STATUS_FAIL; + } + + return status; +} + +isolation_group_status_t +IsoGrpOrch::delIsolationGroup(string name) +{ + SWSS_LOG_ENTER(); + + auto grp = m_isolationGrps.find(name); + if (grp != m_isolationGrps.end()) + { + if (!grp->second->hasObservers()) + { + grp->second->destroy(); + m_isolationGrps.erase(name); + } + else + { + SWSS_LOG_NOTICE("%s group has observers. Not deleting", name.c_str()); + } + } + + return ISO_GRP_STATUS_SUCCESS; +} + + +void +IsoGrpOrch::update(SubjectType type, void *cntx) +{ + SWSS_LOG_ENTER(); + + if (type != SUBJECT_TYPE_BRIDGE_PORT_CHANGE) + { + return; + } + + for (auto kv : m_isolationGrps) + { + kv.second->update(type, cntx); + } +} + + +isolation_group_status_t +IsolationGroup::create() +{ + SWSS_LOG_ENTER(); + sai_attribute_t attr; + + attr.id = SAI_ISOLATION_GROUP_ATTR_TYPE; + if (ISOLATION_GROUP_TYPE_BRIDGE_PORT == m_type) + { + attr.value.s32 = SAI_ISOLATION_GROUP_TYPE_BRIDGE_PORT; + } + else + { + attr.value.s32 = SAI_ISOLATION_GROUP_TYPE_PORT; + } + + sai_status_t status = sai_isolation_group_api->create_isolation_group(&m_oid, gSwitchId, 1, &attr); + if (SAI_STATUS_SUCCESS != status) + { + SWSS_LOG_ERROR("Error %d creating isolation group %s", status, m_name.c_str()); + return ISO_GRP_STATUS_FAIL; + } + else + { + SWSS_LOG_NOTICE("Isolation group %s has oid %lx", m_name.c_str(), m_oid); + } + + return ISO_GRP_STATUS_SUCCESS; +} + +isolation_group_status_t +IsolationGroup::destroy() +{ + SWSS_LOG_ENTER(); + sai_attribute_t attr; + + // Remove all bindings + attr.value.oid = SAI_NULL_OBJECT_ID; + for (auto p : m_bind_ports) + { + Port port; + gPortsOrch->getPort(p, port); + if (ISOLATION_GROUP_TYPE_BRIDGE_PORT == m_type) + { + attr.id = SAI_BRIDGE_PORT_ATTR_ISOLATION_GROUP; + if (SAI_STATUS_SUCCESS != sai_bridge_api->set_bridge_port_attribute(port.m_bridge_port_id, &attr)) + { + SWSS_LOG_ERROR("Unable to del SAI_BRIDGE_PORT_ATTR_ISOLATION_GROUP from %s", p.c_str()); + } + else + { + SWSS_LOG_NOTICE("SAI_BRIDGE_PORT_ATTR_ISOLATION_GROUP removed from %s", p.c_str()); + } + } + else if (ISOLATION_GROUP_TYPE_PORT == m_type) + { + attr.id = SAI_PORT_ATTR_ISOLATION_GROUP; + if (SAI_STATUS_SUCCESS != sai_port_api->set_port_attribute( + (port.m_type == Port::PHY ? port.m_port_id : port.m_lag_id), + &attr)) + { + SWSS_LOG_ERROR("Unable to del SAI_PORT_ATTR_ISOLATION_GROUP from %s", p.c_str()); + } + else + { + SWSS_LOG_NOTICE("SAI_PORT_ATTR_ISOLATION_GROUP removed from %s", p.c_str()); + } + } + } + m_bind_ports.clear(); + m_pending_bind_ports.clear(); + + // Remove all members + for (auto &kv : m_members) + { + if (SAI_STATUS_SUCCESS != sai_isolation_group_api->remove_isolation_group_member(kv.second)) + { + SWSS_LOG_ERROR("Unable to delete isolation group member %lx from %s:%lx for port %s", + kv.second, + m_name.c_str(), + m_oid, + kv.first.c_str()); + } + else + { + SWSS_LOG_NOTICE("Isolation group member %lx deleted from %s:%lx for port %s", + kv.second, + m_name.c_str(), + m_oid, + kv.first.c_str()); + } + } + m_members.clear(); + + sai_status_t status = sai_isolation_group_api->remove_isolation_group(m_oid); + if (SAI_STATUS_SUCCESS != status) + { + SWSS_LOG_ERROR("Unable to delete isolation group %s with oid %lx", m_name.c_str(), m_oid); + } + else + { + SWSS_LOG_NOTICE("Isolation group %s with oid %lx deleted", m_name.c_str(), m_oid); + } + m_oid = SAI_NULL_OBJECT_ID; + + return ISO_GRP_STATUS_SUCCESS; +} + +isolation_group_status_t +IsolationGroup::addMember(Port &port) +{ + SWSS_LOG_ENTER(); + sai_object_id_t port_id = SAI_NULL_OBJECT_ID; + + if (m_type == ISOLATION_GROUP_TYPE_BRIDGE_PORT) + { + port_id = port.m_bridge_port_id; + } + else if (m_type == ISOLATION_GROUP_TYPE_PORT) + { + port_id = (port.m_type == Port::PHY ? port.m_port_id : port.m_lag_id); + } + + if (SAI_NULL_OBJECT_ID == port_id) + { + SWSS_LOG_NOTICE("Port %s not ready for for isolation group %s of type %d", + port.m_alias.c_str(), + m_name.c_str(), + m_type); + + m_pending_members.push_back(port.m_alias); + + return ISO_GRP_STATUS_SUCCESS; + } + + if (m_members.find(port.m_alias) != m_members.end()) + { + SWSS_LOG_DEBUG("Port %s:%lx already a member of %s", port.m_alias.c_str(), port_id, m_name.c_str()); + } + else + { + sai_object_id_t mem_id = SAI_NULL_OBJECT_ID; + sai_attribute_t mem_attr[2]; + sai_status_t status = SAI_STATUS_SUCCESS; + + mem_attr[0].id = SAI_ISOLATION_GROUP_MEMBER_ATTR_ISOLATION_GROUP_ID; + mem_attr[0].value.oid = m_oid; + mem_attr[1].id = SAI_ISOLATION_GROUP_MEMBER_ATTR_ISOLATION_OBJECT; + mem_attr[1].value.oid = port_id; + + status = sai_isolation_group_api->create_isolation_group_member(&mem_id, gSwitchId, 2, mem_attr); + if (SAI_STATUS_SUCCESS != status) + { + SWSS_LOG_ERROR("Unable to add %s:%lx as member of %s:%lx", port.m_alias.c_str(), port_id, + m_name.c_str(), m_oid); + return ISO_GRP_STATUS_FAIL; + } + else + { + m_members[port.m_alias] = mem_id; + SWSS_LOG_NOTICE("Port %s:%lx added as member of %s:%lx with oid %lx", + port.m_alias.c_str(), + port_id, + m_name.c_str(), + m_oid, + mem_id); + } + } + + return ISO_GRP_STATUS_SUCCESS; +} + +isolation_group_status_t +IsolationGroup::delMember(Port &port, bool do_fwd_ref) +{ + SWSS_LOG_ENTER(); + + if (m_members.find(port.m_alias) == m_members.end()) + { + auto node = find(m_pending_members.begin(), m_pending_members.end(), port.m_alias); + if (node != m_pending_members.end()) + { + m_pending_members.erase(node); + } + + return ISO_GRP_STATUS_SUCCESS; + } + + sai_object_id_t mem_id = m_members[port.m_alias]; + sai_status_t status = SAI_STATUS_SUCCESS; + + status = sai_isolation_group_api->remove_isolation_group_member(mem_id); + if (SAI_STATUS_SUCCESS != status) + { + SWSS_LOG_ERROR("Unable to delete isolation group member %lx for port %s and iso group %s %lx", + mem_id, + port.m_alias.c_str(), + m_name.c_str(), + m_oid); + + return ISO_GRP_STATUS_FAIL; + } + else + { + SWSS_LOG_NOTICE("Deleted isolation group member %lx for port %s and iso group %s %lx", + mem_id, + port.m_alias.c_str(), + m_name.c_str(), + m_oid); + + m_members.erase(port.m_alias); + } + + if (do_fwd_ref) + { + m_pending_members.push_back(port.m_alias); + } + + return ISO_GRP_STATUS_SUCCESS; +} + +isolation_group_status_t +IsolationGroup::setMembers(string ports) +{ + SWSS_LOG_ENTER(); + auto port_list = tokenize(ports, ','); + set portList(port_list.begin(), port_list.end()); + vector old_members = m_pending_members; + + for (auto mem : m_members) + { + old_members.emplace_back(mem.first); + } + + for (auto alias : portList) + { + if ((0 == alias.find("Ethernet")) || (0 == alias.find("PortChannel"))) + { + auto iter = find(old_members.begin(), old_members.end(), alias); + if (iter != old_members.end()) + { + SWSS_LOG_NOTICE("Port %s already part of %s. No change", alias.c_str(), m_name.c_str()); + old_members.erase(iter); + } + else + { + Port port; + if (!gPortsOrch->getPort(alias, port)) + { + SWSS_LOG_NOTICE("Port %s not found. Added it to m_pending_members", alias.c_str()); + m_pending_members.emplace_back(alias); + continue; + } + addMember(port); + } + } + else + { + SWSS_LOG_ERROR("Port %s not supported", alias.c_str()); + continue; + } + } + + // Remove all the ports which are no longer needed + for (auto alias : old_members) + { + Port port; + if (!gPortsOrch->getPort(alias, port)) + { + SWSS_LOG_ERROR("Port %s not found", alias.c_str()); + m_pending_members.erase(find(m_pending_members.begin(), m_pending_members.end(), port.m_alias)); + } + else + { + delMember(port); + } + } + + return ISO_GRP_STATUS_SUCCESS; +} + +isolation_group_status_t +IsolationGroup::bind(Port &port) +{ + SWSS_LOG_ENTER(); + sai_attribute_t attr; + sai_status_t status = SAI_STATUS_SUCCESS; + + if (find(m_bind_ports.begin(), m_bind_ports.end(), port.m_alias) != m_bind_ports.end()) + { + SWSS_LOG_NOTICE("isolation group %s of type %d already bound to Port %s", + m_name.c_str(), + m_type, + port.m_alias.c_str()); + + return ISO_GRP_STATUS_SUCCESS; + } + + attr.value.oid = m_oid; + if (m_type == ISOLATION_GROUP_TYPE_BRIDGE_PORT) + { + if (port.m_bridge_port_id != SAI_NULL_OBJECT_ID) + { + attr.id = SAI_BRIDGE_PORT_ATTR_ISOLATION_GROUP; + status = sai_bridge_api->set_bridge_port_attribute(port.m_bridge_port_id, &attr); + if (SAI_STATUS_SUCCESS != status) + { + SWSS_LOG_ERROR("Unable to set attribute %d value %lx to %s", + attr.id, + attr.value.oid, + port.m_alias.c_str()); + } + else + { + m_bind_ports.push_back(port.m_alias); + } + } + else + { + m_pending_bind_ports.push_back(port.m_alias); + SWSS_LOG_NOTICE("Port %s saved in pending bind ports for isolation group %s of type %d", + port.m_alias.c_str(), + m_name.c_str(), + m_type); + } + } + else if (m_type == ISOLATION_GROUP_TYPE_PORT) + { + if ((port.m_type == Port::PHY ? port.m_port_id : port.m_lag_id) != SAI_NULL_OBJECT_ID) + { + attr.id = SAI_PORT_ATTR_ISOLATION_GROUP; + status = sai_port_api->set_port_attribute((port.m_type == Port::PHY ? port.m_port_id : port.m_lag_id), &attr); + if (SAI_STATUS_SUCCESS != status) + { + SWSS_LOG_ERROR("Unable to set attribute %d value %lx to %s", + attr.id, + attr.value.oid, + port.m_alias.c_str()); + } + else + { + m_bind_ports.push_back(port.m_alias); + } + } + else + { + m_pending_bind_ports.push_back(port.m_alias); + SWSS_LOG_NOTICE("Port %s saved in pending bind ports for isolation group %s of type %d", + port.m_alias.c_str(), + m_name.c_str(), + m_type); + } + } + else + { + return ISO_GRP_STATUS_INVALID_PARAM; + } + + return ISO_GRP_STATUS_SUCCESS; +} + +isolation_group_status_t +IsolationGroup::unbind(Port &port, bool do_fwd_ref) +{ + SWSS_LOG_ENTER(); + sai_attribute_t attr; + sai_status_t status = SAI_STATUS_SUCCESS; + + if (find(m_bind_ports.begin(), m_bind_ports.end(), port.m_alias) == m_bind_ports.end()) + { + auto node = find(m_pending_bind_ports.begin(), m_pending_bind_ports.end(), port.m_alias); + if (node != m_pending_bind_ports.end()) + { + m_pending_bind_ports.erase(node); + } + + return ISO_GRP_STATUS_SUCCESS; + } + + attr.value.oid = SAI_NULL_OBJECT_ID; + if (m_type == ISOLATION_GROUP_TYPE_BRIDGE_PORT) + { + attr.id = SAI_BRIDGE_PORT_ATTR_ISOLATION_GROUP; + status = sai_bridge_api->set_bridge_port_attribute(port.m_bridge_port_id, &attr); + } + else if (m_type == ISOLATION_GROUP_TYPE_PORT) + { + attr.id = SAI_PORT_ATTR_ISOLATION_GROUP; + status = sai_port_api->set_port_attribute(port.m_port_id, &attr); + } + else + { + return ISO_GRP_STATUS_INVALID_PARAM; + } + + if (SAI_STATUS_SUCCESS != status) + { + SWSS_LOG_ERROR("Unable to set attribute %d value %lx to %s", attr.id, attr.value.oid, port.m_alias.c_str()); + } + else + { + m_bind_ports.erase(find(m_bind_ports.begin(), m_bind_ports.end(), port.m_alias)); + } + + if (do_fwd_ref) + { + m_pending_bind_ports.push_back(port.m_alias); + } + + return ISO_GRP_STATUS_SUCCESS; +} + +isolation_group_status_t +IsolationGroup::setBindPorts(string ports) +{ + SWSS_LOG_ENTER(); + vector old_bindports = m_pending_bind_ports; + auto port_list = tokenize(ports, ','); + set portList(port_list.begin(), port_list.end()); + + old_bindports.insert(old_bindports.end(), m_bind_ports.begin(), m_bind_ports.end()); + for (auto alias : portList) + { + if ((0 == alias.find("Ethernet")) || (0 == alias.find("PortChannel"))) + { + auto iter = find(old_bindports.begin(), old_bindports.end(), alias); + if (iter != old_bindports.end()) + { + SWSS_LOG_NOTICE("%s is already bound to %s", m_name.c_str(), alias.c_str()); + old_bindports.erase(iter); + } + else + { + Port port; + if (!gPortsOrch->getPort(alias, port)) + { + SWSS_LOG_NOTICE("Port %s not found. Added it to m_pending_bind_ports", alias.c_str()); + m_pending_bind_ports.emplace_back(alias); + return ISO_GRP_STATUS_INVALID_PARAM; + } + bind(port); + } + } + else + { + return ISO_GRP_STATUS_INVALID_PARAM; + } + } + + // Remove all the ports which are no longer needed + for (auto alias : old_bindports) + { + Port port; + if (!gPortsOrch->getPort(alias, port)) + { + SWSS_LOG_ERROR("Port %s not found", alias.c_str()); + m_pending_bind_ports.erase(find(m_pending_bind_ports.begin(), m_pending_bind_ports.end(), port.m_alias)); + } + else + { + unbind(port); + } + } + + return ISO_GRP_STATUS_SUCCESS; +} + +void +IsolationGroup::update(SubjectType, void *cntx) +{ + PortUpdate *update = static_cast(cntx); + Port &port = update->port; + + if (update->add) + { + auto mem_node = find(m_pending_members.begin(), m_pending_members.end(), port.m_alias); + if (mem_node != m_pending_members.end()) + { + m_pending_members.erase(mem_node); + addMember(port); + } + + auto bind_node = find(m_pending_bind_ports.begin(), m_pending_bind_ports.end(), port.m_alias); + if (bind_node != m_pending_bind_ports.end()) + { + m_pending_bind_ports.erase(bind_node); + bind(port); + } + } + else + { + auto bind_node = find(m_bind_ports.begin(), m_bind_ports.end(), port.m_alias); + if (bind_node != m_bind_ports.end()) + { + unbind(port, true); + } + + auto mem_node = m_members.find(port.m_alias); + if (mem_node != m_members.end()) + { + delMember(port, true); + } + } +} + + + +DEBUGSH_CLI(IsolationGroupOrchGroupCreate, + "debug system internal orchagent isogroup group create (port|bridge) NAME", + DEBUG_COMMAND, + SYSTEM_DEBUG_COMMAND, + INTERNAL_COMMAND, + "Orchagent related commands", + "Isolation group orch related commands", + "Isolation group related commands", + "Create Isolation group", + "Port Isolation group", + "Bridge Port Isolation group", + "Isolation group name") +{ + isolation_group_status_t status; + isolation_group_type_t type = ISOLATION_GROUP_TYPE_PORT; + auto grp = gIsoGrpOrch->getIsolationGroup(args[0]); + + if (cmd_tokens[7] == "bridge") + { + type = ISOLATION_GROUP_TYPE_BRIDGE_PORT; + } + if (grp) + { + DEBUGSH_OUT(this, "Group %s exists", args[0].c_str()); + } + + status = gIsoGrpOrch->addIsolationGroup(args[0], type, "", "", ""); + if (ISO_GRP_STATUS_SUCCESS == status) + { + DEBUGSH_OUT(this, "Group %s of type %s create success", args[0].c_str(), cmd_tokens[7].c_str()); + } + else + { + DEBUGSH_OUT(this, "Group %s of type %s create failed with %d error", args[0].c_str(), cmd_tokens[7].c_str(), + status); + } +} + +DEBUGSH_CLI(IsolationGroupOrchGroupDelete, + "debug system internal orchagent isogroup group delete NAME", + DEBUG_COMMAND, + SYSTEM_DEBUG_COMMAND, + INTERNAL_COMMAND, + "Orchagent related commands", + "Isolation group orch related commands", + "Isolation group related commands", + "Delete Isolation group", + "Isolation group name") +{ + auto status = gIsoGrpOrch->delIsolationGroup(args[0]); + if (ISO_GRP_STATUS_SUCCESS == status) + { + DEBUGSH_OUT(this, "Group %s delete success", args[0].c_str()); + } + else + { + DEBUGSH_OUT(this, "Group %s delete failed with %d error", args[0].c_str(), status); + } +} + +DEBUGSH_CLI(IsolationGroupOrchGroupSetBinding, + "debug system internal orchagent isogroup group update NAME set-bind PORTS", + DEBUG_COMMAND, + SYSTEM_DEBUG_COMMAND, + INTERNAL_COMMAND, + "Orchagent related commands", + "Isolation group orch related commands", + "Isolation group related commands", + "Update Isolation group", + "Isolation group Name", + "Set Isolation group Binding", + "Port Names which are comma(,) separated") +{ + auto grp = gIsoGrpOrch->getIsolationGroup(args[0]); + auto status = grp->setBindPorts(args[1]); + + if (ISO_GRP_STATUS_SUCCESS == status) + { + DEBUGSH_OUT(this, "Group %s binding set to %s", args[0].c_str(), args[1].c_str()); + } + else + { + DEBUGSH_OUT(this, "Error %d Group %s binding set to %s", status, args[0].c_str(), args[1].c_str()); + } +} + +DEBUGSH_CLI(IsolationGroupOrchGroupSetMembers, + "debug system internal orchagent isogroup group update NAME set-members PORTS", + DEBUG_COMMAND, + SYSTEM_DEBUG_COMMAND, + INTERNAL_COMMAND, + "Orchagent related commands", + "Isolation group orch related commands", + "Isolation group related commands", + "Update Isolation group", + "Isolation group Name", + "Set Isolation group member ports", + "Port Names which are comma(,) separated") +{ + auto grp = gIsoGrpOrch->getIsolationGroup(args[0]); + auto status = grp->setMembers(args[1]); + + if (ISO_GRP_STATUS_SUCCESS == status) + { + DEBUGSH_OUT(this, "Group %s members set to %s", args[0].c_str(), args[1].c_str()); + } + else + { + DEBUGSH_OUT(this, "Error %d Group %s members set to %s", status, args[0].c_str(), args[1].c_str()); + } +} + +DEBUGSH_CLI(IsolationGroupOrchGroupDump, + "show system internal orchagent isogroup group (NAME|)", + SHOW_COMMAND, + SYSTEM_DEBUG_COMMAND, + INTERNAL_COMMAND, + "Orchagent related commands", + "Isolation group orch related commands", + "Isolation group related commands", + "Name of Isolation Group") +{ + if (args.size()) + { + gIsoGrpOrch->debugShowGroup(this, args[0]); + } + else + { + gIsoGrpOrch->debugShowGroup(this); + } +} + + +void +IsoGrpOrch::installDebugClis() +{ + DebugShCmd::install(new IsolationGroupOrchGroupCreate()); + DebugShCmd::install(new IsolationGroupOrchGroupDelete()); + DebugShCmd::install(new IsolationGroupOrchGroupSetBinding()); + DebugShCmd::install(new IsolationGroupOrchGroupSetMembers()); + DebugShCmd::install(new IsolationGroupOrchGroupDump()); +} + +void +IsoGrpOrch::debugShowGroup(DebugShCmd *cmd, string name) +{ + if (name == "") + { + for (auto kv : m_isolationGrps) + { + DEBUGSH_OUT(cmd, "-------------------------------------------------------------------------------------\n"); + kv.second->debugShow(cmd); + } + } + else + { + auto grp = gIsoGrpOrch->getIsolationGroup(name); + if (grp) + { + grp->debugShow(cmd); + } + } +} + +void +IsolationGroup::debugShow(DebugShCmd *cmd) +{ + DEBUGSH_OUT(cmd, + "Name:%s Type:%s Oid:%016lx\n", + m_name.c_str(), + m_type == ISOLATION_GROUP_TYPE_PORT ? "Port" : "Bridge-Port", + m_oid); + + DEBUGSH_OUT(cmd, "Member Ports:\n"); + for (auto kv : m_members) + { + DEBUGSH_OUT(cmd, " %s -> 0x%016lx\n", kv.first.c_str(), kv.second); + } + + DEBUGSH_OUT(cmd, "\nBind Ports:\n"); + for (auto v : m_bind_ports) + { + DEBUGSH_OUT(cmd, " %s\n", v.c_str()); + } + + DEBUGSH_OUT(cmd, "\nPending Member Ports:\n"); + for (auto v : m_pending_members) + { + DEBUGSH_OUT(cmd, " %s\n", v.c_str()); + } + + DEBUGSH_OUT(cmd, "\nPending Bind Ports:\n"); + for (auto v : m_pending_bind_ports) + { + DEBUGSH_OUT(cmd, " %s\n", v.c_str()); + } + +} diff --git a/orchagent/isolationgrouporch.h b/orchagent/isolationgrouporch.h new file mode 100644 index 0000000000..15e45aa766 --- /dev/null +++ b/orchagent/isolationgrouporch.h @@ -0,0 +1,153 @@ +/* + * Copyright 2019 Broadcom. The term "Broadcom" refers to Broadcom Inc. + * and/or its subsidiaries. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ISOLATIONGROUPORCH_H__ +#define __ISOLATIONGROUPORCH_H__ + +#include "orch.h" +#include "port.h" +#include "observer.h" +#include "debugshcmd.h" + + +#define ISOLATION_GRP_DESCRIPTION "DESCRIPTION" +#define ISOLATION_GRP_TYPE "TYPE" +#define ISOLATION_GRP_PORTS "PORTS" +#define ISOLATION_GRP_MEMBERS "MEMBERS" +#define ISOLATION_GRP_TYPE_PORT "port" +#define ISOLATION_GRP_TYPE_BRIDGE_PORT "bridge-port" + +typedef enum IsolationGroupType +{ + ISOLATION_GROUP_TYPE_INVALID, + ISOLATION_GROUP_TYPE_PORT, + ISOLATION_GROUP_TYPE_BRIDGE_PORT +} isolation_group_type_t; + +typedef enum IsolationGroupStatus +{ + ISO_GRP_STATUS_RETRY = -100, + ISO_GRP_STATUS_FAIL, + ISO_GRP_STATUS_INVALID_PARAM, + ISO_GRP_STATUS_SUCCESS = 0 +}isolation_group_status_t; + +class IsolationGroup: public Observer, public Subject +{ +public: + string m_description; + + IsolationGroup(string name, isolation_group_type_t type = ISOLATION_GROUP_TYPE_PORT, string description=""): + m_name(name), + m_description(description), + m_type(type), + m_oid(SAI_NULL_OBJECT_ID) + { + } + + // Create Isolation group in SAI + isolation_group_status_t create(); + + // Delete Isolation group in SAI + isolation_group_status_t destroy(); + + // Add Isolation group member + isolation_group_status_t addMember(Port &port); + + // Delete Isolation group member + isolation_group_status_t delMember(Port &port, bool do_fwd_ref=false); + + // Set Isolation group members to the input. May involve adding or deleting members + isolation_group_status_t setMembers(string ports); + + // Apply the Isolation group to all linked ports + isolation_group_status_t bind(Port &port); + + // Remove the Isolation group from all linked ports + isolation_group_status_t unbind(Port &port, bool do_fwd_ref=false); + + // Set Isolation group binding to the input. May involve bind + isolation_group_status_t setBindPorts(string ports); + + void update(SubjectType, void *); + + isolation_group_type_t + getType() + { + return m_type; + } + + void notifyObservers(SubjectType type, void *cntx) + { + this->notify(type, cntx); + } + + void + debugShow(DebugShCmd *cmd); + +protected: + string m_name; + isolation_group_type_t m_type; + sai_object_id_t m_oid; + map m_members; // Members Name -> Member OID + vector m_bind_ports; // Ports in which this Iso Group is applied. + vector m_pending_members; + vector m_pending_bind_ports; +}; + +class IsoGrpOrch : public Orch, public Observer +{ +public: + IsoGrpOrch(vector &connectors); + + ~IsoGrpOrch(); + + shared_ptr + getIsolationGroup(string name); + + isolation_group_status_t + addIsolationGroup(string name, isolation_group_type_t type, string descr, string bindPorts, string memPorts); + + isolation_group_status_t + delIsolationGroup(string name); + + void update(SubjectType, void *); + + void + installDebugClis(); + + void + debugShowGroup(DebugShCmd *cmd, string name=""); + +private: + void + doTask(Consumer &consumer); + + void + doIsoGrpTblTask(Consumer &consumer); + + map> m_isolationGrps; +}; + +struct IsolationGroupUpdate +{ + IsolationGroup *group; + bool add; +}; + + +#endif /* __ISOLATIONGROUPORCH_H__ */ diff --git a/orchagent/mlagorch.cpp b/orchagent/mlagorch.cpp new file mode 100644 index 0000000000..838f0bac40 --- /dev/null +++ b/orchagent/mlagorch.cpp @@ -0,0 +1,579 @@ +/* + * Copyright 2019 Broadcom. The term "Broadcom" refers to Broadcom Inc. + * and/or its subsidiaries. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "portsorch.h" +#include "mlagorch.h" + +//Name of ISL isolation group must match with the name used by Mclagsyncd +#define MLAG_ISL_ISOLATION_GROUP_NAME "MCLAG_ISO_GRP" +#define MLAG_ISL_ISOLATION_GROUP_DESCR "Isolation group for MCLAG" + +using namespace std; +using namespace swss; + +extern PortsOrch *gPortsOrch; +extern IsoGrpOrch *gIsoGrpOrch; +extern MlagOrch *gMlagOrch; + +MlagOrch::MlagOrch(DBConnector *db, vector &tableNames): + Orch(db, tableNames) +{ + SWSS_LOG_ENTER(); + this->installDebugClis(); +} + +MlagOrch::~MlagOrch() +{ + SWSS_LOG_ENTER(); +} + +void MlagOrch::update(SubjectType type, void *cntx) +{ + IsolationGroupUpdate *update; + + if (type == SUBJECT_TYPE_ISOLATION_GROUP_CHANGE) + { + update = static_cast(cntx); + + if (update->add) + { + m_iccp_control_isolation_grp = true; + SWSS_LOG_NOTICE("MLAG yields control of isolation group"); + } + else + { + m_iccp_control_isolation_grp = false; + addAllMlagInterfacesToIsolationGroup(); + SWSS_LOG_NOTICE("MLAG takes control of isolation group"); + } + } +} + +DEBUGSH_CLI(MlagOrchShowDebug, + "show system internal orchagent mlag global", + SHOW_COMMAND, + SYSTEM_DEBUG_COMMAND, + INTERNAL_COMMAND, + "Orchagent related commands", + "Mlag orch related commands", + "Mlag global info") +{ + gMlagOrch->showDebugInfo(this); +} + +void MlagOrch::installDebugClis() +{ + DebugShCmd::install(new MlagOrchShowDebug()); +} + +//------------------------------------------------------------------ +//Private API section +//------------------------------------------------------------------ +void MlagOrch::doTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + + if (!gPortsOrch->allPortsReady()) + { + return; + } + string table_name = consumer.getTableName(); + if (table_name == CFG_MCLAG_TABLE_NAME) + { + doMlagDomainTask(consumer); + } + else if (table_name == CFG_MCLAG_INTF_TABLE_NAME) + { + doMlagInterfaceTask(consumer); + } + else + { + SWSS_LOG_ERROR("MLAG receives invalid table %s", table_name.c_str()); + } +} + +//Only interest in peer-link info from MLAG domain table +void MlagOrch::doMlagDomainTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + + string peer_link; + + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + KeyOpFieldsValuesTuple t = it->second; + string op = kfvOp(t); + + if (op == SET_COMMAND) + { + for (auto i : kfvFieldsValues(t)) + { + if (fvField(i) == "peer_link") + { + peer_link = fvValue(i); + break; + } + } + if (!peer_link.empty()) + { + if (addIslInterface(peer_link)) + it = consumer.m_toSync.erase(it); + else + it++; + } + else + it = consumer.m_toSync.erase(it); + } + else if (op == DEL_COMMAND) + { + if (delIslInterface()) + it = consumer.m_toSync.erase(it); + else + it++; + } + else + { + SWSS_LOG_ERROR("MLAG receives unknown operation type %s", op.c_str()); + it = consumer.m_toSync.erase(it); + } + } +} + +//MLAG interface table key format: MCLAG_INTF_TABLE|mclag|ifname +void MlagOrch::doMlagInterfaceTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + + size_t delimiter_pos; + string mlag_if_name; + + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + KeyOpFieldsValuesTuple t = it->second; + string op = kfvOp(t); + string key = kfvKey(t); + + delimiter_pos = key.find_first_of("|"); + mlag_if_name = key.substr(delimiter_pos+1); + + if (op == SET_COMMAND) + { + if (addMlagInterface(mlag_if_name)) + it = consumer.m_toSync.erase(it); + else + it++; + } + else if (op == DEL_COMMAND) + { + if (delMlagInterface(mlag_if_name)) + it = consumer.m_toSync.erase(it); + else + it++; + } + else + { + SWSS_LOG_ERROR("MLAG receives unknown operation type %s", op.c_str()); + it = consumer.m_toSync.erase(it); + } + } +} + +bool MlagOrch::addIslInterface(string isl_name) +{ + Port isl_port; + MlagIslUpdate update; + + //No change + if ((m_isl_name == isl_name) || (isl_name.empty())) + return true; + + m_isl_name = isl_name; + + //Create isolation group if ICCPd has not created it yet + addIslIsolationGroup(); + + //Update observers + update.isl_name = isl_name; + update.is_add = true; + notify(SUBJECT_TYPE_MLAG_ISL_CHANGE, static_cast(&update)); + return true; +} + +bool MlagOrch::delIslInterface() +{ + MlagIslUpdate update; + + if (m_isl_name.empty()) + return true; + + update.isl_name = m_isl_name; + update.is_add = false; + + m_isl_name.clear(); + //Delete isolation group if ICCP has not taken control yet + deleteIslIsolationGroup(); + + //Notify observer + notify(SUBJECT_TYPE_MLAG_ISL_CHANGE, static_cast(&update)); + + return true; +} + +//Mlag interface can be added even before interface is configured +bool MlagOrch::addMlagInterface(string if_name) +{ + MlagIfUpdate update; + + //Duplicate add + if (m_mlagIntfs.find(if_name) != m_mlagIntfs.end()) + { + SWSS_LOG_ERROR("MLAG adds duplicate MLAG interface %s", if_name.c_str()); + } + else + { + + m_mlagIntfs.insert(if_name); + + //If this is the first MLAG interface added, create isolation group + if (m_mlagIntfs.size() == 1) + addIslIsolationGroup(); + else + updateIslIsolationGroup(if_name, true); + + //Notify observer + update.if_name = if_name; + update.is_add = true; + notify(SUBJECT_TYPE_MLAG_INTF_CHANGE, static_cast(&update)); + } + return true; + +} +bool MlagOrch::delMlagInterface(string if_name) +{ + MlagIfUpdate update; + + //Delete an unknown MLAG interface + if (m_mlagIntfs.find(if_name) == m_mlagIntfs.end()) + { + SWSS_LOG_ERROR("MLAG deletes unknown MLAG interface %s", if_name.c_str()); + } + else + { + m_mlagIntfs.erase(if_name); + + //If this is the last MLAG interface added, delete isolation group + if (m_mlagIntfs.size() == 0) + deleteIslIsolationGroup(); + else + updateIslIsolationGroup(if_name, false); + + //Notify observers + update.if_name = if_name; + update.is_add = false; + notify(SUBJECT_TYPE_MLAG_INTF_CHANGE, static_cast(&update)); + } + return true; +} + +bool MlagOrch::isMlagInterface(string if_name) +{ + if (m_mlagIntfs.find(if_name) == m_mlagIntfs.end()) + return false; + else + return true; +} + +bool MlagOrch::isIslInterface(string if_name) +{ + if (m_isl_name == if_name) + return true; + else + return false; +} + +/* Create isolation group based on MLAG configuration before ICCPd + * takes control of the isolation group + */ +bool MlagOrch::addIslIsolationGroup() +{ + isolation_group_status_t status; + string isolate_dst_ports; + + //Need peer link and at least one MLAG interface to create an isolation group + if (m_isl_name.empty() || (m_mlagIntfs.size() == 0)) + { + SWSS_LOG_NOTICE("MLAG skips adding isolation group: isl name(%s), num MLAG interface %lu", + m_isl_name.empty() ? "invalid" : m_isl_name.c_str(), m_mlagIntfs.size()); + return false; + } + //During SwSS warm reboot, isolation group can be created first by ICCP + //due to IsoGrpOrch processing info from APP_DB first + auto isolation_grp = gIsoGrpOrch->getIsolationGroup(MLAG_ISL_ISOLATION_GROUP_NAME); + if (isolation_grp) + { + m_iccp_control_isolation_grp = true; + + //Register with IsoGrpOrch to receive update when ICCP deletes the group + if (!isolation_grp->isObserver(this)) + { + isolation_grp->attach(SUBJECT_TYPE_ISOLATION_GROUP_CHANGE, this); + ++m_num_isolation_grp_attach; + m_attach_isolation_grp = true; + SWSS_LOG_NOTICE("MLAG found ICCP-controlled isolation group. Attach to it"); + } + else + SWSS_LOG_NOTICE("MLAG is already attached to ICCP-controlled isolation group"); + return false; + } + //Create a new isolation group + for (auto mlag_if = m_mlagIntfs.begin(); mlag_if != m_mlagIntfs.end(); ++mlag_if) + { + if (isolate_dst_ports.length()) + { + isolate_dst_ports = isolate_dst_ports + ',' + *mlag_if; + } + else + { + isolate_dst_ports = *mlag_if; + } + } + status = gIsoGrpOrch->addIsolationGroup( + MLAG_ISL_ISOLATION_GROUP_NAME, + ISOLATION_GROUP_TYPE_BRIDGE_PORT, + MLAG_ISL_ISOLATION_GROUP_DESCR, + m_isl_name, isolate_dst_ports); + + if (status != ISO_GRP_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("MLAG failed to create ISL isolation group, status %d", status); + ++m_num_isolation_grp_add_error; + return false; + } + //Register wiht IsoGrpOrch to receive update when ICCP adds the group + isolation_grp = gIsoGrpOrch->getIsolationGroup(MLAG_ISL_ISOLATION_GROUP_NAME); + if (isolation_grp) + { + isolation_grp->attach(SUBJECT_TYPE_ISOLATION_GROUP_CHANGE, this); + ++m_num_isolation_grp_attach; + m_attach_isolation_grp = true; + } + SWSS_LOG_NOTICE("MLAG creates ISL isolation group"); + return true; +} + +bool MlagOrch::deleteIslIsolationGroup() +{ + isolation_group_status_t status; + + //Delete isolation group if either peer link or all MLAG interfaces are removed + if (!m_isl_name.empty() && (m_mlagIntfs.size() > 0)) + { + SWSS_LOG_NOTICE("MLAG skips deleting isolation group: isl name %s, num MLAG interface %lu", + m_isl_name.c_str(), m_mlagIntfs.size()); + return false; + } + //The delete request is triggered when the last MLAG interface is deleted + //or when peer link interface is deleted. If MlagOrch no longer attaches + //to isolation group due to previous deletion, do not need to do anything + if (!m_attach_isolation_grp) + return false; + + auto isolation_grp = gIsoGrpOrch->getIsolationGroup(MLAG_ISL_ISOLATION_GROUP_NAME); + + if (!isolation_grp) + { + SWSS_LOG_ERROR("MLAG fails to find isolation group, iccp_control %d", + m_iccp_control_isolation_grp); + return false; + } + //Reset the ICCP control flag since MlagOrch will detach from the group + //and won't receive any further update + m_iccp_control_isolation_grp = false; + + //Only need to unregister with IsoGrpOrch if ICCP is in control + if (m_iccp_control_isolation_grp) + { + //Mlag configuration is deleted while it is up + if (m_attach_isolation_grp) + { + isolation_grp->detach(SUBJECT_TYPE_ISOLATION_GROUP_CHANGE, this); + ++m_num_isolation_grp_detach; + m_attach_isolation_grp = false; + SWSS_LOG_NOTICE("MLAG detaches from ICCP-controlled isolation group"); + } + else + SWSS_LOG_ERROR("MLAG is not attached to ICCP-controlled isolation group"); + } + else + { + //Unregister with IsoGrpOrch before deleting since the group is deleted + //only after all observers are removed + if (m_attach_isolation_grp) + { + isolation_grp->detach(SUBJECT_TYPE_ISOLATION_GROUP_CHANGE, this); + ++m_num_isolation_grp_detach; + m_attach_isolation_grp = false; + } + status = gIsoGrpOrch->delIsolationGroup(MLAG_ISL_ISOLATION_GROUP_NAME); + if (status == ISO_GRP_STATUS_SUCCESS) + { + SWSS_LOG_NOTICE("MLAG deletes ISL isolation group"); + return true; + } + else + { + SWSS_LOG_ERROR("MLAG can't delete ISL isolation group, status %d", status); + ++m_num_isolation_grp_del_error; + return false; + } + } + return true; +} + +bool MlagOrch::updateIslIsolationGroup(string if_name, bool is_add) +{ + string isolate_dst_ports; + isolation_group_status_t status; + + //Do not trigger any update if ICCP already tooks control + if (m_iccp_control_isolation_grp) + return false; + + auto isolation_grp = gIsoGrpOrch->getIsolationGroup(MLAG_ISL_ISOLATION_GROUP_NAME); + if (isolation_grp) + { + //Isolation group can handle forward reference. Updated it with + //the latest set of MLAG interfaces + for (auto mlag_if = m_mlagIntfs.begin(); mlag_if != m_mlagIntfs.end(); ++mlag_if) + { + if (isolate_dst_ports.length()) + isolate_dst_ports = isolate_dst_ports + ',' + *mlag_if; + else + isolate_dst_ports = *mlag_if; + } + status = isolation_grp->setMembers(isolate_dst_ports); + if (status != ISO_GRP_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("MLAG can't %s member %s for isolation group, status %d", + is_add ? "add" : "delete", if_name.c_str(), status); + ++m_num_isolation_grp_update_error; + return false; + } + else + { + SWSS_LOG_NOTICE("MLAG %s member %s for isolation group", + is_add ? "adds" : "deletes", if_name.c_str()); + return true; + } + } + else + { + SWSS_LOG_ERROR("MLAG can't find MlagOrch-controlled isolation group to update"); + } + return true; +} + +bool MlagOrch::addAllMlagInterfacesToIsolationGroup() +{ + isolation_group_status_t status; + string isolate_dst_ports; + + //Need peer link and at least one MLAG interface to create an isolation group + if (m_isl_name.empty() || (m_mlagIntfs.size() == 0)) + { + SWSS_LOG_NOTICE("MLAG skips adding mlag-if to isolation group: isl name(%s), mlag-if count %lu", + m_isl_name.empty() ? "invalid" : m_isl_name.c_str(), m_mlagIntfs.size()); + return false; + } + auto isolation_grp = gIsoGrpOrch->getIsolationGroup(MLAG_ISL_ISOLATION_GROUP_NAME); + if (!isolation_grp) + { + SWSS_LOG_ERROR("MLAG can't find ISL isolation group"); + return false; + } + for (auto mlag_if = m_mlagIntfs.begin(); mlag_if != m_mlagIntfs.end(); ++mlag_if) + { + if (isolate_dst_ports.length()) + { + isolate_dst_ports = isolate_dst_ports + ',' + *mlag_if; + } + else + { + isolate_dst_ports = *mlag_if; + } + } + //Update isolation group + status = gIsoGrpOrch->addIsolationGroup( + MLAG_ISL_ISOLATION_GROUP_NAME, + ISOLATION_GROUP_TYPE_BRIDGE_PORT, + MLAG_ISL_ISOLATION_GROUP_DESCR, + m_isl_name, isolate_dst_ports); + + if (status != ISO_GRP_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("MLAG fails to update ISL isolation group, status %d", status); + ++m_num_isolation_grp_update_error; + return false; + } + else + { + SWSS_LOG_NOTICE("MLAG adds all MLAG interfaces to ISL isolation group"); + return true; + } +} + +void MlagOrch::showDebugInfo(DebugShCmd *cmd) +{ + Port mlag_port, isl_port; + + //Show Mlag interface info + DEBUGSH_OUT(cmd, "Isolation group name: %s(%s)\n", + MLAG_ISL_ISOLATION_GROUP_NAME, + gIsoGrpOrch->getIsolationGroup(MLAG_ISL_ISOLATION_GROUP_NAME) ? + "created" : "not created"); + DEBUGSH_OUT(cmd, "ICCP controls isolation group: %s\n", + m_iccp_control_isolation_grp ? "yes" : "no"); + DEBUGSH_OUT(cmd, "MlagOrch attaches to isolation group: %s\n", + m_attach_isolation_grp ? "yes" : "no"); + DEBUGSH_OUT(cmd, "Isolation group attach count: %u\n", m_num_isolation_grp_attach); + DEBUGSH_OUT(cmd, "Isolation group detach count: %u\n", m_num_isolation_grp_detach); + DEBUGSH_OUT(cmd, "Isolation group add error count: %u\n", m_num_isolation_grp_add_error); + DEBUGSH_OUT(cmd, "Isolation group delete error count: %u\n", m_num_isolation_grp_del_error); + DEBUGSH_OUT(cmd, "Isolation group update error count: %u\n\n", m_num_isolation_grp_update_error); + + DEBUGSH_OUT(cmd, "MLAG ISL interface: %s\n", m_isl_name.c_str()); + DEBUGSH_OUT(cmd, "MLAG interfaces: %lu\n", m_mlagIntfs.size()); + for (auto &name: m_mlagIntfs) + { + //MLAG interface is configured before the interface is configured + if (!gPortsOrch->getPort(name, mlag_port)) + { + DEBUGSH_OUT(cmd, " %s\n", name.c_str()); + } + else + { + DEBUGSH_OUT(cmd, + " %s: oper %s, traffic_disable %d, hw_pending_lag_mbrs %lu\n", + mlag_port.m_alias.c_str(), + oper_status_strings.at(mlag_port.m_oper_status).c_str(), + mlag_port.m_lag_traffic_disable, + mlag_port.m_hw_pending_lag_members.size()); + } + } +} diff --git a/orchagent/mlagorch.h b/orchagent/mlagorch.h new file mode 100644 index 0000000000..736af86f56 --- /dev/null +++ b/orchagent/mlagorch.h @@ -0,0 +1,81 @@ +/* + * Copyright 2019 Broadcom. The term "Broadcom" refers to Broadcom Inc. + * and/or its subsidiaries. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SWSS_MLAGORCH_H +#define SWSS_MLAGORCH_H + +#include +#include +#include "orch.h" +#include "port.h" +#include "isolationgrouporch.h" +#include "debugshcmd.h" + +struct MlagIfUpdate +{ + string if_name; + bool is_add; +}; + +struct MlagIslUpdate +{ + string isl_name; + bool is_add; +}; + +class MlagOrch: public Orch, public Observer, public Subject +{ +public: + MlagOrch(DBConnector *db, vector &tableNames); + ~MlagOrch(); + void update(SubjectType type, void *cntx); + void installDebugClis(); + void showDebugInfo(DebugShCmd *cmd); + bool isMlagInterface(string if_name); + bool isIslInterface(string if_name); + + const std::set& + getMlagIntfs() const + { + return m_mlagIntfs; + } + +private: + std::string m_isl_name; + std::set m_mlagIntfs; + bool m_iccp_control_isolation_grp = false; + bool m_attach_isolation_grp = false; + uint32_t m_num_isolation_grp_attach = 0; + uint32_t m_num_isolation_grp_detach = 0; + uint32_t m_num_isolation_grp_add_error = 0; + uint32_t m_num_isolation_grp_del_error = 0; + uint32_t m_num_isolation_grp_update_error = 0; + + void doTask(Consumer &consumer); + void doMlagDomainTask(Consumer &consumer); + void doMlagInterfaceTask(Consumer &consumer); + bool addIslInterface(string isl_name); + bool delIslInterface(); + bool addMlagInterface(string if_name); + bool delMlagInterface(string if_name); + bool addIslIsolationGroup(); + bool deleteIslIsolationGroup(); + bool updateIslIsolationGroup(string if_name, bool is_add); + bool addAllMlagInterfacesToIsolationGroup(); +}; + +#endif /* SWSS_MLAGORCH_H */ diff --git a/orchagent/observer.h b/orchagent/observer.h index 2630ee992f..fee2962c9a 100644 --- a/orchagent/observer.h +++ b/orchagent/observer.h @@ -16,6 +16,8 @@ enum SubjectType SUBJECT_TYPE_MIRROR_SESSION_CHANGE, SUBJECT_TYPE_INT_SESSION_CHANGE, SUBJECT_TYPE_PORT_CHANGE, + SUBJECT_TYPE_MLAG_INTF_CHANGE, + SUBJECT_TYPE_BRIDGE_PORT_CHANGE }; class Observer diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 26ff1f0301..bcf52592f2 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -36,6 +36,8 @@ BufferOrch *gBufferOrch; SwitchOrch *gSwitchOrch; Directory gDirectory; NatOrch *gNatOrch; +MlagOrch *gMlagOrch; +IsoGrpOrch *gIsoGrpOrch; bool gIsNatSupported = false; @@ -270,6 +272,19 @@ bool OrchDaemon::init() TableConnector stateDbSwitchTable(m_stateDb, "SWITCH_CAPABILITY"); gAclOrch = new AclOrch(acl_table_connectors, stateDbSwitchTable, gPortsOrch, mirror_orch, gNeighOrch, gRouteOrch, dtel_orch); + vector mlag_tables = { + { CFG_MCLAG_TABLE_NAME }, + { CFG_MCLAG_INTF_TABLE_NAME } + }; + gMlagOrch = new MlagOrch(m_configDb, mlag_tables); + + TableConnector appDbIsoGrpTbl(m_applDb, APP_ISOLATION_GROUP_TABLE_NAME); + vector iso_grp_tbl_ctrs = { + appDbIsoGrpTbl + }; + + gIsoGrpOrch = new IsoGrpOrch(iso_grp_tbl_ctrs); + m_orchList.push_back(gFdbOrch); m_orchList.push_back(mirror_orch); m_orchList.push_back(gAclOrch); @@ -282,6 +297,8 @@ bool OrchDaemon::init() m_orchList.push_back(vnet_orch); m_orchList.push_back(vnet_rt_orch); m_orchList.push_back(gNatOrch); + m_orchList.push_back(gMlagOrch); + m_orchList.push_back(gIsoGrpOrch); m_select = new Select(); diff --git a/orchagent/orchdaemon.h b/orchagent/orchdaemon.h index 3094692df6..e1ee3ad03c 100644 --- a/orchagent/orchdaemon.h +++ b/orchagent/orchdaemon.h @@ -31,6 +31,7 @@ #include "debugcounterorch.h" #include "directory.h" #include "natorch.h" +#include "mlagorch.h" using namespace swss; diff --git a/orchagent/saihelper.cpp b/orchagent/saihelper.cpp index ec990d605e..707a022d38 100644 --- a/orchagent/saihelper.cpp +++ b/orchagent/saihelper.cpp @@ -44,6 +44,7 @@ sai_bmtor_api_t* sai_bmtor_api; sai_samplepacket_api_t* sai_samplepacket_api; sai_debug_counter_api_t* sai_debug_counter_api; sai_nat_api_t* sai_nat_api; +sai_isolation_group_api_t* sai_isolation_group_api; extern sai_object_id_t gSwitchId; extern bool gSairedisRecord; @@ -136,6 +137,7 @@ void initSaiApi() sai_api_query(SAI_API_SAMPLEPACKET, (void **)&sai_samplepacket_api); sai_api_query(SAI_API_DEBUG_COUNTER, (void **)&sai_debug_counter_api); sai_api_query(SAI_API_NAT, (void **)&sai_nat_api); + sai_api_query(SAI_API_ISOLATION_GROUP, (void **)&sai_isolation_group_api); sai_log_set(SAI_API_SWITCH, SAI_LOG_LEVEL_NOTICE); sai_log_set(SAI_API_BRIDGE, SAI_LOG_LEVEL_NOTICE); diff --git a/tests/test_mclag.py b/tests/test_mclag.py new file mode 100644 index 0000000000..7addbd9b11 --- /dev/null +++ b/tests/test_mclag.py @@ -0,0 +1,111 @@ +# Common file to test all MCLAG related changes +from swsscommon import swsscommon +import time +import re +import json +import pytest +import platform +from distutils.version import StrictVersion + +# Create port-channel +def create_portchannel(table, po_name): + fvs = swsscommon.FieldValuePairs([("admin", "up"), ("mtu", "1500")]) + table.set(po_name, fvs) + time.sleep(1) + +# Delete port-channel +def delete_portchannel(table, po_name): + table._del(po_name) + time.sleep(1) + +# Create port-channel member +def create_portchannel_member(table, po_name, po_member_name): + fvs = swsscommon.FieldValuePairs([("status", "enabled")]) + table.set(po_name + ":" + po_member_name, fvs) + time.sleep(1) + +# Delete port-channel member +def delete_portchannel_member(table, po_name, po_member_name): + table._del(po_name + ":" + po_member_name) + time.sleep(1) + + +# Test newly introduce traffic_disable attribute in APP_DB LAG table +class TestPortChannelTrafficDisable(object): + + APP_LAG_TABLE = "LAG_TABLE" + APP_LAG_MEMBER_TABLE = "LAG_MEMBER_TABLE" + ASIC_LAG_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_LAG" + ASIC_LAG_MEMBER_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER" + + PORTCHANNEL_NAME = "PortChannel100" + PORTCHANNEL_MEMBER1 = "Ethernet0" + PORTCHANNEL_MEMBER2 = "Ethernet4" + + # Set LAG traffic_disable attribute + def set_portchannel_trafficdisable(self, table, po_name, bool_str): + fvs = swsscommon.FieldValuePairs([("traffic_disable", bool_str)]) + table.set(po_name, fvs) + time.sleep(1) + + def check_portchannel_member_in_asicdb(self, dvs, po_member_name): + asic_lag_table = swsscommon.Table(self.asic_db, self.ASIC_LAG_TABLE) + lag_entries = asic_lag_table.getKeys() + assert len(lag_entries) == 1, "No LAG entry in ASIC_DB" + + asic_lag_mbr_table = swsscommon.Table(self.asic_db, self.ASIC_LAG_MEMBER_TABLE) + lag_mem_entries = asic_lag_mbr_table.getKeys() + if len(lag_mem_entries) == 0: + return False + for i in range(len(lag_mem_entries)): + (status, fvs) = asic_lag_mbr_table.get(lag_mem_entries[i]) + for fv in fvs: + if fv[0] == "SAI_LAG_MEMBER_ATTR_LAG_ID": + assert fv[1] == lag_entries[0] + elif fv[0] == "SAI_LAG_MEMBER_ATTR_PORT_ID": + if dvs.asicdb.portoidmap[fv[1]] == po_member_name: + return True + return False + + # Test traffic_disable attribute setting on LAG table entry in APP_DB + # 1. Create LAG with 1 member. Verify LAG and LAG member are added to ASIC_DB + # 2. Set traffic disable to true for LAG. Verify LAG member is removed from ASIC_DB + # 3. Add a second LAG member. Verify it is not added to ASIC_DB + # 4. Set traffic disable to false for LAG. Verify both LAG members are added to ASIC_DB + # 5. Delete LAG and its two members + def test_portchannel_traffic_disable(self, dvs, testlog): + self.app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + self.asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + lag_table = swsscommon.ProducerStateTable(self.app_db, self.APP_LAG_TABLE) + lag_member_table = swsscommon.ProducerStateTable(self.app_db, self.APP_LAG_MEMBER_TABLE) + + # Test1: verify default traffic_disable is not set + create_portchannel(lag_table, self.PORTCHANNEL_NAME) + create_portchannel_member(lag_member_table, self.PORTCHANNEL_NAME, self.PORTCHANNEL_MEMBER1) + status = self.check_portchannel_member_in_asicdb(dvs, self.PORTCHANNEL_MEMBER1) + assert status == True, "LAG member is not added to ASIC_DB" + + # Test2: verify LAG member is removed from ASIC_DB when traffic_disable + # attribute is set to true + self.set_portchannel_trafficdisable(lag_table, self.PORTCHANNEL_NAME, "true") + status = self.check_portchannel_member_in_asicdb(dvs, self.PORTCHANNEL_MEMBER1) + assert status == False, "LAG member is not removed from ASIC_DB" + + # Test3: verify new LAG member is not added to ASIC_DB when traffic_disable + # attribute is set to true + create_portchannel_member(lag_member_table, self.PORTCHANNEL_NAME, self.PORTCHANNEL_MEMBER2) + status = self.check_portchannel_member_in_asicdb(dvs, self.PORTCHANNEL_MEMBER2) + assert status == False, "LAG member is incorrectly added to ASIC_DB" + + # Test4: verify both LAG members are added to ASIC_DB whent traffic_disable + # attribute is set to false + self.set_portchannel_trafficdisable(lag_table, self.PORTCHANNEL_NAME, "false") + status = self.check_portchannel_member_in_asicdb(dvs, self.PORTCHANNEL_MEMBER1) + assert status == True, "LAG member Ethernet0 is not added to ASIC_DB" + status = self.check_portchannel_member_in_asicdb(dvs, self.PORTCHANNEL_MEMBER2) + assert status == True, "LAG member Ethernet4 is not added to ASIC_DB" + + # Cleanup + delete_portchannel_member(lag_member_table, self.PORTCHANNEL_NAME, self.PORTCHANNEL_MEMBER1) + delete_portchannel_member(lag_member_table, self.PORTCHANNEL_NAME, self.PORTCHANNEL_MEMBER2) + delete_portchannel(lag_table, self.PORTCHANNEL_NAME) diff --git a/tests/test_mclag_fdb.py b/tests/test_mclag_fdb.py new file mode 100644 index 0000000000..7de7ab632f --- /dev/null +++ b/tests/test_mclag_fdb.py @@ -0,0 +1,511 @@ +from swsscommon import swsscommon +import os +import sys +import time +import json +import pytest +from distutils.version import StrictVersion + +def create_entry(tbl, key, pairs): + fvs = swsscommon.FieldValuePairs(pairs) + tbl.set(key, fvs) + + time.sleep(1) + +def create_entry_tbl(db, table, key, pairs): + tbl = swsscommon.Table(db, table) + create_entry(tbl, key, pairs) + +def create_entry_pst(db, table, key, pairs): + tbl = swsscommon.ProducerStateTable(db, table) + create_entry(tbl, key, pairs) + +def delete_entry_pst(db, table, key): + tbl = swsscommon.ProducerStateTable(db, table) + tbl._del(key) + +def get_port_oid(dvs, port_name): + counters_db = swsscommon.DBConnector(swsscommon.COUNTERS_DB, dvs.redis_sock, 0) + port_map_tbl = swsscommon.Table(counters_db, 'COUNTERS_PORT_NAME_MAP') + for k in port_map_tbl.get('')[1]: + if k[0] == port_name: + return k[1] + return None + +def get_bridge_port_oid(dvs, port_oid): + tbl = swsscommon.Table(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT") + for key in tbl.getKeys(): + status, data = tbl.get(key) + assert status + values = dict(data) + if port_oid == values["SAI_BRIDGE_PORT_ATTR_PORT_ID"]: + return key + return None + +def create_port_channel(dvs, alias): + tbl = swsscommon.Table(dvs.cdb, "PORTCHANNEL") + fvs = swsscommon.FieldValuePairs([("admin_status", "up"), + ("mtu", "9100")]) + tbl.set(alias, fvs) + time.sleep(1) + +def remove_port_channel(dvs, alias): + tbl = swsscommon.Table(dvs.cdb, "PORTCHANNEL") + tbl._del(alias) + time.sleep(1) + +def add_port_channel_members(dvs, lag, members): + tbl = swsscommon.Table(dvs.cdb, "PORTCHANNEL_MEMBER") + fvs = swsscommon.FieldValuePairs([("NULL", "NULL")]) + for member in members: + tbl.set(lag + "|" + member, fvs) + time.sleep(1) + +def remove_port_channel_members(dvs, lag, members): + tbl = swsscommon.Table(dvs.cdb, "PORTCHANNEL_MEMBER") + for member in members: + tbl._del(lag + "|" + member) + time.sleep(1) + +def how_many_entries_exist(db, table): + tbl = swsscommon.Table(db, table) + return len(tbl.getKeys()) + +# Test-1 Verify basic config add + +@pytest.mark.dev_sanity +def test_mclagFdb_basic_config_add(dvs, testlog): + dvs.setup_db() + dvs.runcmd("sonic-clear fdb all") + time.sleep(2) + + vlan_before = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN") + bp_before = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT") + vm_before = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN_MEMBER") + + # create PortChannel0005 + create_port_channel(dvs, "PortChannel0005") + + # add members to PortChannel0005 + add_port_channel_members(dvs, "PortChannel0005", ["Ethernet4"]) + + # create PortChannel0006 + create_port_channel(dvs, "PortChannel0006") + + # add members to PortChannel0006 + add_port_channel_members(dvs, "PortChannel0006", ["Ethernet8"]) + + # create PortChannel0008 + create_port_channel(dvs, "PortChannel0008") + + # add members to PortChannel0008 + add_port_channel_members(dvs, "PortChannel0008", ["Ethernet12"]) + + # create vlan + dvs.create_vlan("200") + + # Add vlan members + dvs.create_vlan_member("200", "PortChannel0005") + dvs.create_vlan_member("200", "PortChannel0006") + dvs.create_vlan_member("200", "PortChannel0008") + + # check that the vlan information was propagated + vlan_after = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN") + bp_after = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT") + vm_after = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN_MEMBER") + + assert vlan_after - vlan_before == 1, "The Vlan200 wasn't created" + assert bp_after - bp_before == 3, "The bridge port wasn't created" + assert vm_after - vm_before == 3, "The vlan member wasn't added" + +# Test-2 Remote Dynamic MAC Add + +@pytest.mark.dev_sanity +def test_mclagFdb_remote_dynamic_mac_add(dvs, testlog): + dvs.setup_db() + # create FDB entry in APP_DB MCLAG_FDB_TABLE + create_entry_pst( + dvs.pdb, + "MCLAG_FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + [ + ("port", "PortChannel0005"), + ("type", "dynamic"), + ] + ) + + # check that the FDB entry was inserted into ASIC DB + assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 1, "The MCLAG fdb entry not inserted to ASIC" + + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC_MACMOVE"), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0005")))] + ) + + assert ok, str(extra) + +# Test-3 Remote Dynamic MAC Delete + +@pytest.mark.dev_sanity +def test_mclagFdb_remote_dynamic_mac_delete(dvs, testlog): + dvs.setup_db() + + delete_entry_pst( + dvs.pdb, + "MCLAG_FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + ) + + time.sleep(2) + # check that the FDB entry was deleted from ASIC DB + assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 0, "The MCLAG fdb entry not deleted" + + +# Test-4 Remote Static MAC Add + +@pytest.mark.dev_sanity +def test_mclagFdb_remote_static_mac_add(dvs, testlog): + dvs.setup_db() + + create_entry_pst( + dvs.pdb, + "MCLAG_FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + [ + ("port", "PortChannel0005"), + ("type", "static"), + ] + ) + + # check that the FDB entry was inserted into ASIC DB + assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 1, "The MCLAG static fdb entry not inserted to ASIC" + + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0005")))] + ) + + assert ok, str(extra) + +# Test-5 Remote Static MAC Del + +@pytest.mark.dev_sanity +def test_mclagFdb_remote_static_mac_del(dvs, testlog): + dvs.setup_db() + + delete_entry_pst( + dvs.pdb, + "MCLAG_FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + ) + + time.sleep(2) + # check that the FDB entry was deleted from ASIC DB + assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 0, "The MCLAG static fdb entry not deleted" + + +# Test-6 Verify Remote to Local Move. + +@pytest.mark.dev_sanity +def test_mclagFdb_remote_to_local_mac_move(dvs, testlog): + dvs.setup_db() + + #Add remote MAC to MCLAG_FDB_TABLE on PortChannel0005 + create_entry_pst( + dvs.pdb, + "MCLAG_FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + [ + ("port", "PortChannel0005"), + ("type", "dynamic"), + ] + ) + + # check that the FDB entry inserted into ASIC DB + assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 1, "The MCLAG fdb entry not inserted to ASIC" + + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC_MACMOVE"), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0005")))] + ) + + assert ok, str(extra) + + #Move MAC to PortChannel0008 on Local FDB_TABLE + create_entry_pst( + dvs.pdb, + "FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + [ + ("port", "PortChannel0008"), + ("type", "dynamic"), + ] + ) + + # check that the FDB entry was inserted into ASIC DB + assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 1, "The fdb entry not inserted to ASIC" + + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC"), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0008")))] + ) + + assert ok, str(extra) + +# Test-7 Verify Remote MAC del should not del local MAC after move + +@pytest.mark.dev_sanity +def test_mclagFdb_local_mac_move_del(dvs, testlog): + dvs.setup_db() + + #Cleanup the FDB from MCLAG_FDB_TABLE + delete_entry_pst( + dvs.pdb, + "MCLAG_FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + ) + + # Verify that the local FDB entry still inserted into ASIC DB + assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 1, "The fdb entry not inserted to ASIC" + + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC"), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0008")))] + ) + + assert ok, str(extra) + + + #delete the local FDB and Verify + delete_entry_pst( + dvs.pdb, + "FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + ) + + time.sleep(2) + # check that the FDB entry was deleted from ASIC DB + assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 0, "The fdb entry was not deleted" + + +# Test-8 Verify Local to Remote Move. + +@pytest.mark.dev_sanity +def test_mclagFdb_local_to_remote_move(dvs, testlog): + dvs.setup_db() + + #Add local MAC to FDB_TABLE on PortChannel0008 + create_entry_pst( + dvs.pdb, + "FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + [ + ("port", "PortChannel0008"), + ("type", "dynamic"), + ] + ) + + # check that the FDB entry was inserted into ASIC DB + assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 1, "The MCLAG fdb entry not inserted to ASIC" + + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC"), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0008")))] + ) + + assert ok, str(extra) + + #Move MAC to PortChannel0005 on Remote FDB_TABLE + create_entry_pst( + dvs.pdb, + "MCLAG_FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + [ + ("port", "PortChannel0005"), + ("type", "dynamic"), + ] + ) + + # check that the FDB entry was inserted into ASIC DB + assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 1, "The MCLAG fdb entry not inserted to ASIC" + + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC_MACMOVE"), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0005")))] + ) + + assert ok, str(extra) + +# Test-9 Verify local MAC del should not del remote MAC after move + +@pytest.mark.dev_sanity +def test_mclagFdb_remote_move_del(dvs, testlog): + dvs.setup_db() + + #Cleanup the local FDB + delete_entry_pst( + dvs.pdb, + "FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + ) + + # check that the remote FDB entry still inserted into ASIC DB + assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 1, "The MCLAG fdb entry not inserted to ASIC" + + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC_MACMOVE"), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0005")))] + ) + + assert ok, str(extra) + + #delete the remote FDB and Verify + delete_entry_pst( + dvs.pdb, + "MCLAG_FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + ) + + time.sleep(2) + # check that the FDB entry was deleted from ASIC DB + assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 0, "The fdb entry not deleted" + + + +# Test-10 Verify remote MAC move in remote node is updated locally. + +@pytest.mark.dev_sanity +def test_mclagFdb_remote_move_peer_node(dvs, testlog): + dvs.setup_db() + + #Add remote MAC to MCLAG_FDB_TABLE on PortChannel0005 + create_entry_pst( + dvs.pdb, + "MCLAG_FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + [ + ("port", "PortChannel0005"), + ("type", "dynamic"), + ] + ) + + # check that the FDB entry inserted into ASIC DB + assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 1, "The MCLAG fdb entry not inserted to ASIC" + + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC_MACMOVE"), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0005")))] + ) + + assert ok, str(extra) + + # Move remote MAC in MCLAG_FDB_TABLE to PortChannel0006 + create_entry_pst( + dvs.pdb, + "MCLAG_FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + [ + ("port", "PortChannel0006"), + ("type", "dynamic"), + ] + ) + + # check that the FDB entry inserted into ASIC DB + assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 1, "The MCLAG fdb entry not inserted to ASIC" + + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC_MACMOVE"), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0006")))] + ) + + assert ok, str(extra) + + #delete the remote FDB and Verify + delete_entry_pst( + dvs.pdb, + "MCLAG_FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + ) + + time.sleep(2) + # check that the FDB entry was deleted from ASIC DB + assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 0, "The fdb entry not deleted" + + +# Test-11 Verify remote dynamic MAC move rejection in presecense of local static MAC. + +@pytest.mark.dev_sanity +def test_mclagFdb_static_mac_dynamic_move_reject(dvs, testlog): + dvs.setup_db() + + #Add local MAC to FDB_TABLE on PortChannel0008 + create_entry_pst( + dvs.pdb, + "FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + [ + ("port", "PortChannel0008"), + ("type", "static"), + ] + ) + + # check that the static FDB entry was inserted into ASIC DB + assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 1, "The MCLAG fdb entry not inserted to ASIC" + + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0008")))] + ) + + assert ok, str(extra) + + #Add remote MAC to MCLAG_FDB_TABLE on PortChannel0005 + create_entry_pst( + dvs.pdb, + "MCLAG_FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + [ + ("port", "PortChannel0005"), + ("type", "dynamic"), + ] + ) + + # check that still static FDB entry is inserted into ASIC DB + assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 1, "The MCLAG fdb entry not inserted to ASIC" + + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0008")))] + ) + + assert ok, str(extra) + + delete_entry_pst( + dvs.pdb, + "FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + ) + + time.sleep(2) + # check that the FDB entry was deleted from ASIC DB + assert how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY") == 0, "The MCLAG static fdb entry not deleted" + + delete_entry_pst( + dvs.pdb, + "MCLAG_FDB_TABLE", "Vlan200:3C:85:99:5E:00:01", + ) + +# Test-12 Verify cleanup of the basic config. + +@pytest.mark.dev_sanity +def test_mclagFdb_basic_config_del(dvs, testlog): + dvs.setup_db() + + dvs.remove_vlan_member("200", "PortChannel0005") + dvs.remove_vlan_member("200", "PortChannel0006") + dvs.remove_vlan_member("200", "PortChannel0008") + dvs.remove_vlan("200") + remove_port_channel_members(dvs, "PortChannel0005", + ["Ethernet4"]) + remove_port_channel_members(dvs, "PortChannel0006", + ["Ethernet8"]) + remove_port_channel_members(dvs, "PortChannel0008", + ["Ethernet12"]) + remove_port_channel(dvs, "PortChannel0005") + remove_port_channel(dvs, "PortChannel0006") + remove_port_channel(dvs, "PortChannel0008") + From 16e2cf97b3abf9fd98bccc7a6871f84b7ae225da Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Wed, 18 Nov 2020 00:49:37 -0800 Subject: [PATCH 02/54] Updating code to fix compilation issues. --- orchagent/fdborch.cpp | 98 +++++-------- orchagent/fdborch.h | 4 +- orchagent/isolationgrouporch.cpp | 201 -------------------------- orchagent/isolationgrouporch.h | 11 -- orchagent/mlagorch.cpp | 56 -------- orchagent/mlagorch.h | 3 - orchagent/observer.h | 4 +- orchagent/orchdaemon.cpp | 12 +- orchagent/port.h | 4 + orchagent/portsorch.cpp | 2 +- tests/test_mclag_cfg.py | 238 +++++++++++++++++++++++++++++++ 11 files changed, 297 insertions(+), 336 deletions(-) create mode 100644 tests/test_mclag_cfg.py diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index 8753534023..40b7862a19 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -19,17 +19,18 @@ extern sai_fdb_api_t *sai_fdb_api; extern sai_object_id_t gSwitchId; extern PortsOrch* gPortsOrch; -extern NeighOrch* gNeighOrch; extern CrmOrch * gCrmOrch; extern MlagOrch* gMlagOrch; extern Directory gDirectory; const int fdborch_pri = 20; -FdbOrch::FdbOrch(DBConnector* applDbConnector, vector appFdbTables, TableConnector stateDbFdbConnector, PortsOrch *port) : +FdbOrch::FdbOrch(DBConnector* applDbConnector, vector appFdbTables, + TableConnector stateDbFdbConnector, TableConnector stateDbMclagFdbConnector, PortsOrch *port) : Orch(applDbConnector, appFdbTables), m_portsOrch(port), - m_fdbStateTable(stateDbFdbConnector.first, stateDbFdbConnector.second) + m_fdbStateTable(stateDbFdbConnector.first, stateDbFdbConnector.second), + m_mclagFdbStateTable(stateDbMclagFdbConnector.first, stateDbMclagFdbConnector.second) { for(auto it: appFdbTables) @@ -66,21 +67,6 @@ bool FdbOrch::bake() return true; } -//used for ICCPd FDB entries only for now. -void FdbOrch::neighborOrchFdbUnregister(const MacAddress &mac, unsigned int vlan_id) -{ - fdb_mac_cache fdbmac; - memset(&fdbmac, 0, sizeof(fdb_mac_cache)); - fdbmac.mac = mac; - fdbmac.fdid = vlan_id; - - if (gNeighOrch->delFdbNeighCache(fdbmac, FDB_SYNCD_MAC)) - SWSS_LOG_NOTICE(" MAC Un-Register with NeighOrch Success: " - "Mac: %s Vlan: %d ", fdbmac.mac.to_string().c_str(), fdbmac.fdid); - else - SWSS_LOG_NOTICE(" MAC Un-Register with NeighOrch Failed: " - "Mac: %s Vlan: %d ", fdbmac.mac.to_string().c_str(), fdbmac.fdid); -} bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) { @@ -132,7 +118,6 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) fdbdata.bridge_port_id = update.port.m_bridge_port_id; fdbdata.type = update.type; fdbdata.origin = FDB_ORIGIN_LEARN; - fdbdata.origin_sources = FDB_ORIGIN_LEARN; m_entries[entry] = fdbdata; SWSS_LOG_NOTICE("FdbOrch notification: mac %s was inserted into bv_id 0x%" PRIx64, @@ -142,8 +127,11 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) if (mac_move && (oldFdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED)) { - // un-register with NeighborOrch. - neighborOrchFdbUnregister(entry.mac, vlan.m_vlan_info.vlan_id); + SWSS_LOG_NOTICE("fdbEvent: FdbOrch MCLAG remote to local move delete mac from state MCLAG remote fdb %s table:" + "bv_id 0x%" PRIx64, entry.mac.to_string().c_str(), entry.bv_id); + + m_mclagFdbStateTable.del(key); + } // Write to StateDb @@ -179,8 +167,9 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) if (oldFdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) { - // un-register with NeighborOrch. - neighborOrchFdbUnregister(entry.mac, vlan.m_vlan_info.vlan_id); + SWSS_LOG_NOTICE("fdbEvent: FdbOrch MCLAG remote mac %s deleted, remove from state mclag remote fdb table:" + "bv_id 0x%" PRIx64, entry.mac.to_string().c_str(), entry.bv_id); + m_mclagFdbStateTable.del(key); } gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); @@ -217,7 +206,8 @@ void FdbOrch::update(sai_fdb_event_t type, { case SAI_FDB_EVENT_LEARNED: { - SWSS_LOG_INFO"Received LEARN event for bvid=%lx mac=%s port=%lx", entry->bv_id, update.entry.mac.to_string().c_str(), bridge_port_id); + SWSS_LOG_INFO("Received LEARN event for bvid=%lx mac=%s port=%lx", + entry->bv_id, update.entry.mac.to_string().c_str(), bridge_port_id); if (!m_portsOrch->getPort(entry->bv_id, vlan)) { @@ -367,7 +357,8 @@ void FdbOrch::update(sai_fdb_event_t type, if (vlan.m_members.find(update.port.m_alias) == vlan.m_members.end()) { update.type = "static"; - saved_fdb_entries[update.port.m_alias].push_back({existing_entry->first.mac, vlan.m_vlan_info.vlan_id, "static"}); + //tbd_to_build + //saved_fdb_entries[update.port.m_alias].push_back({existing_entry->first.mac, vlan.m_vlan_info.vlan_id, "static"}); } else { @@ -704,6 +695,7 @@ void FdbOrch::doTask(Consumer& consumer) FdbEntry entry; entry.mac = MacAddress(keys[1]); entry.bv_id = vlan.m_vlan_info.vlan_oid; + string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string(); if (op == SET_COMMAND) { @@ -739,10 +731,9 @@ void FdbOrch::doTask(Consumer& consumer) { if (type == "dynamic_local") { - //Un-Register with NeighborOrch. - neighborOrchFdbUnregister(entry.mac, vlan.m_vlan_info.vlan_id); + m_mclagFdbStateTable.del(key); - SWSS_LOG_NOTICE("do Task Add: Delete ICCP FDB found in cache: " + SWSS_LOG_NOTICE("do Task Add: Delete ICCP FDB from kernel: " "Mac: %s Vlan: %d port:%s type:%s",entry.mac.to_string().c_str(), vlan.m_vlan_info.vlan_id, it->second.port.c_str(), it->second.type.c_str()); } @@ -759,8 +750,9 @@ void FdbOrch::doTask(Consumer& consumer) { if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED) { - //Un-Register with NeighborOrch. - neighborOrchFdbUnregister(entry.mac, vlan.m_vlan_info.vlan_id); + m_mclagFdbStateTable.del(key); + SWSS_LOG_NOTICE("fdbEvent: do Task Delete MCLAG FDB from state mclag remote fdb table: " + "Mac: %s Vlan: %d ",entry.mac.to_string().c_str(), vlan.m_vlan_info.vlan_id ); } it = consumer.m_toSync.erase(it); @@ -782,6 +774,7 @@ extern std::string joinFieldValues(_In_ const std::vector void FdbOrch::doTask(NotificationConsumer& consumer) { SWSS_LOG_ENTER(); + sai_status_t status; if (!gPortsOrch->allPortsReady()) { @@ -945,7 +938,8 @@ void FdbOrch::updateVlanMember(const VlanMemberUpdate& update) if (!update.add) { - flushFdbByPortVlan(port_name, vlan_name, 1); + //tbd_to_build + //flushFdbByPortVlan(port_name, vlan_name, 1); return; } @@ -1043,10 +1037,9 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const { /* old mac was static and provisioned, it can not be changed by Remote Mac */ SWSS_LOG_NOTICE("Already existing static MAC:%s in Vlan:%d. " - "Received same MAC from peer:%s; " + "Received same MAC from peer " "Peer mac ignored", - entry.mac.to_string().c_str(), vlan.m_vlan_info.vlan_id, - remote_ip.c_str()); + entry.mac.to_string().c_str(), vlan.m_vlan_info.vlan_id); return true; } @@ -1141,7 +1134,6 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const fdbData.bridge_port_id = port.m_bridge_port_id; fdbData.type = type; fdbData.origin = origin; - fdbData.origin_sources = origin; // overwrite the type and origin if ((origin == FDB_ORIGIN_MCLAG_ADVERTIZED) && (type == "dynamic_local")) @@ -1183,29 +1175,22 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const //register with NeighborOrch for ICCP learned MAC addresses if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED && (type != "dynamic_local")) { - //Register with NeighborOrch. - fdb_mac_cache fdbmac; - memset(&fdbmac, 0, sizeof(fdb_mac_cache)); - fdbmac.mac = entry.mac; - fdbmac.fdid = vlan.m_vlan_info.vlan_id; - fdbmac.alias = port_name; - fdbmac.type = type; - fdbmac.origin = origin; - - if (gNeighOrch->addFdbNeighCache(fdbmac, FDB_SYNCD_MAC)) - SWSS_LOG_NOTICE("AddFdbEntry: Register ICCP MAC with NeighOrch Success: " - "Mac: %s Vlan: %d port:%s type:%s", entry.mac.to_string().c_str(), - fdbmac.fdid, port_name.c_str(), type.c_str()); - else - SWSS_LOG_NOTICE("AddFdbEntry: Register ICCP MAC with NeighOrch Failed: " - "Mac: %s Vlan: %d port:%s type:%s", entry.mac.to_string().c_str(), - fdbmac.fdid, port_name.c_str(), type.c_str()); + std::vector fvs; + fvs.push_back(FieldValueTuple("port", port_name)); + fvs.push_back(FieldValueTuple("type", type)); + m_mclagFdbStateTable.set(key, fvs); + + SWSS_LOG_NOTICE("fdbEvent: AddFdbEntry: Add MCLAG MAC with state mclag remote fdb table " + "Mac: %s Vlan: %d port:%s type:%s", entry.mac.to_string().c_str(), + vlan.m_vlan_info.vlan_id, port_name.c_str(), type.c_str()); } else if (macUpdate && (oldOrigin == FDB_ORIGIN_MCLAG_ADVERTIZED) && (origin != FDB_ORIGIN_MCLAG_ADVERTIZED)) { - //UnRegister with NeighborOrch as MAC moved from iccp to non-iccp - neighborOrchFdbUnregister(entry.mac, vlan.m_vlan_info.vlan_id); + SWSS_LOG_NOTICE("fdbEvent: AddFdbEntry: del MCLAG MAC from state MCLAG remote fdb table " + "Mac: %s Vlan: %d port:%s type:%s", entry.mac.to_string().c_str(), + vlan.m_vlan_info.vlan_id, port_name.c_str(), type.c_str()); + m_mclagFdbStateTable.del(key); } if(!macUpdate) @@ -1275,8 +1260,6 @@ bool FdbOrch::removeFdbEntry(const FdbEntry& entry, FdbOrigin origin) } else { - // delete origin from learn sources. - fdbData.origin_sources &= ~origin; m_entries[entry] = fdbData; SWSS_LOG_NOTICE("FdbOrch RemoveFDBEntry: mac=%s fdb origin is different; found_origin:%d delete_origin:%d", entry.mac.to_string().c_str(), fdbData.origin, origin); @@ -1290,9 +1273,6 @@ bool FdbOrch::removeFdbEntry(const FdbEntry& entry, FdbOrigin origin) } } - //unset the current origin flag. - fdbData.origin_sources &= ~origin; - string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string(); sai_status_t status = SAI_STATUS_SUCCESS; diff --git a/orchagent/fdborch.h b/orchagent/fdborch.h index 027d4b1404..29980d034c 100644 --- a/orchagent/fdborch.h +++ b/orchagent/fdborch.h @@ -68,7 +68,8 @@ class FdbOrch: public Orch, public Subject, public Observer { public: - FdbOrch(DBConnector* applDbConnector, vector appFdbTables, TableConnector stateDbFdbConnector, PortsOrch *port); + FdbOrch(DBConnector* applDbConnector, vector appFdbTables, + TableConnector stateDbFdbConnector, TableConnector stateDbMclagFdbConnector, PortsOrch *port); ~FdbOrch() { @@ -89,6 +90,7 @@ class FdbOrch: public Orch, public Subject, public Observer fdb_entries_by_port_t saved_fdb_entries; vector m_appTables; Table m_fdbStateTable; + Table m_mclagFdbStateTable; NotificationConsumer* m_flushNotificationsConsumer; NotificationConsumer* m_fdbNotificationConsumer; diff --git a/orchagent/isolationgrouporch.cpp b/orchagent/isolationgrouporch.cpp index 618f2a3995..bf7374aa54 100644 --- a/orchagent/isolationgrouporch.cpp +++ b/orchagent/isolationgrouporch.cpp @@ -753,204 +753,3 @@ IsolationGroup::update(SubjectType, void *cntx) } } } - - - -DEBUGSH_CLI(IsolationGroupOrchGroupCreate, - "debug system internal orchagent isogroup group create (port|bridge) NAME", - DEBUG_COMMAND, - SYSTEM_DEBUG_COMMAND, - INTERNAL_COMMAND, - "Orchagent related commands", - "Isolation group orch related commands", - "Isolation group related commands", - "Create Isolation group", - "Port Isolation group", - "Bridge Port Isolation group", - "Isolation group name") -{ - isolation_group_status_t status; - isolation_group_type_t type = ISOLATION_GROUP_TYPE_PORT; - auto grp = gIsoGrpOrch->getIsolationGroup(args[0]); - - if (cmd_tokens[7] == "bridge") - { - type = ISOLATION_GROUP_TYPE_BRIDGE_PORT; - } - if (grp) - { - DEBUGSH_OUT(this, "Group %s exists", args[0].c_str()); - } - - status = gIsoGrpOrch->addIsolationGroup(args[0], type, "", "", ""); - if (ISO_GRP_STATUS_SUCCESS == status) - { - DEBUGSH_OUT(this, "Group %s of type %s create success", args[0].c_str(), cmd_tokens[7].c_str()); - } - else - { - DEBUGSH_OUT(this, "Group %s of type %s create failed with %d error", args[0].c_str(), cmd_tokens[7].c_str(), - status); - } -} - -DEBUGSH_CLI(IsolationGroupOrchGroupDelete, - "debug system internal orchagent isogroup group delete NAME", - DEBUG_COMMAND, - SYSTEM_DEBUG_COMMAND, - INTERNAL_COMMAND, - "Orchagent related commands", - "Isolation group orch related commands", - "Isolation group related commands", - "Delete Isolation group", - "Isolation group name") -{ - auto status = gIsoGrpOrch->delIsolationGroup(args[0]); - if (ISO_GRP_STATUS_SUCCESS == status) - { - DEBUGSH_OUT(this, "Group %s delete success", args[0].c_str()); - } - else - { - DEBUGSH_OUT(this, "Group %s delete failed with %d error", args[0].c_str(), status); - } -} - -DEBUGSH_CLI(IsolationGroupOrchGroupSetBinding, - "debug system internal orchagent isogroup group update NAME set-bind PORTS", - DEBUG_COMMAND, - SYSTEM_DEBUG_COMMAND, - INTERNAL_COMMAND, - "Orchagent related commands", - "Isolation group orch related commands", - "Isolation group related commands", - "Update Isolation group", - "Isolation group Name", - "Set Isolation group Binding", - "Port Names which are comma(,) separated") -{ - auto grp = gIsoGrpOrch->getIsolationGroup(args[0]); - auto status = grp->setBindPorts(args[1]); - - if (ISO_GRP_STATUS_SUCCESS == status) - { - DEBUGSH_OUT(this, "Group %s binding set to %s", args[0].c_str(), args[1].c_str()); - } - else - { - DEBUGSH_OUT(this, "Error %d Group %s binding set to %s", status, args[0].c_str(), args[1].c_str()); - } -} - -DEBUGSH_CLI(IsolationGroupOrchGroupSetMembers, - "debug system internal orchagent isogroup group update NAME set-members PORTS", - DEBUG_COMMAND, - SYSTEM_DEBUG_COMMAND, - INTERNAL_COMMAND, - "Orchagent related commands", - "Isolation group orch related commands", - "Isolation group related commands", - "Update Isolation group", - "Isolation group Name", - "Set Isolation group member ports", - "Port Names which are comma(,) separated") -{ - auto grp = gIsoGrpOrch->getIsolationGroup(args[0]); - auto status = grp->setMembers(args[1]); - - if (ISO_GRP_STATUS_SUCCESS == status) - { - DEBUGSH_OUT(this, "Group %s members set to %s", args[0].c_str(), args[1].c_str()); - } - else - { - DEBUGSH_OUT(this, "Error %d Group %s members set to %s", status, args[0].c_str(), args[1].c_str()); - } -} - -DEBUGSH_CLI(IsolationGroupOrchGroupDump, - "show system internal orchagent isogroup group (NAME|)", - SHOW_COMMAND, - SYSTEM_DEBUG_COMMAND, - INTERNAL_COMMAND, - "Orchagent related commands", - "Isolation group orch related commands", - "Isolation group related commands", - "Name of Isolation Group") -{ - if (args.size()) - { - gIsoGrpOrch->debugShowGroup(this, args[0]); - } - else - { - gIsoGrpOrch->debugShowGroup(this); - } -} - - -void -IsoGrpOrch::installDebugClis() -{ - DebugShCmd::install(new IsolationGroupOrchGroupCreate()); - DebugShCmd::install(new IsolationGroupOrchGroupDelete()); - DebugShCmd::install(new IsolationGroupOrchGroupSetBinding()); - DebugShCmd::install(new IsolationGroupOrchGroupSetMembers()); - DebugShCmd::install(new IsolationGroupOrchGroupDump()); -} - -void -IsoGrpOrch::debugShowGroup(DebugShCmd *cmd, string name) -{ - if (name == "") - { - for (auto kv : m_isolationGrps) - { - DEBUGSH_OUT(cmd, "-------------------------------------------------------------------------------------\n"); - kv.second->debugShow(cmd); - } - } - else - { - auto grp = gIsoGrpOrch->getIsolationGroup(name); - if (grp) - { - grp->debugShow(cmd); - } - } -} - -void -IsolationGroup::debugShow(DebugShCmd *cmd) -{ - DEBUGSH_OUT(cmd, - "Name:%s Type:%s Oid:%016lx\n", - m_name.c_str(), - m_type == ISOLATION_GROUP_TYPE_PORT ? "Port" : "Bridge-Port", - m_oid); - - DEBUGSH_OUT(cmd, "Member Ports:\n"); - for (auto kv : m_members) - { - DEBUGSH_OUT(cmd, " %s -> 0x%016lx\n", kv.first.c_str(), kv.second); - } - - DEBUGSH_OUT(cmd, "\nBind Ports:\n"); - for (auto v : m_bind_ports) - { - DEBUGSH_OUT(cmd, " %s\n", v.c_str()); - } - - DEBUGSH_OUT(cmd, "\nPending Member Ports:\n"); - for (auto v : m_pending_members) - { - DEBUGSH_OUT(cmd, " %s\n", v.c_str()); - } - - DEBUGSH_OUT(cmd, "\nPending Bind Ports:\n"); - for (auto v : m_pending_bind_ports) - { - DEBUGSH_OUT(cmd, " %s\n", v.c_str()); - } - -} diff --git a/orchagent/isolationgrouporch.h b/orchagent/isolationgrouporch.h index 15e45aa766..b8152cf96c 100644 --- a/orchagent/isolationgrouporch.h +++ b/orchagent/isolationgrouporch.h @@ -21,8 +21,6 @@ #include "orch.h" #include "port.h" #include "observer.h" -#include "debugshcmd.h" - #define ISOLATION_GRP_DESCRIPTION "DESCRIPTION" #define ISOLATION_GRP_TYPE "TYPE" @@ -96,9 +94,6 @@ class IsolationGroup: public Observer, public Subject this->notify(type, cntx); } - void - debugShow(DebugShCmd *cmd); - protected: string m_name; isolation_group_type_t m_type; @@ -127,12 +122,6 @@ class IsoGrpOrch : public Orch, public Observer void update(SubjectType, void *); - void - installDebugClis(); - - void - debugShowGroup(DebugShCmd *cmd, string name=""); - private: void doTask(Consumer &consumer); diff --git a/orchagent/mlagorch.cpp b/orchagent/mlagorch.cpp index 838f0bac40..7b4f7997af 100644 --- a/orchagent/mlagorch.cpp +++ b/orchagent/mlagorch.cpp @@ -63,23 +63,6 @@ void MlagOrch::update(SubjectType type, void *cntx) } } -DEBUGSH_CLI(MlagOrchShowDebug, - "show system internal orchagent mlag global", - SHOW_COMMAND, - SYSTEM_DEBUG_COMMAND, - INTERNAL_COMMAND, - "Orchagent related commands", - "Mlag orch related commands", - "Mlag global info") -{ - gMlagOrch->showDebugInfo(this); -} - -void MlagOrch::installDebugClis() -{ - DebugShCmd::install(new MlagOrchShowDebug()); -} - //------------------------------------------------------------------ //Private API section //------------------------------------------------------------------ @@ -538,42 +521,3 @@ bool MlagOrch::addAllMlagInterfacesToIsolationGroup() } } -void MlagOrch::showDebugInfo(DebugShCmd *cmd) -{ - Port mlag_port, isl_port; - - //Show Mlag interface info - DEBUGSH_OUT(cmd, "Isolation group name: %s(%s)\n", - MLAG_ISL_ISOLATION_GROUP_NAME, - gIsoGrpOrch->getIsolationGroup(MLAG_ISL_ISOLATION_GROUP_NAME) ? - "created" : "not created"); - DEBUGSH_OUT(cmd, "ICCP controls isolation group: %s\n", - m_iccp_control_isolation_grp ? "yes" : "no"); - DEBUGSH_OUT(cmd, "MlagOrch attaches to isolation group: %s\n", - m_attach_isolation_grp ? "yes" : "no"); - DEBUGSH_OUT(cmd, "Isolation group attach count: %u\n", m_num_isolation_grp_attach); - DEBUGSH_OUT(cmd, "Isolation group detach count: %u\n", m_num_isolation_grp_detach); - DEBUGSH_OUT(cmd, "Isolation group add error count: %u\n", m_num_isolation_grp_add_error); - DEBUGSH_OUT(cmd, "Isolation group delete error count: %u\n", m_num_isolation_grp_del_error); - DEBUGSH_OUT(cmd, "Isolation group update error count: %u\n\n", m_num_isolation_grp_update_error); - - DEBUGSH_OUT(cmd, "MLAG ISL interface: %s\n", m_isl_name.c_str()); - DEBUGSH_OUT(cmd, "MLAG interfaces: %lu\n", m_mlagIntfs.size()); - for (auto &name: m_mlagIntfs) - { - //MLAG interface is configured before the interface is configured - if (!gPortsOrch->getPort(name, mlag_port)) - { - DEBUGSH_OUT(cmd, " %s\n", name.c_str()); - } - else - { - DEBUGSH_OUT(cmd, - " %s: oper %s, traffic_disable %d, hw_pending_lag_mbrs %lu\n", - mlag_port.m_alias.c_str(), - oper_status_strings.at(mlag_port.m_oper_status).c_str(), - mlag_port.m_lag_traffic_disable, - mlag_port.m_hw_pending_lag_members.size()); - } - } -} diff --git a/orchagent/mlagorch.h b/orchagent/mlagorch.h index 736af86f56..8144d8a72b 100644 --- a/orchagent/mlagorch.h +++ b/orchagent/mlagorch.h @@ -23,7 +23,6 @@ #include "orch.h" #include "port.h" #include "isolationgrouporch.h" -#include "debugshcmd.h" struct MlagIfUpdate { @@ -43,8 +42,6 @@ class MlagOrch: public Orch, public Observer, public Subject MlagOrch(DBConnector *db, vector &tableNames); ~MlagOrch(); void update(SubjectType type, void *cntx); - void installDebugClis(); - void showDebugInfo(DebugShCmd *cmd); bool isMlagInterface(string if_name); bool isIslInterface(string if_name); diff --git a/orchagent/observer.h b/orchagent/observer.h index 6c222af6e4..60bbce7869 100644 --- a/orchagent/observer.h +++ b/orchagent/observer.h @@ -17,8 +17,8 @@ enum SubjectType SUBJECT_TYPE_INT_SESSION_CHANGE, SUBJECT_TYPE_PORT_CHANGE, SUBJECT_TYPE_MLAG_INTF_CHANGE, - SUBJECT_TYPE_BRIDGE_PORT_CHANGE - SUBJECT_TYPE_PORT_OPER_STATE_CHANGE, + SUBJECT_TYPE_BRIDGE_PORT_CHANGE, + SUBJECT_TYPE_PORT_OPER_STATE_CHANGE }; class Observer diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 2fee580676..b9df0caf1a 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -90,9 +90,17 @@ bool OrchDaemon::init() gCrmOrch = new CrmOrch(m_configDb, CFG_CRM_TABLE_NAME); gPortsOrch = new PortsOrch(m_applDb, ports_tables); - TableConnector applDbFdb(m_applDb, APP_FDB_TABLE_NAME); + + const int fdborch_pri = 20; + + vector app_fdb_tables = { + { APP_FDB_TABLE_NAME, fdborch_pri}, + { APP_MCLAG_FDB_TABLE_NAME, fdborch_pri} + }; + TableConnector stateDbFdb(m_stateDb, STATE_FDB_TABLE_NAME); - gFdbOrch = new FdbOrch(applDbFdb, stateDbFdb, gPortsOrch); + TableConnector stateMclagDbFdb(m_stateDb, STATE_MCLAG_REMOTE_FDB_TABLE_NAME); + gFdbOrch = new FdbOrch(m_applDb, app_fdb_tables, stateDbFdb, stateMclagDbFdb, gPortsOrch); vector vnet_tables = { APP_VNET_RT_TABLE_NAME, diff --git a/orchagent/port.h b/orchagent/port.h index d3ba42c4a0..59267a8c93 100644 --- a/orchagent/port.h +++ b/orchagent/port.h @@ -24,6 +24,7 @@ namespace swss { struct VlanMemberEntry { + std::string alias; sai_object_id_t vlan_member_id; sai_vlan_tagging_mode_t vlan_mode; }; @@ -83,6 +84,7 @@ class Port VlanInfo m_vlan_info; MacAddress m_mac; sai_object_id_t m_bridge_port_id = 0; // TODO: port could have multiple bridge port IDs + sai_object_id_t m_bridge_port_admin_state = 0; // TODO: port could have multiple bridge port IDs sai_vlan_id_t m_port_vlan_id = DEFAULT_PORT_VLAN_ID; // Port VLAN ID sai_object_id_t m_rif_id = 0; sai_object_id_t m_vr_id = 0; @@ -101,6 +103,8 @@ class Port std::vector m_priority_group_ids; sai_port_priority_flow_control_mode_t m_pfc_asym = SAI_PORT_PRIORITY_FLOW_CONTROL_MODE_COMBINED; uint8_t m_pfc_bitmask = 0; + uint32_t m_fdb_count = 0; + uint32_t m_up_member_count = 0; uint32_t m_nat_zone_id = 0; /* diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 21318fa319..79c7dd0c44 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -3622,7 +3622,7 @@ bool PortsOrch::addVlanMember(Port &vlan, Port &port, string &tagging_mode) } /* a physical port may join multiple vlans */ - VlanMemberEntry vme = {vlan_member_id, sai_tagging_mode}; + VlanMemberEntry vme = {vlan.m_alias, vlan_member_id, sai_tagging_mode}; port.m_vlan_members[vlan.m_vlan_info.vlan_id] = vme; m_portList[port.m_alias] = port; vlan.m_members.insert(port.m_alias); diff --git a/tests/test_mclag_cfg.py b/tests/test_mclag_cfg.py new file mode 100644 index 0000000000..0a79c767da --- /dev/null +++ b/tests/test_mclag_cfg.py @@ -0,0 +1,238 @@ +# Common file to test all MCLAG related changes +from swsscommon import swsscommon +import time +import re +import json +import pytest +import platform +from distutils.version import StrictVersion + + +def delete_table_keys(db, table): + tbl = swsscommon.Table(db, table) + keys = tbl.getKeys() + for key in keys: + tbl.delete(key) + +#check table entry exits with this key +def check_table_exists(db, table, key): + error_info = [ ] + tbl = swsscommon.Table(db, table) + keys = tbl.getKeys() + if key not in keys: + error_info.append("The table with desired key %s not found" % key) + return False, error_info + return True, error_info + +#check table entry doesn't exits with this key +def check_table_doesnt_exists(db, table, key): + error_info = [ ] + tbl = swsscommon.Table(db, table) + keys = tbl.getKeys() + if key in keys: + error_info.append("unexcpected: The table with desired key %s is found" % key) + return False, error_info + return True, error_info + + + + +# Test MCLAG Configs +class TestMclagConfig(object): + CFG_MCLAG_DOMAIN_TABLE = "MCLAG_DOMAIN" + CFG_MCLAG_INTERFACE_TABLE = "MCLAG_INTERFACE" + + PORTCHANNEL1 = "PortChannel11" + PORTCHANNEL2 = "PortChannel50" + PORTCHANNEL3 = "PortChannel51" + + MCLAG_DOMAIN_ID = "4095" + MCLAG_SRC_IP = "10.5.1.1" + MCLAG_PEER_IP = "10.5.1.2" + MCLAG_PEER_LINK = PORTCHANNEL1 + + MCLAG_DOMAIN_2 = "111" + + MCLAG_SESS_TMOUT_VALID_LIST = ["3","3600"] + MCLAG_KA_VALID_LIST = ["1","60"] + + MCLAG_KA_INVALID_LIST = ["0","61"] + MCLAG_SESS_TMOUT_INVALID_LIST = ["0","3601"] + + MCLAG_INTERFACE1 = PORTCHANNEL2 + MCLAG_INTERFACE2 = PORTCHANNEL3 + + + # Testcase 1 Verify Configuration of MCLAG Domain with src, peer ip and peer link config gets updated in CONFIG_DB + @pytest.mark.dev_sanity + def test_mclag_cfg_domain_add(self, dvs, testlog): + self.cfg_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + #cleanup existing entries + delete_table_keys(self.cfg_db, self.CFG_MCLAG_DOMAIN_TABLE) + delete_table_keys(self.cfg_db, self.CFG_MCLAG_INTERFACE_TABLE) + + cmd_string ="config mclag add {} {} {} {}".format(self.MCLAG_DOMAIN_ID, self.MCLAG_SRC_IP, self.MCLAG_PEER_IP, self.MCLAG_PEER_LINK) + dvs.runcmd(cmd_string) + time.sleep(2) + + #check whether domain cfg table contents are same as configured values + ok,error_info = dvs.all_table_entry_has(self.cfg_db, self.CFG_MCLAG_DOMAIN_TABLE, self.MCLAG_DOMAIN_ID, + [ + ("source_ip",self.MCLAG_SRC_IP), + ("peer_ip",self.MCLAG_PEER_IP), + ("peer_link",self.MCLAG_PEER_LINK) + ] + ) + assert ok,error_info + + # Testcase 2 Verify that second domain addition fails when there is already a domain configured + @pytest.mark.dev_sanity + def test_mclag_cfg_domain_add_2nd(self, dvs, testlog): + self.cfg_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + cmd_string ="config mclag add {} {} {} {}".format(self.MCLAG_DOMAIN_2, self.MCLAG_SRC_IP, self.MCLAG_PEER_IP, self.MCLAG_PEER_LINK) + dvs.runcmd(cmd_string) + time.sleep(2) + + #check whether second domain config is not added to config db + key_string = self.MCLAG_DOMAIN_2 + ok,error_info = check_table_doesnt_exists(self.cfg_db, self.CFG_MCLAG_DOMAIN_TABLE, key_string) + assert ok,error_info + + + + # Testcase 3 Verify Configuration of MCLAG Interface to existing domain + @pytest.mark.dev_sanity + def test_mclag_cfg_intf_add(self, dvs, testlog): + self.cfg_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + cmd_string ="config mclag member add {} {}".format(self.MCLAG_DOMAIN_ID, self.MCLAG_INTERFACE1) + dvs.runcmd(cmd_string) + time.sleep(2) + + #check whether mclag interface config is reflected + key_string = self.MCLAG_DOMAIN_ID + "|" + self.MCLAG_INTERFACE1 + ok,error_info = check_table_exists(self.cfg_db, self.CFG_MCLAG_INTERFACE_TABLE, key_string) + assert ok,error_info + + # Testcase 4 Verify remove and add mclag interface + @pytest.mark.dev_sanity + def test_mclag_cfg_intf_remove_and_add(self, dvs, testlog): + self.cfg_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + cmd_string ="config mclag member del {} {}".format(self.MCLAG_DOMAIN_ID, self.MCLAG_INTERFACE1) + dvs.runcmd(cmd_string) + time.sleep(2) + + #check whether mclag interface is removed + key_string = self.MCLAG_DOMAIN_ID + "|" + self.MCLAG_INTERFACE1 + ok,error_info = check_table_doesnt_exists(self.cfg_db, self.CFG_MCLAG_INTERFACE_TABLE, key_string) + assert ok,error_info + + #add different mclag interface + cmd_string ="config mclag member del {} {}".format(self.MCLAG_DOMAIN_ID, self.MCLAG_INTERFACE2) + dvs.runcmd(cmd_string) + time.sleep(2) + + #check whether new mclag interface is added + key_string = self.MCLAG_DOMAIN_ID + "|" + self.MCLAG_INTERFACE2 + ok,error_info = check_table_doesnt_exists(self.cfg_db, self.CFG_MCLAG_INTERFACE_TABLE, key_string) + assert ok,error_info + + # Testcase 5 Verify Configuration of valid values for session timeout + @pytest.mark.dev_sanity + def test_mclag_cfg_session_timeout_valid_values(self, dvs, testlog): + self.cfg_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + for value in self.MCLAG_SESS_TMOUT_VALID_LIST: + cmd_string ="config mclag session-timeout {} {}".format(self.MCLAG_DOMAIN_ID, value) + dvs.runcmd(cmd_string) + time.sleep(2) + + #check whether domain cfg table contents are same as configured values + ok,error_info = dvs.all_table_entry_has(self.cfg_db, self.CFG_MCLAG_DOMAIN_TABLE, self.MCLAG_DOMAIN_ID, + [ + ("source_ip",self.MCLAG_SRC_IP), + ("peer_ip",self.MCLAG_PEER_IP), + ("peer_link",self.MCLAG_PEER_LINK), + ("session_timeout",value) + ] + ) + assert ok,error_info + + # Testcase 6 Verify Configuration of valid values for KA timer + @pytest.mark.dev_sanity + def test_mclag_cfg_ka_valid_values(self, dvs, testlog): + self.cfg_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + for value in self.MCLAG_KA_VALID_LIST: + cmd_string ="config mclag keepalive-interval {} {}".format(self.MCLAG_DOMAIN_ID, value) + dvs.runcmd(cmd_string) + time.sleep(2) + + #check whether domain cfg table contents are same as configured values + ok,error_info = dvs.all_table_entry_has(self.cfg_db, self.CFG_MCLAG_DOMAIN_TABLE, self.MCLAG_DOMAIN_ID, + [ + ("source_ip",self.MCLAG_SRC_IP), + ("peer_ip",self.MCLAG_PEER_IP), + ("peer_link",self.MCLAG_PEER_LINK), + ("keepalive_interval",value) + ] + ) + assert ok,error_info + + + + # Testcase 7 Verify Configuration of invalid values for KA + @pytest.mark.dev_sanity + def test_mclag_cfg_ka_invalid_values(self, dvs, testlog): + self.cfg_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + for value in self.MCLAG_KA_INVALID_LIST: + cmd_string ="config mclag keepalive-interval {} {}".format(self.MCLAG_DOMAIN_ID, value) + dvs.runcmd(cmd_string) + time.sleep(2) + + #check whether domain cfg table contents are same as configured values + found,error_info = dvs.all_table_entry_has(self.cfg_db, self.CFG_MCLAG_DOMAIN_TABLE, self.MCLAG_DOMAIN_ID, + [ + ("keepalive_interval",value) + ] + ) + assert found == False, "invalid keepalive value %s written to CONFIG_DB" % value + + # Testcase 8 Verify Configuration of invalid values for session timeout + @pytest.mark.dev_sanity + def test_mclag_cfg_session_invalid_values(self, dvs, testlog): + self.cfg_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + for value in self.MCLAG_SESS_TMOUT_INVALID_LIST: + cmd_string ="config mclag session-timeout {} {}".format(self.MCLAG_DOMAIN_ID, value) + dvs.runcmd(cmd_string) + time.sleep(2) + + #check whether domain cfg table contents are same as configured values + found,error_info = dvs.all_table_entry_has(self.cfg_db, self.CFG_MCLAG_DOMAIN_TABLE, self.MCLAG_DOMAIN_ID, + [ + ("session_timeout",value) + ] + ) + assert found == False, "invalid keepalive value %s written to CONFIG_DB" % value + + # Testcase 9 Verify Deletion of MCLAG Domain + @pytest.mark.dev_sanity + def test_mclag_cfg_domain_del(self, dvs, testlog): + self.cfg_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + cmd_string ="config mclag del {}".format(self.MCLAG_DOMAIN_ID) + dvs.runcmd(cmd_string) + time.sleep(2) + + #check whether domain cfg table contents are same as configured values + ok, error_info = check_table_doesnt_exists(self.cfg_db, self.CFG_MCLAG_DOMAIN_TABLE, self.MCLAG_DOMAIN_ID) + assert ok,error_info + + #make sure mclag interface tables entries are also deleted when mclag domain is deleted + key_string = self.MCLAG_DOMAIN_ID + ok,error_info = check_table_doesnt_exists(self.cfg_db, self.CFG_MCLAG_INTERFACE_TABLE, key_string) + assert ok,error_info + From bc66c0af8125e419bb9a4c3523af0527c4bc2f1c Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Fri, 20 Nov 2020 14:22:49 -0800 Subject: [PATCH 03/54] Adding change to allow MCLAG remote MAC move. --- orchagent/fdborch.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index 40b7862a19..484aeb4127 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -385,6 +385,48 @@ void FdbOrch::update(sai_fdb_event_t type, } } + // If MAC is MCLAG remote do not delete for age event, Add the MAC back.. + if (existing_entry->second.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + { + sai_status_t status; + sai_fdb_entry_t fdb_entry; + + fdb_entry.switch_id = gSwitchId; + memcpy(fdb_entry.mac_address, entry->mac_address, sizeof(sai_mac_t)); + fdb_entry.bv_id = entry->bv_id; + + sai_attribute_t attr; + vector attrs; + + attr.id = SAI_FDB_ENTRY_ATTR_TYPE; + attr.value.s32 = SAI_FDB_ENTRY_TYPE_STATIC; + attrs.push_back(attr); + + attr.id = SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE; + attr.value.booldata = true; + attrs.push_back(attr); + + attr.id = SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID; + attr.value.oid = existing_entry->second.bridge_port_id; + attrs.push_back(attr); + + SWSS_LOG_NOTICE("fdbEvent: MAC age event received, MAC is MCLAG origin, added back" + "to HW type %s FDB %s in %s on %s", + existing_entry->second.type.c_str(), + update.entry.mac.to_string().c_str(), vlan.m_alias.c_str(), + update.port.m_alias.c_str()); + + status = sai_fdb_api->create_fdb_entry(&fdb_entry, (uint32_t)attrs.size(), attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create %s FDB %s in %s on %s, rv:%d", + existing_entry->second.type.c_str(), update.entry.mac.to_string().c_str(), + vlan.m_alias.c_str(), update.port.m_alias.c_str(), status); + fdb_dbg_cnt.common.fail_fdb_entry_create++; + } + return; + } + update.add = false; storeFdbEntryState(update); if (!update.port.m_alias.empty()) @@ -1070,7 +1112,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const if (type == "dynamic_local") attr.value.s32 = SAI_FDB_ENTRY_TYPE_DYNAMIC; else - attr.value.s32 = (type == "dynamic") ? SAI_FDB_ENTRY_TYPE_STATIC_MACMOVE : SAI_FDB_ENTRY_TYPE_STATIC; + attr.value.s32 = SAI_FDB_ENTRY_TYPE_STATIC; } else { @@ -1078,6 +1120,16 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const } attrs.push_back(attr); + if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + { + if (type != "dynamic_local") + { + attr.id = SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE; + attr.value.booldata = true; + attrs.push_back(attr); + } + } + attr.id = SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID; attr.value.oid = port.m_bridge_port_id; attrs.push_back(attr); From faa00b7ae1947fcdc12a260b0fedcbb2a4b8e37a Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Fri, 20 Nov 2020 14:48:49 -0800 Subject: [PATCH 04/54] Remove unused code. --- orchagent/fdborch.h | 6 ------ orchagent/isolationgrouporch.cpp | 1 - orchagent/mlagorch.cpp | 1 - 3 files changed, 8 deletions(-) diff --git a/orchagent/fdborch.h b/orchagent/fdborch.h index 29980d034c..0b53015915 100644 --- a/orchagent/fdborch.h +++ b/orchagent/fdborch.h @@ -44,12 +44,6 @@ struct FdbData FdbOrigin origin; }; -struct MclagFdbData -{ - string port; - string type; -}; - struct SavedFdbEntry { MacAddress mac; diff --git a/orchagent/isolationgrouporch.cpp b/orchagent/isolationgrouporch.cpp index bf7374aa54..5279fd5c5e 100644 --- a/orchagent/isolationgrouporch.cpp +++ b/orchagent/isolationgrouporch.cpp @@ -30,7 +30,6 @@ extern IsoGrpOrch *gIsoGrpOrch; IsoGrpOrch::IsoGrpOrch(vector &connectors) : Orch(connectors) { SWSS_LOG_ENTER(); - this->installDebugClis(); gPortsOrch->attach(this); } diff --git a/orchagent/mlagorch.cpp b/orchagent/mlagorch.cpp index 7b4f7997af..e4b42324ec 100644 --- a/orchagent/mlagorch.cpp +++ b/orchagent/mlagorch.cpp @@ -33,7 +33,6 @@ MlagOrch::MlagOrch(DBConnector *db, vector &tableNames): Orch(db, tableNames) { SWSS_LOG_ENTER(); - this->installDebugClis(); } MlagOrch::~MlagOrch() From d634b39576e928de7d8983fbe66a3a2df0676011 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Thu, 3 Dec 2020 23:56:38 -0800 Subject: [PATCH 05/54] 1.Updated the PR-885 latest changes. 2.Fixed build issues. 3. Added support for adding mclag remote mac to kernel, on top of PR-1276 --- .gitignore | 1 + Makefile.am | 2 +- configure.ac | 1 + fdbsyncd/Makefile.am | 17 + fdbsyncd/fdbsync.cpp | 803 ++++++++++++++++++++++++++++++++ fdbsyncd/fdbsync.h | 151 ++++++ fdbsyncd/fdbsyncd.cpp | 111 +++++ orchagent/fdborch.cpp | 639 +++++++++++++------------ orchagent/fdborch.h | 12 +- orchagent/observer.h | 54 ++- orchagent/port.h | 2 +- orchagent/portsorch.cpp | 412 ++++++++++++---- orchagent/portsorch.h | 21 +- tests/mock_tests/aclorch_ut.cpp | 12 +- 14 files changed, 1794 insertions(+), 444 deletions(-) create mode 100644 fdbsyncd/Makefile.am create mode 100644 fdbsyncd/fdbsync.cpp create mode 100644 fdbsyncd/fdbsync.h create mode 100644 fdbsyncd/fdbsyncd.cpp diff --git a/.gitignore b/.gitignore index f793ab78d9..af68a7c8b0 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,7 @@ cfgmgr/sflowmgrd fpmsyncd/fpmsyncd gearsyncd/gearsyncd mclagsyncd/mclagsyncd +fdbsyncd/fdbsyncd natsyncd/natsyncd neighsyncd/neighsyncd orchagent/orchagent diff --git a/Makefile.am b/Makefile.am index f2a71687db..c65daac646 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = fpmsyncd neighsyncd portsyncd mclagsyncd natsyncd orchagent swssconfig cfgmgr tests gearsyncd +SUBDIRS = fpmsyncd neighsyncd portsyncd mclagsyncd fdbsyncd natsyncd orchagent swssconfig cfgmgr tests gearsyncd if HAVE_LIBTEAM SUBDIRS += teamsyncd tlm_teamd diff --git a/configure.ac b/configure.ac index 11c793201d..d06fa5dd64 100644 --- a/configure.ac +++ b/configure.ac @@ -97,6 +97,7 @@ AC_CONFIG_FILES([ teamsyncd/Makefile tlm_teamd/Makefile mclagsyncd/Makefile + fdbsyncd/Makefile swssconfig/Makefile cfgmgr/Makefile tests/Makefile diff --git a/fdbsyncd/Makefile.am b/fdbsyncd/Makefile.am new file mode 100644 index 0000000000..f1b5010724 --- /dev/null +++ b/fdbsyncd/Makefile.am @@ -0,0 +1,17 @@ +INCLUDES = -I $(top_srcdir) -I $(top_srcdir)/warmrestart + +bin_PROGRAMS = fdbsyncd + +if DEBUG +DBGFLAGS = -ggdb -DDEBUG +else +DBGFLAGS = -g +endif + +fdbsyncd_SOURCES = fdbsyncd.cpp fdbsync.cpp $(top_srcdir)/warmrestart/warmRestartAssist.cpp + +fdbsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(COV_CFLAGS) +fdbsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(COV_CFLAGS) +fdbsyncd_LDADD = -lnl-3 -lnl-route-3 -lswsscommon $(COV_LDFLAGS) + + diff --git a/fdbsyncd/fdbsync.cpp b/fdbsyncd/fdbsync.cpp new file mode 100644 index 0000000000..e8d92b4a94 --- /dev/null +++ b/fdbsyncd/fdbsync.cpp @@ -0,0 +1,803 @@ +#include +#include +#include +#include +#include +#include + +#include "logger.h" +#include "dbconnector.h" +#include "producerstatetable.h" +#include "ipaddress.h" +#include "netmsg.h" +#include "macaddress.h" +#include "exec.h" +#include "fdbsync.h" +#include "warm_restart.h" +#include "errno.h" + +using namespace std; +using namespace swss; + +#define VXLAN_BR_IF_NAME_PREFIX "Brvxlan" + +FdbSync::FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db) : + m_fdbTable(pipelineAppDB, APP_VXLAN_FDB_TABLE_NAME), + m_imetTable(pipelineAppDB, APP_VXLAN_REMOTE_VNI_TABLE_NAME), + m_fdbStateTable(stateDb, STATE_FDB_TABLE_NAME), + m_mclagRemoteFdbStateTable(stateDb, STATE_MCLAG_REMOTE_FDB_TABLE_NAME), + m_cfgEvpnNvoTable(config_db, CFG_VXLAN_EVPN_NVO_TABLE_NAME) +{ + m_AppRestartAssist = new AppRestartAssist(pipelineAppDB, "fdbsyncd", "swss", DEFAULT_FDBSYNC_WARMSTART_TIMER); + if (m_AppRestartAssist) + { + m_AppRestartAssist->registerAppTable(APP_VXLAN_FDB_TABLE_NAME, &m_fdbTable); + m_AppRestartAssist->registerAppTable(APP_VXLAN_REMOTE_VNI_TABLE_NAME, &m_imetTable); + } +} + +FdbSync::~FdbSync() +{ + if (m_AppRestartAssist) + { + delete m_AppRestartAssist; + } +} + +void FdbSync::processCfgEvpnNvo() +{ + std::deque entries; + m_cfgEvpnNvoTable.pops(entries); + bool lastNvoState = m_isEvpnNvoExist; + + for (auto entry: entries) + { + std::string op = kfvOp(entry); + + if (op == SET_COMMAND) + { + m_isEvpnNvoExist = true; + } + else if (op == DEL_COMMAND) + { + m_isEvpnNvoExist = false; + } + + if (lastNvoState != m_isEvpnNvoExist) + { + updateAllLocalMac(); + } + } + return; +} + +void FdbSync::updateAllLocalMac() +{ + for ( auto it = m_fdb_mac.begin(); it != m_fdb_mac.end(); ++it ) + { + if (m_isEvpnNvoExist) + { + /* Add the Local FDB entry into Kernel */ + addLocalMac(it->first, "replace"); + } + else + { + /* Delete the Local FDB entry from Kernel */ + addLocalMac(it->first, "del"); + } + } +} + +void FdbSync::processStateFdb() +{ + struct m_fdb_info info; + std::deque entries; + + m_fdbStateTable.pops(entries); + + int count =0 ; + for (auto entry: entries) + { + count++; + std::string key = kfvKey(entry); + std::string op = kfvOp(entry); + + std::size_t delimiter = key.find_first_of(":"); + auto vlan_name = key.substr(0, delimiter); + auto mac_address = key.substr(delimiter+1); + + info.vid = vlan_name; + memcpy(info.mac, mac_address.c_str(),mac_address.length()); + + if(op == "SET") + { + info.op_type = FDB_OPER_ADD ; + } + else + { + info.op_type = FDB_OPER_DEL ; + } + + SWSS_LOG_INFO("FDBSYNCD STATE FDB updates key=%s, operation=%s\n", key.c_str(), op.c_str()); + + for (auto i : kfvFieldsValues(entry)) + { + SWSS_LOG_INFO(" FDBSYNCD STATE FDB updates : " + "FvFiels %s, FvValues: %s \n", fvField(i).c_str(), fvValue(i).c_str()); + + if(fvField(i) == "port") + { + memcpy(info.port_name, fvValue(i).c_str(), fvValue(i).length()); + } + + if(fvField(i) == "type") + { + if(fvValue(i) == "dynamic") + { + info.type = FDB_TYPE_DYNAMIC; + } + else if (fvValue(i) == "static") + { + info.type = FDB_TYPE_STATIC; + } + } + } + + if (op != "SET" && macCheckSrcDB(&info) == false) + { + continue; + } + updateLocalMac(&info); + } +} + +void FdbSync::processStateMclagRemoteFdb() +{ + struct m_fdb_info info; + std::deque entries; + + m_mclagRemoteFdbStateTable.pops(entries); + + int count =0 ; + for (auto entry: entries) + { + count++; + std::string key = kfvKey(entry); + std::string op = kfvOp(entry); + + std::size_t delimiter = key.find_first_of(":"); + auto vlan_name = key.substr(0, delimiter); + auto mac_address = key.substr(delimiter+1); + + info.vid = vlan_name; + memcpy(info.mac, mac_address.c_str(),mac_address.length()); + + if(op == "SET") + { + info.op_type = FDB_OPER_ADD ; + } + else + { + info.op_type = FDB_OPER_DEL ; + } + + SWSS_LOG_INFO("FDBSYNCD STATE FDB updates key=%s, operation=%s\n", key.c_str(), op.c_str()); + + for (auto i : kfvFieldsValues(entry)) + { + SWSS_LOG_INFO(" FDBSYNCD STATE FDB updates : " + "FvFiels %s, FvValues: %s \n", fvField(i).c_str(), fvValue(i).c_str()); + + if(fvField(i) == "port") + { + memcpy(info.port_name, fvValue(i).c_str(), fvValue(i).length()); + } + + if(fvField(i) == "type") + { + if(fvValue(i) == "dynamic") + { + info.type = FDB_TYPE_DYNAMIC; + } + else if (fvValue(i) == "static") + { + info.type = FDB_TYPE_STATIC; + } + } + } + + if (op != "SET" && macCheckSrcDB(&info) == false) + { + continue; + } + updateMclagRemoteMac(&info); + } +} + +void FdbSync::macUpdateCache(struct m_fdb_info *info) +{ + string key = info->vid + ":" + info->mac; + m_fdb_mac[key].port_name = info->port_name; + m_fdb_mac[key].type = info->type; + + return; +} + +void FdbSync::macUpdateMclagRemoteCache(struct m_fdb_info *info) +{ + string key = info->vid + ":" + info->mac; + m_mclag_remote_fdb_mac[key].port_name = info->port_name; + m_mclag_remote_fdb_mac[key].type = info->type; + + return; +} + +bool FdbSync::macCheckSrcDB(struct m_fdb_info *info) +{ + string key = info->vid + ":" + info->mac; + if (m_fdb_mac.find(key) != m_fdb_mac.end()) + { + SWSS_LOG_INFO("DEL_KEY %s ", key.c_str()); + return true; + } + + return false; +} + +void FdbSync::macDelVxlanEntry(string auxkey, struct m_fdb_info *info) +{ + std::string vtep = m_mac[auxkey].vtep; + + const std::string cmds = std::string("") + + " bridge fdb del " + info->mac + " dev " + + m_mac[auxkey].ifname + " dst " + vtep + " vlan " + info->vid.substr(4); + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_INFO("Success cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + + return; +} + +void FdbSync::updateLocalMac (struct m_fdb_info *info) +{ + char *op; + char *type; + string port_name = ""; + string key = info->vid + ":" + info->mac; + short fdb_type; /*dynamic or static*/ + + if (info->op_type == FDB_OPER_ADD) + { + macUpdateCache(info); + op = "replace"; + port_name = info->port_name; + fdb_type = info->type; + /* Check if this vlan+key is also learned by vxlan neighbor then delete learned on */ + if (m_mac.find(key) != m_mac.end()) + { + macDelVxlanEntry(key, info); + SWSS_LOG_INFO("Local learn event deleting from VXLAN table DEL_KEY %s", key.c_str()); + macDelVxlan(key); + } + } + else + { + op = "del"; + port_name = m_fdb_mac[key].port_name; + fdb_type = m_fdb_mac[key].type; + m_fdb_mac.erase(key); + } + + if (!m_isEvpnNvoExist) + { + SWSS_LOG_INFO("Ignore kernel update EVPN NVO is not configured MAC %s", key.c_str()); + return; + } + + if (fdb_type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + op + " " + info->mac + " dev " + + port_name + " master " + type + " vlan " + info->vid.substr(4); + + std::string res; + int ret = swss::exec(cmds, res); + + SWSS_LOG_INFO("cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + + return; +} + +void FdbSync::addLocalMac(string key, string op) +{ + char *type; + string port_name = ""; + string mac = ""; + string vlan = ""; + size_t str_loc = string::npos; + + str_loc = key.find(":"); + if (str_loc == string::npos) + { + SWSS_LOG_ERROR("Local MAC issue with Key:%s", key.c_str()); + return; + } + vlan = key.substr(4, str_loc-4); + mac = key.substr(str_loc+1, std::string::npos); + + SWSS_LOG_INFO("Local route Vlan:%s MAC:%s Key:%s Op:%s", vlan.c_str(), mac.c_str(), key.c_str(), op.c_str()); + + if (m_fdb_mac.find(key)!=m_fdb_mac.end()) + { + port_name = m_fdb_mac[key].port_name; + if (port_name.empty()) + { + SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); + return; + } + + if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + op + " " + mac + " dev " + + port_name + " master " + type + " vlan " + vlan; + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_INFO("Config triggered cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + return; +} + +void FdbSync::updateMclagRemoteMac (struct m_fdb_info *info) +{ + char *op; + char *type; + string port_name = ""; + string key = info->vid + ":" + info->mac; + short fdb_type; /*dynamic or static*/ + + if (info->op_type == FDB_OPER_ADD) + { + macUpdateMclagRemoteCache(info); + op = "replace"; + port_name = info->port_name; + fdb_type = info->type; + } + else + { + op = "del"; + port_name = m_mclag_remote_fdb_mac[key].port_name; + fdb_type = m_mclag_remote_fdb_mac[key].type; + m_mclag_remote_fdb_mac.erase(key); + } + + if (fdb_type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + op + " " + info->mac + " dev " + + port_name + " master " + type + " vlan " + info->vid.substr(4); + + std::string res; + int ret = swss::exec(cmds, res); + + SWSS_LOG_INFO("cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + + return; +} + +/* + * This is a special case handling where mac is learned in the ASIC. + * Then MAC is learned in the Kernel, Since this mac is learned in the Kernel + * This MAC will age out, when MAC delete is received from the Kernel. + * If MAC is still present in the state DB cache then fdbsyncd will be + * re-programmed with MAC in the Kernel + */ +void FdbSync::macRefreshStateDB(int vlan, string kmac) +{ + string key = "Vlan" + to_string(vlan) + ":" + kmac; + char *type; + string port_name = ""; + + SWSS_LOG_INFO("Refreshing Vlan:%d MAC route MAC:%s Key %s", vlan, kmac.c_str(), key.c_str()); + + if (m_fdb_mac.find(key)!=m_fdb_mac.end()) + { + port_name = m_fdb_mac[key].port_name; + if (port_name.empty()) + { + SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); + return; + } + + if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + "replace" + " " + kmac + " dev " + + port_name + " master " + type + " vlan " + to_string(vlan); + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_INFO("Refreshing cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + return; +} + +bool FdbSync::checkImetExist(string key, uint32_t vni) +{ + if (m_imet_route.find(key) != m_imet_route.end()) + { + SWSS_LOG_INFO("IMET exist key:%s Vni:%d", key.c_str(), vni); + return false; + } + m_imet_route[key].vni = vni; + return true; +} + +bool FdbSync::checkDelImet(string key, uint32_t vni) +{ + int ret = false; + + SWSS_LOG_INFO("Del IMET key:%s Vni:%d", key.c_str(), vni); + if (m_imet_route.find(key) != m_imet_route.end()) + { + ret = true; + m_imet_route.erase(key); + } + return ret; +} + +void FdbSync::imetAddRoute(struct in_addr vtep, string vlan_str, uint32_t vni) +{ + string vlan_id = "Vlan" + vlan_str; + string key = vlan_id + ":" + inet_ntoa(vtep); + + if (!checkImetExist(key, vni)) + { + return; + } + + SWSS_LOG_INFO("%sIMET Add route key:%s vtep:%s %s", + m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", + key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); + + std::vector fvVector; + FieldValueTuple f("vni", to_string(vni)); + fvVector.push_back(f); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, false); + return; + } + + m_imetTable.set(key, fvVector); + return; +} + +void FdbSync::imetDelRoute(struct in_addr vtep, string vlan_str, uint32_t vni) +{ + string vlan_id = "Vlan" + vlan_str; + string key = vlan_id + ":" + inet_ntoa(vtep); + + if (!checkDelImet(key, vni)) + { + return; + } + + SWSS_LOG_INFO("%sIMET Del route key:%s vtep:%s %s", + m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", + key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); + + std::vector fvVector; + FieldValueTuple f("vni", to_string(vni)); + fvVector.push_back(f); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, true); + return; + } + + m_imetTable.del(key); + return; +} + +void FdbSync::macDelVxlanDB(string key) +{ + string vtep = m_mac[key].vtep; + string type; + string vni = to_string(m_mac[key].vni); + type = m_mac[key].type; + + std::vector fvVector; + FieldValueTuple rv("remote_vtep", vtep); + FieldValueTuple t("type", type); + FieldValueTuple v("vni", vni); + fvVector.push_back(rv); + fvVector.push_back(t); + fvVector.push_back(v); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, true); + return; + } + + SWSS_LOG_INFO("VXLAN_FDB_TABLE: DEL_KEY %s vtep:%s type:%s", key.c_str(), vtep.c_str(), type.c_str()); + m_fdbTable.del(key); + return; + +} + +void FdbSync::macAddVxlan(string key, struct in_addr vtep, string type, uint32_t vni, string intf_name) +{ + string svtep = inet_ntoa(vtep); + string svni = to_string(vni); + + /* Update the DB with Vxlan MAC */ + m_mac[key] = {svtep, type, vni, intf_name}; + + std::vector fvVector; + FieldValueTuple rv("remote_vtep", svtep); + FieldValueTuple t("type", type); + FieldValueTuple v("vni", svni); + fvVector.push_back(rv); + fvVector.push_back(t); + fvVector.push_back(v); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, false); + return; + } + + SWSS_LOG_INFO("VXLAN_FDB_TABLE: ADD_KEY %s vtep:%s type:%s", key.c_str(), svtep.c_str(), type.c_str()); + m_fdbTable.set(key, fvVector); + + return; +} + +void FdbSync::macDelVxlan(string key) +{ + if (m_mac.find(key) != m_mac.end()) + { + SWSS_LOG_INFO("DEL_KEY %s vtep:%s type:%s", key.c_str(), m_mac[key].vtep.c_str(), m_mac[key].type.c_str()); + macDelVxlanDB(key); + m_mac.erase(key); + } + return; +} + +void FdbSync::onMsgNbr(int nlmsg_type, struct nl_object *obj) +{ + char macStr[MAX_ADDR_SIZE + 1] = {0}; + struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj; + struct in_addr vtep = {0}; + int vlan = 0, ifindex = 0; + uint32_t vni = 0; + nl_addr *vtep_addr; + string ifname; + string key; + bool delete_key = false; + size_t str_loc = string::npos; + string type = ""; + string vlan_id = ""; + bool isVxlanIntf = false; + + if ((nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_GETNEIGH) && + (nlmsg_type != RTM_DELNEIGH)) + { + return; + } + + /* Only MAC route is to be supported */ + if (rtnl_neigh_get_family(neigh) != AF_BRIDGE) + { + return; + } + ifindex = rtnl_neigh_get_ifindex(neigh); + if (m_intf_info.find(ifindex) != m_intf_info.end()) + { + isVxlanIntf = true; + ifname = m_intf_info[ifindex].ifname; + } + + nl_addr2str(rtnl_neigh_get_lladdr(neigh), macStr, MAX_ADDR_SIZE); + + if (isVxlanIntf == false) + { + if (nlmsg_type != RTM_DELNEIGH) + { + return; + } + } + else + { + /* If this is for vnet bridge vxlan interface, then return */ + if (ifname.find(VXLAN_BR_IF_NAME_PREFIX) != string::npos) + { + return; + } + + /* VxLan netdevice should be in - format */ + str_loc = ifname.rfind("-"); + if (str_loc == string::npos) + { + return; + } + + vlan_id = "Vlan" + ifname.substr(str_loc+1, std::string::npos); + vni = m_intf_info[ifindex].vni; + } + + + if (isVxlanIntf == false) + { + vlan = rtnl_neigh_get_vlan(neigh); + if (m_isEvpnNvoExist) + { + macRefreshStateDB(vlan, macStr); + } + return; + } + + vtep_addr = rtnl_neigh_get_dst(neigh); + if (vtep_addr == NULL) + { + return; + } + else + { + /* Currently we only support ipv4 tunnel endpoints */ + vtep.s_addr = *(uint32_t *)nl_addr_get_binary_addr(vtep_addr); + SWSS_LOG_INFO("Tunnel IP %s Int%d", inet_ntoa(vtep), *(uint32_t *)nl_addr_get_binary_addr(vtep_addr)); + } + + int state = rtnl_neigh_get_state(neigh); + if ((nlmsg_type == RTM_DELNEIGH) || (state == NUD_INCOMPLETE) || + (state == NUD_FAILED)) + { + delete_key = true; + } + + if (state & NUD_NOARP) + { + /* This is a static route */ + type = "static"; + } + else + { + type = "dynamic"; + } + + /* Handling IMET routes */ + if (MacAddress(macStr) == MacAddress("00:00:00:00:00:00")) + { + if (vtep.s_addr) + { + string vlan_str = ifname.substr(str_loc+1, string::npos); + + if (!delete_key) + { + imetAddRoute(vtep, vlan_str, vni); + } + else + { + imetDelRoute(vtep, vlan_str, vni); + } + } + return; + } + + key+= vlan_id; + key+= ":"; + key+= macStr; + + if (!delete_key) + { + macAddVxlan(key, vtep, type, vni, ifname); + } + else + { + macDelVxlan(key); + } + return; +} + +void FdbSync::onMsgLink(int nlmsg_type, struct nl_object *obj) +{ + struct rtnl_link *link; + char *ifname = NULL; + char *nil = "NULL"; + int ifindex; + unsigned int vni; + + link = (struct rtnl_link *)obj; + ifname = rtnl_link_get_name(link); + ifindex = rtnl_link_get_ifindex(link); + if (rtnl_link_is_vxlan(link) == 0) + { + return; + } + + if (rtnl_link_vxlan_get_id(link, &vni) != 0) + { + SWSS_LOG_INFO("Op:%d VxLAN dev:%s index:%d vni:%d. Not found", nlmsg_type, ifname? ifname: nil, ifindex, vni); + return; + } + SWSS_LOG_INFO("Op:%d VxLAN dev %s index:%d vni:%d", nlmsg_type, ifname? ifname: nil, ifindex, vni); + if (nlmsg_type == RTM_NEWLINK) + { + m_intf_info[ifindex].vni = vni; + m_intf_info[ifindex].ifname = ifname; + } + return; +} + +void FdbSync::onMsg(int nlmsg_type, struct nl_object *obj) +{ + if ((nlmsg_type != RTM_NEWLINK) && + (nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_DELNEIGH)) + { + SWSS_LOG_DEBUG("netlink: unhandled event: %d", nlmsg_type); + return; + } + if (nlmsg_type == RTM_NEWLINK) + { + onMsgLink(nlmsg_type, obj); + } + else + { + onMsgNbr(nlmsg_type, obj); + } +} + diff --git a/fdbsyncd/fdbsync.h b/fdbsyncd/fdbsync.h new file mode 100644 index 0000000000..9487e225c6 --- /dev/null +++ b/fdbsyncd/fdbsync.h @@ -0,0 +1,151 @@ +#ifndef __FDBSYNC__ +#define __FDBSYNC__ + +#include +#include +#include "dbconnector.h" +#include "producerstatetable.h" +#include "subscriberstatetable.h" +#include "netmsg.h" +#include "warmRestartAssist.h" + +// The timeout value (in seconds) for fdbsyncd reconcilation logic +#define DEFAULT_FDBSYNC_WARMSTART_TIMER 30 + +namespace swss { + +enum FDB_OP_TYPE { + FDB_OPER_ADD =1, + FDB_OPER_DEL = 2, +}; + +enum FDB_TYPE { + FDB_TYPE_STATIC = 1, + FDB_TYPE_DYNAMIC = 2, +}; + +struct m_fdb_info +{ + char mac[32]; + std::string vid; /*Store as Vlan */ + char port_name[32]; + short type; /*dynamic or static*/ + short op_type; /*add or del*/ +}; + +class FdbSync : public NetMsg +{ +public: + enum { MAX_ADDR_SIZE = 64 }; + + FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db); + ~FdbSync(); + + virtual void onMsg(int nlmsg_type, struct nl_object *obj); + + bool isFdbRestoreDone(); + + AppRestartAssist *getRestartAssist() + { + return m_AppRestartAssist; + } + + SubscriberStateTable *getFdbStateTable() + { + return &m_fdbStateTable; + } + + SubscriberStateTable *getMclagRemoteFdbStateTable() + { + return &m_mclagRemoteFdbStateTable; + } + + SubscriberStateTable *getCfgEvpnNvoTable() + { + return &m_cfgEvpnNvoTable; + } + + void processStateFdb(); + + void processStateMclagRemoteFdb(); + + void processCfgEvpnNvo(); + + bool m_reconcileDone = false; + + bool m_isEvpnNvoExist = false; + +private: + ProducerStateTable m_fdbTable; + ProducerStateTable m_imetTable; + SubscriberStateTable m_fdbStateTable; + SubscriberStateTable m_mclagRemoteFdbStateTable; + AppRestartAssist *m_AppRestartAssist; + SubscriberStateTable m_cfgEvpnNvoTable; + + struct m_local_fdb_info + { + std::string port_name; + short type;/*dynamic or static*/ + }; + std::unordered_map m_fdb_mac; + + std::unordered_map m_mclag_remote_fdb_mac; + + void macDelVxlanEntry(std::string auxkey, struct m_fdb_info *info); + + void macUpdateCache(struct m_fdb_info *info); + + bool macCheckSrcDB(struct m_fdb_info *info); + + void updateLocalMac(struct m_fdb_info *info); + + void updateAllLocalMac(); + + void macRefreshStateDB(int vlan, std::string kmac); + + void updateMclagRemoteMac(struct m_fdb_info *info); + + void macUpdateMclagRemoteCache(struct m_fdb_info *info); + + bool checkImetExist(std::string key, uint32_t vni); + + bool checkDelImet(std::string key, uint32_t vni); + + struct m_mac_info + { + std::string vtep; + std::string type; + unsigned int vni; + std::string ifname; + }; + std::unordered_map m_mac; + + struct m_imet_info + { + unsigned int vni; + }; + std::unordered_map m_imet_route; + + struct intf + { + std::string ifname; + unsigned int vni; + }; + std::unordered_map m_intf_info; + + void addLocalMac(std::string key, std::string op); + void macAddVxlan(std::string key, struct in_addr vtep, std::string type, uint32_t vni, std::string intf_name); + void macDelVxlan(std::string auxkey); + void macDelVxlanDB(std::string key); + void imetAddRoute(struct in_addr vtep, std::string ifname, uint32_t vni); + void imetDelRoute(struct in_addr vtep, std::string ifname, uint32_t vni); + void onMsgNbr(int nlmsg_type, struct nl_object *obj); + void onMsgLink(int nlmsg_type, struct nl_object *obj); +}; + +} + +#endif + + diff --git a/fdbsyncd/fdbsyncd.cpp b/fdbsyncd/fdbsyncd.cpp new file mode 100644 index 0000000000..60e88477d1 --- /dev/null +++ b/fdbsyncd/fdbsyncd.cpp @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include "logger.h" +#include "select.h" +#include "netdispatcher.h" +#include "netlink.h" +#include "fdbsyncd/fdbsync.h" + +using namespace std; +using namespace swss; + +int main(int argc, char **argv) +{ + Logger::linkToDbNative("fdbsyncd"); + + DBConnector appDb(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + RedisPipeline pipelineAppDB(&appDb); + DBConnector stateDb(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + DBConnector log_db(LOGLEVEL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + DBConnector config_db(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + + FdbSync sync(&pipelineAppDB, &stateDb, &config_db); + + NetDispatcher::getInstance().registerMessageHandler(RTM_NEWNEIGH, &sync); + NetDispatcher::getInstance().registerMessageHandler(RTM_DELNEIGH, &sync); + NetDispatcher::getInstance().registerMessageHandler(RTM_NEWLINK, &sync); + + while (1) + { + try + { + NetLink netlink; + Selectable *temps; + int ret; + Select s; + + using namespace std::chrono; + + /* + * If WarmStart is enabled, restore the VXLAN-FDB and VNI + * tables and start a reconcillation timer + */ + if (sync.getRestartAssist()->isWarmStartInProgress()) + { + sync.getRestartAssist()->readTablesToMap(); + SWSS_LOG_NOTICE("Starting ReconcileTimer"); + } + + netlink.registerGroup(RTNLGRP_LINK); + netlink.registerGroup(RTNLGRP_NEIGH); + SWSS_LOG_NOTICE("Listens to link and neigh messages..."); + netlink.dumpRequest(RTM_GETLINK); + s.addSelectable(&netlink); + ret = s.select(&temps, 1); + if (ret == Select::ERROR) + { + SWSS_LOG_ERROR("Error in RTM_GETLINK dump"); + } + + netlink.dumpRequest(RTM_GETNEIGH); + + s.addSelectable(sync.getFdbStateTable()); + s.addSelectable(sync.getMclagRemoteFdbStateTable()); + s.addSelectable(sync.getCfgEvpnNvoTable()); + while (true) + { + s.select(&temps); + + if(temps == (Selectable *)sync.getFdbStateTable()) + { + sync.processStateFdb(); + } + else if(temps == (Selectable *)sync.getMclagRemoteFdbStateTable()) + { + sync.processStateMclagRemoteFdb(); + } + else if (temps == (Selectable *)sync.getCfgEvpnNvoTable()) + { + sync.processCfgEvpnNvo(); + } + else + { + /* + * If warmstart is in progress, we check the reconcile timer, + * if timer expired, we stop the timer and start the reconcile process + */ + if (sync.getRestartAssist()->isWarmStartInProgress()) + { + if (sync.getRestartAssist()->checkReconcileTimer(temps)) + { + sync.m_reconcileDone = true; + sync.getRestartAssist()->stopReconcileTimer(s); + sync.getRestartAssist()->reconcile(); + SWSS_LOG_NOTICE("VXLAN FDB VNI Reconcillation Complete (Timer)"); + } + } + } + } + } + catch (const std::exception& e) + { + cout << "Exception \"" << e.what() << "\" had been thrown in deamon" << endl; + return 0; + } + } + + return 1; +} + diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index 967854edea..7411dcbb54 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -11,7 +11,6 @@ #include "crmorch.h" #include "notifier.h" #include "sai_serialize.h" -#include "neighorch.h" #include "mlagorch.h" #include "directory.h" @@ -71,8 +70,9 @@ bool FdbOrch::bake() bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) { const FdbEntry& entry = update.entry; - FdbData fdbdata; + const FdbData fdbdata = {update.port.m_bridge_port_id, update.type, FDB_ORIGIN_LEARN}; FdbData oldFdbData; + const Port& port = update.port; const MacAddress& mac = entry.mac; string portName = port.m_alias; @@ -90,16 +90,13 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) if (update.add) { - bool mac_move=false; + bool mac_move = false; auto it = m_entries.find(entry); - if(it != m_entries.end()) + if (it != m_entries.end()) { - /* This block is specifically added for MAC_MOVE event - and not expected to be executed for LEARN event - */ - if(port.m_bridge_port_id == it->second.bridge_port_id) + if (port.m_bridge_port_id == it->second.bridge_port_id) { - if (it->second.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + if (it->second.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) { mac_move=true; oldFdbData = it->second; @@ -110,20 +107,15 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) return false; } } - - mac_move=true; - oldFdbData = it->second; + mac_move = true; + oldFdbData = it->second; } - fdbdata.bridge_port_id = update.port.m_bridge_port_id; - fdbdata.type = update.type; - fdbdata.origin = FDB_ORIGIN_LEARN; - m_entries[entry] = fdbdata; - SWSS_LOG_NOTICE("FdbOrch notification: mac %s was inserted into bv_id 0x%" PRIx64, + SWSS_LOG_DEBUG("FdbOrch notification: mac %s was inserted into bv_id 0x%" PRIx64, entry.mac.to_string().c_str(), entry.bv_id); - SWSS_LOG_NOTICE("m_entries size=%lu mac=%s port=%lx", m_entries.size(), - entry.mac.to_string().c_str(), m_entries[entry].bridge_port_id); + SWSS_LOG_DEBUG("m_entries size=%lu mac=%s port=0x%" PRIx64, + m_entries.size(), entry.mac.to_string().c_str(), m_entries[entry].bridge_port_id); if (mac_move && (oldFdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED)) { @@ -131,22 +123,18 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) "bv_id 0x%" PRIx64, entry.mac.to_string().c_str(), entry.bv_id); m_mclagFdbStateTable.del(key); - } - // Write to StateDb std::vector fvs; - fvs.push_back(FieldValueTuple("port", portName)); fvs.push_back(FieldValueTuple("type", update.type)); m_fdbStateTable.set(key, fvs); - if(!mac_move) + if (!mac_move) { gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); } - return true; } else @@ -156,9 +144,8 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) { oldFdbData = it->second; } - size_t erased = m_entries.erase(entry); - SWSS_LOG_NOTICE("FdbOrch notification: mac %s was removed from bv_id 0x%" PRIx64, entry.mac.to_string().c_str(), entry.bv_id); + SWSS_LOG_DEBUG("FdbOrch notification: mac %s was removed from bv_id 0x%" PRIx64, entry.mac.to_string().c_str(), entry.bv_id); if (erased == 0) { @@ -172,6 +159,9 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) m_mclagFdbStateTable.del(key); } + // Remove in StateDb + m_fdbStateTable.del(key); + gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); return true; } @@ -206,18 +196,17 @@ void FdbOrch::update(sai_fdb_event_t type, { case SAI_FDB_EVENT_LEARNED: { - SWSS_LOG_INFO("Received LEARN event for bvid=%lx mac=%s port=%lx", - entry->bv_id, update.entry.mac.to_string().c_str(), bridge_port_id); + SWSS_LOG_INFO("Received LEARN event for bvid=0x%" PRIx64 "mac=%s port=0x%" PRIx64, entry->bv_id, update.entry.mac.to_string().c_str(), bridge_port_id); if (!m_portsOrch->getPort(entry->bv_id, vlan)) { - SWSS_LOG_ERROR("FdbOrch LEARN notification: Failed to locate vlan port from bv_id 0x%lx", entry->bv_id); + SWSS_LOG_ERROR("FdbOrch LEARN notification: Failed to locate vlan port from bv_id 0x%" PRIx64, entry->bv_id); return; } if (!m_portsOrch->getPortByBridgePortId(bridge_port_id, update.port)) { - SWSS_LOG_ERROR("Failed to get port by bridge port ID 0x%" PRIx64, bridge_port_id); + SWSS_LOG_ERROR("FdbOrch LEARN notification: Failed to get port by bridge port ID 0x%" PRIx64, bridge_port_id); return; } @@ -225,10 +214,11 @@ void FdbOrch::update(sai_fdb_event_t type, auto existing_entry = m_entries.find(update.entry); if (existing_entry != m_entries.end()) { - SWSS_LOG_INFO("FdbOrch LEARN notification: mac %s with origin %d is already in bv_id 0x%lx with different BP existing-bp 0x%lx new-bp:0x%lx", - update.entry.mac.to_string().c_str(), existing_entry->second.origin, entry->bv_id, existing_entry->second.bridge_port_id, bridge_port_id); + SWSS_LOG_INFO("FdbOrch LEARN notification: mac %s is already in bv_id 0x%" + PRIx64 "existing-bp 0x%" PRIx64 "new-bp:0x%" PRIx64, + update.entry.mac.to_string().c_str(), entry->bv_id, existing_entry->second.bridge_port_id, bridge_port_id); - if (existing_entry->second.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + if (existing_entry->second.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) { // If the bp is different MOVE the MAC entry. if (existing_entry->second.bridge_port_id != bridge_port_id) @@ -298,6 +288,7 @@ void FdbOrch::update(sai_fdb_event_t type, update.entry.mac.to_string().c_str(), entry->bv_id, existing_entry->second.bridge_port_id, bridge_port_id); break; } + } update.add = true; @@ -310,10 +301,8 @@ void FdbOrch::update(sai_fdb_event_t type, m_portsOrch->setPort(vlan.m_alias, vlan); SWSS_LOG_INFO("Notifying observers of FDB entry LEARN"); - for (auto observer: m_observers) - { - observer->update(SUBJECT_TYPE_FDB_CHANGE, &update); - } + + notify(SUBJECT_TYPE_FDB_CHANGE, &update); break; } @@ -356,9 +345,8 @@ void FdbOrch::update(sai_fdb_event_t type, { if (vlan.m_members.find(update.port.m_alias) == vlan.m_members.end()) { - update.type = "static"; - //tbd_to_build - //saved_fdb_entries[update.port.m_alias].push_back({existing_entry->first.mac, vlan.m_vlan_info.vlan_id, "static"}); + update.type = "static"; + saved_fdb_entries[update.port.m_alias].push_back({existing_entry->first.mac, vlan.m_vlan_info.vlan_id, "static", FDB_ORIGIN_PROVISIONED }); } else { @@ -422,11 +410,9 @@ void FdbOrch::update(sai_fdb_event_t type, SWSS_LOG_ERROR("Failed to create %s FDB %s in %s on %s, rv:%d", existing_entry->second.type.c_str(), update.entry.mac.to_string().c_str(), vlan.m_alias.c_str(), update.port.m_alias.c_str(), status); - fdb_dbg_cnt.common.fail_fdb_entry_create++; } return; } - update.add = false; storeFdbEntryState(update); if (!update.port.m_alias.empty()) @@ -441,12 +427,8 @@ void FdbOrch::update(sai_fdb_event_t type, } SWSS_LOG_INFO("Notifying observers of FDB entry removal on AGED/MOVED"); - for (auto observer: m_observers) - { - observer->update(SUBJECT_TYPE_FDB_CHANGE, &update); - } + notify(SUBJECT_TYPE_FDB_CHANGE, &update); break; - } case SAI_FDB_EVENT_MOVE: { @@ -489,39 +471,16 @@ void FdbOrch::update(sai_fdb_event_t type, storeFdbEntryState(update); - for (auto observer: m_observers) - { - observer->update(SUBJECT_TYPE_FDB_CHANGE, &update); - } + notify(SUBJECT_TYPE_FDB_CHANGE, &update); + break; } - case SAI_FDB_EVENT_FLUSHED: - - SWSS_LOG_INFO("FDB Flush event received: [ %s , 0x%" PRIx64 " ], \ - bridge port ID: 0x%" PRIx64 ".", - update.entry.mac.to_string().c_str(), entry->bv_id, - bridge_port_id); - - string vlanName = "-"; - if (entry->bv_id) { - Port vlan; - - if (!m_portsOrch->getPort(entry->bv_id, vlan)) - { - SWSS_LOG_ERROR("FdbOrch notification: Failed to locate vlan\ - port from bv_id 0x%" PRIx64, entry->bv_id); - return; - } - vlanName = "Vlan" + to_string(vlan.m_vlan_info.vlan_id); - } - - if (bridge_port_id == SAI_NULL_OBJECT_ID && - entry->bv_id == SAI_NULL_OBJECT_ID) + case SAI_FDB_EVENT_FLUSHED: + SWSS_LOG_INFO("Received FLUSH event for bvid=%lx mac=%s port=%lx", entry->bv_id, update.entry.mac.to_string().c_str(), bridge_port_id); + for (auto itr = m_entries.begin(); itr != m_entries.end();) { - SWSS_LOG_INFO("FDB Flush: [ %s , %s ] = { port: - }", - update.entry.mac.to_string().c_str(), vlanName.c_str()); - for (auto itr = m_entries.begin(); itr != m_entries.end();) + if (itr->second.type == "static") { itr++; continue; @@ -535,69 +494,41 @@ void FdbOrch::update(sai_fdb_event_t type, if (!m_portsOrch->getPortByBridgePortId(itr->second.bridge_port_id, update.port)) { SWSS_LOG_ERROR("FdbOrch FLUSH notification: Failed to get port by bridge port ID 0x%lx", itr->second.bridge_port_id); + itr++; + continue; } if (!m_portsOrch->getPort(itr->first.bv_id, vlan)) { SWSS_LOG_NOTICE("FdbOrch FLUSH notification: Failed to locate vlan port from bv_id 0x%lx", itr->first.bv_id); + itr++; + continue; } update.entry.mac = itr->first.mac; update.entry.bv_id = itr->first.bv_id; update.add = false; + update.vlan_id = vlan.m_vlan_info.vlan_id; itr++; + update.port.m_fdb_count--; + m_portsOrch->setPort(update.port.m_alias, update.port); + vlan.m_fdb_count--; + m_portsOrch->setPort(vlan.m_alias, vlan); + /* This will invalidate the current iterator hence itr++ is done before */ storeFdbEntryState(update); - for (auto observer: m_observers) - { - observer->update(SUBJECT_TYPE_FDB_CHANGE, &update); - } - } - } - else if (entry->bv_id == SAI_NULL_OBJECT_ID) - { - /* FLUSH based on port */ - SWSS_LOG_INFO("FDB Flush: [ %s , %s ] = { port: %s }", - update.entry.mac.to_string().c_str(), - vlanName.c_str(), update.port.m_alias.c_str()); + SWSS_LOG_DEBUG("FdbOrch FLUSH notification: mac %s was removed", update.entry.mac.to_string().c_str()); - for (auto itr = m_entries.begin(); itr != m_entries.end();) + notify(SUBJECT_TYPE_FDB_CHANGE, &update); + } + else { - auto next_item = std::next(itr); - if (itr->port_name == update.port.m_alias) - { - update.entry.mac = itr->mac; - update.entry.bv_id = itr->bv_id; - update.add = false; - - storeFdbEntryState(update); - - for (auto observer: m_observers) - { - observer->update(SUBJECT_TYPE_FDB_CHANGE, &update); - } - } - itr = next_item; + itr++; } } - else if (bridge_port_id == SAI_NULL_OBJECT_ID) - { - /* FLUSH based on VLAN - unsupported */ - SWSS_LOG_ERROR("Unsupported FDB Flush: [ %s , %s ] = { port: - }", - update.entry.mac.to_string().c_str(), - vlanName.c_str()); - - } - else - { - /* FLUSH based on port and VLAN - unsupported */ - SWSS_LOG_ERROR("Unsupported FDB Flush: [ %s , %s ] = { port: %s }", - update.entry.mac.to_string().c_str(), - vlanName.c_str(), update.port.m_alias.c_str()); - } break; } @@ -632,7 +563,6 @@ void FdbOrch::update(SubjectType type, void *cntx) bool FdbOrch::getPort(const MacAddress& mac, uint16_t vlan, Port& port) { - sai_object_id_t bridge_port_id; SWSS_LOG_ENTER(); if (!m_portsOrch->getVlanByVlanId(vlan, port)) @@ -641,7 +571,6 @@ bool FdbOrch::getPort(const MacAddress& mac, uint16_t vlan, Port& port) return false; } -#if 0 sai_fdb_entry_t entry; entry.switch_id = gSwitchId; memcpy(entry.mac_address, mac.getMac(), sizeof(sai_mac_t)); @@ -657,24 +586,10 @@ bool FdbOrch::getPort(const MacAddress& mac, uint16_t vlan, Port& port) mac.to_string().c_str(), status); return false; } - bridge_port_id = attr.value.oid; -#else - FdbEntry entry; - entry.bv_id = port.m_vlan_info.vlan_oid; - entry.mac = mac; - auto it= m_entries.find(entry); - if(it != m_entries.end()) - { - bridge_port_id = it->second.bridge_port_id; - } - else - { - return false; - } -#endif - if (!m_portsOrch->getPortByBridgePortId(bridge_port_id, port)) + + if (!m_portsOrch->getPortByBridgePortId(attr.value.oid, port)) { - SWSS_LOG_ERROR("Failed to get port by bridge port ID 0x%lx", bridge_port_id); + SWSS_LOG_ERROR("Failed to get port by bridge port ID 0x%" PRIx64, attr.value.oid); return false; } @@ -698,7 +613,6 @@ void FdbOrch::doTask(Consumer& consumer) { origin = FDB_ORIGIN_MCLAG_ADVERTIZED; } - auto it = consumer.m_toSync.begin(); while (it != consumer.m_toSync.end()) { @@ -707,16 +621,15 @@ void FdbOrch::doTask(Consumer& consumer) /* format: : */ vector keys = tokenize(kfvKey(t), ':', 1); string op = kfvOp(t); - unsigned short vlan_id; Port vlan; if (!m_portsOrch->getPort(keys[0], vlan)) { SWSS_LOG_INFO("Failed to locate %s", keys[0].c_str()); - if(op == DEL_COMMAND) { /* Delete if it is in saved_fdb_entry */ + unsigned short vlan_id; try { vlan_id = (unsigned short) stoi(keys[0].substr(4)); } catch(exception &e) { @@ -739,11 +652,11 @@ void FdbOrch::doTask(Consumer& consumer) entry.bv_id = vlan.m_vlan_info.vlan_oid; string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string(); + if (op == SET_COMMAND) { - string port = ""; - string type = "dynamic"; - string sticky = ""; + string port; + string type; for (auto i : kfvFieldsValues(t)) { @@ -756,16 +669,14 @@ void FdbOrch::doTask(Consumer& consumer) { type = fvValue(i); } - } entry.port_name = port; /* FDB type is either dynamic or static */ - - if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED) assert(type == "dynamic" || type == "dynamic_local" || type == "static" ); else - assert(type == "dynamic" || type == "static" ); + assert(type == "dynamic" || type == "static"); if (addFdbEntry(entry, port, type, origin)) { @@ -774,10 +685,6 @@ void FdbOrch::doTask(Consumer& consumer) if (type == "dynamic_local") { m_mclagFdbStateTable.del(key); - - SWSS_LOG_NOTICE("do Task Add: Delete ICCP FDB from kernel: " - "Mac: %s Vlan: %d port:%s type:%s",entry.mac.to_string().c_str(), - vlan.m_vlan_info.vlan_id, it->second.port.c_str(), it->second.type.c_str()); } } @@ -785,11 +692,19 @@ void FdbOrch::doTask(Consumer& consumer) } else it++; + + /* Remove corresponding APP_DB entry if type is 'dynamic' */ + // FIXME: The modification of table is not thread safe. + // Uncomment this after this issue is fixed. + // if (type == "dynamic") + // { + // m_table.del(kfvKey(t)); + // } } else if (op == DEL_COMMAND) { - if (removeFdbEntry(entry, origin)) - { + if (removeFdbEntry(entry)) + { if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED) { m_mclagFdbStateTable.del(key); @@ -800,7 +715,8 @@ void FdbOrch::doTask(Consumer& consumer) it = consumer.m_toSync.erase(it); } else - it++; + it++; + } else { @@ -809,14 +725,10 @@ void FdbOrch::doTask(Consumer& consumer) } } } -extern volatile bool g_record; -extern void recordLine(std::string s); -extern std::string joinFieldValues(_In_ const std::vector &values); void FdbOrch::doTask(NotificationConsumer& consumer) { SWSS_LOG_ENTER(); - sai_status_t status; if (!gPortsOrch->allPortsReady()) { @@ -827,34 +739,23 @@ void FdbOrch::doTask(NotificationConsumer& consumer) std::string data; std::vector values; + consumer.pop(op, data, values); + if (&consumer == m_flushNotificationsConsumer) { - consumer.pop(op, data, values); - if (op == "ALL") { - /* - * so far only support flush all the FDB entris - * flush per port and flush per vlan will be added later. - */ - status = sai_fdb_api->flush_fdb_entries(gSwitchId, 0, NULL); - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Flush fdb failed, return code %x", status); - } - + flushFdbAll(0); return; } else if (op == "PORT") { - /*place holder for flush port fdb*/ - SWSS_LOG_ERROR("Received unsupported flush port fdb request"); + flushFdbByPort(data, 0); return; } else if (op == "VLAN") { - /*place holder for flush vlan fdb*/ - SWSS_LOG_ERROR("Received unsupported flush vlan fdb request"); + flushFdbByVlan(data, 0); return; } else @@ -863,52 +764,30 @@ void FdbOrch::doTask(NotificationConsumer& consumer) return; } } - else if (&consumer == m_fdbNotificationConsumer) + else if (&consumer == m_fdbNotificationConsumer && op == "fdb_event") { - SWSS_LOG_NOTICE("FDBNotification: START"); - size_t batch_size=0; - while((consumer.peek()==1) && (batch_size++ <= DEFAULT_NC_POP_BATCH_SIZE)) - { - uint32_t count; - sai_fdb_event_notification_data_t *fdbevent = nullptr; - extern void handle_fdb_event(_In_ const std::string &data); - - consumer.pop(op, data, values); - if(op == "fdb_event") - { - if (g_record) - { - recordLine("n|" + op + "|" + data + "|" + joinFieldValues(values)); - } + uint32_t count; + sai_fdb_event_notification_data_t *fdbevent = nullptr; - /* The sai_redis fdb handling is moved here so that both - * reference count updates (sai_redis and portsOrch) - * happen in same context to avoid any mismatch. - */ - handle_fdb_event(data); + sai_deserialize_fdb_event_ntf(data, count, &fdbevent); - sai_deserialize_fdb_event_ntf(data, count, &fdbevent); + for (uint32_t i = 0; i < count; ++i) + { + sai_object_id_t oid = SAI_NULL_OBJECT_ID; - for (uint32_t i = 0; i < count; ++i) + for (uint32_t j = 0; j < fdbevent[i].attr_count; ++j) + { + if (fdbevent[i].attr[j].id == SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID) { - sai_object_id_t oid = SAI_NULL_OBJECT_ID; - - for (uint32_t j = 0; j < fdbevent[i].attr_count; ++j) - { - if (fdbevent[i].attr[j].id == SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID) - { - oid = fdbevent[i].attr[j].value.oid; - break; - } - } - - this->update(fdbevent[i].event_type, &fdbevent[i].fdb_entry, oid); + oid = fdbevent[i].attr[j].value.oid; + break; } - - sai_deserialize_free_fdb_event_ntf(count, fdbevent); } + + this->update(fdbevent[i].event_type, &fdbevent[i].fdb_entry, oid); } - SWSS_LOG_NOTICE("FDBNotification: Processed %lu notifications", batch_size); + + sai_deserialize_free_fdb_event_ntf(count, fdbevent); } } @@ -971,27 +850,27 @@ void FdbOrch::notifyObserversFDBFlush(Port &port, sai_object_id_t& bvid) for (auto itr = m_entries.begin(); itr != m_entries.end(); ++itr) { - if ((itr->port_name == port.m_alias) && - (itr->bv_id == bvid)) + if ((itr->second.bridge_port_id == port.m_bridge_port_id) && + (itr->first.bv_id == bvid)) { SWSS_LOG_INFO("Adding MAC learnt on [ port:%s , bvid:0x%" PRIx64 "]\ to ARP flush", port.m_alias.c_str(), bvid); FdbEntry entry; - entry.mac = itr->mac; - entry.bv_id = itr->bv_id; + entry.mac = itr->first.mac; + entry.bv_id = itr->first.bv_id; flushUpdate.entries.push_back(entry); } } +#if 0 //tbd_build if (!flushUpdate.entries.empty()) { - for (auto observer: m_observers) - { - observer->update(SUBJECT_TYPE_FDB_FLUSH_CHANGE, &flushUpdate); - } + notify(SUBJECT_TYPE_FDB_FLUSH_CHANGE, &update); } +#endif } + void FdbOrch::updatePortOperState(const PortOperStateUpdate& update) { SWSS_LOG_ENTER(); @@ -1020,33 +899,18 @@ void FdbOrch::updatePortOperState(const PortOperStateUpdate& update) void FdbOrch::updateVlanMember(const VlanMemberUpdate& update) { - Port port; - string port_name = update.member.m_alias; string vlan_name = update.vlan.m_alias; SWSS_LOG_ENTER(); - if (!m_portsOrch->getPort(port_name, port)) - { - SWSS_LOG_ERROR("could not locate port from alias %s", port_name.c_str()); - swss::Port vlan = update.vlan; - swss::Port port = update.member; - flushFDBEntries(port.m_bridge_port_id, vlan.m_vlan_info.vlan_oid); - notifyObserversFDBFlush(port, vlan.m_vlan_info.vlan_oid); - return; - } - if (!update.add) { - //tbd_to_build - //flushFdbByPortVlan(port_name, vlan_name, 1); + flushFdbByPortVlan(port_name, vlan_name, 1); return; } - auto fdb_list = std::move(saved_fdb_entries[port_name]); - saved_fdb_entries[port_name].clear(); - for (const auto& fdb: fdb_list) + if(!fdb_list.empty()) { for (const auto& fdb: fdb_list) { @@ -1073,7 +937,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const Port port; SWSS_LOG_ENTER(); - SWSS_LOG_NOTICE("mac=%s bv_id=0x%lx port_name=%s type=%s origin=%d", entry.mac.to_string().c_str(), entry.bv_id, port_name.c_str(), type.c_str(), origin); + SWSS_LOG_INFO("mac=%s bv_id=0x%lx port_name %s type %s", entry.mac.to_string().c_str(), entry.bv_id, port_name.c_str(), type.c_str()); if (!m_portsOrch->getPort(entry.bv_id, vlan)) { @@ -1084,9 +948,8 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const /* Retry until port is created */ if (!m_portsOrch->getPort(port_name, port) || (port.m_bridge_port_id == SAI_NULL_OBJECT_ID)) { - SWSS_LOG_NOTICE("Saving the fdb entry until port %s becomes active", port_name.c_str()); - saved_fdb_entries[port_name].push_back({entry.mac, - vlan.m_vlan_info.vlan_id, type, origin}); + SWSS_LOG_INFO("Saving a fdb entry until port %s becomes active origin %d", port_name.c_str(), origin); + saved_fdb_entries[port_name].push_back({entry.mac, vlan.m_vlan_info.vlan_id, type, origin}); return true; } @@ -1094,10 +957,10 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const /* Retry until port is member of vlan*/ if (vlan.m_members.find(port_name) == vlan.m_members.end()) { - SWSS_LOG_NOTICE("Saving the fdb entry until port %s becomes vlan %s member", port_name.c_str(), vlan.m_alias.c_str()); - if (type != "dynamic_local") - saved_fdb_entries[port_name].push_back({entry.mac, - vlan.m_vlan_info.vlan_id, type, origin}); + SWSS_LOG_INFO("Saving a fdb entry until port %s becomes vlan %s member", port_name.c_str(), vlan.m_alias.c_str()); + + if (type != "dynamic_local") + saved_fdb_entries[port_name].push_back({entry.mac, vlan.m_vlan_info.vlan_id, type, origin}); return true; } @@ -1128,7 +991,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const if((oldOrigin == origin) && (oldType == type) && (port.m_bridge_port_id == it->second.bridge_port_id)) { /* Duplicate Mac */ - SWSS_LOG_NOTICE("FdbOrch: mac=%s %s port=%s type=%s origin=%d is duplicate", entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str(), type.c_str(), origin); + SWSS_LOG_INFO("FdbOrch: mac=%s %s port=%s type=%s origin=%d is duplicate", entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str(), type.c_str(), origin); return true; } else if(origin != oldOrigin) @@ -1137,7 +1000,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const if((oldType == "static") && (oldOrigin == FDB_ORIGIN_PROVISIONED)) { /* old mac was static and provisioned, it can not be changed by Remote Mac */ - SWSS_LOG_NOTICE("Already existing static MAC:%s in Vlan:%d. " + SWSS_LOG_INFO("Already existing static MAC:%s in Vlan:%d. " "Received same MAC from peer " "Peer mac ignored", entry.mac.to_string().c_str(), vlan.m_vlan_info.vlan_id); @@ -1148,7 +1011,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const { if ((port.m_bridge_port_id == it->second.bridge_port_id) && (oldType == "dynamic") && (type == "dynamic_local")) { - SWSS_LOG_NOTICE("FdbOrch: mac=%s %s port=%s type=%s origin=%d old_origin=%d" + SWSS_LOG_INFO("FdbOrch: mac=%s %s port=%s type=%s origin=%d old_origin=%d" " old_type=%s local mac exists," " received dynamic_local from iccpd, ignore update", entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str(), @@ -1193,76 +1056,75 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const attr.value.oid = port.m_bridge_port_id; attrs.push_back(attr); - /* PACKET ACTION is FORWARD by default; no need to set it */ - /** attr.id = SAI_FDB_ENTRY_ATTR_PACKET_ACTION; attr.value.s32 = SAI_PACKET_ACTION_FORWARD; attrs.push_back(attr); - */ + + string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string(); if(macUpdate) { - SWSS_LOG_NOTICE("MAC-Update FDB %s in %s on from-%s:to-%s from-%s:to-%s origin-%d-to-%d", - entry.mac.to_string().c_str(), vlan.m_alias.c_str(), oldPort.m_alias.c_str(), - port_name.c_str(), oldType.c_str(), type.c_str(), oldOrigin, origin); - for(auto itr : attrs) + /* delete and re-add fdb entry instead of update, + * as entry may age out in HW/ASIC_DB before + * update, causing the update request to fail. + */ + SWSS_LOG_INFO("MAC-Update FDB %s in %s on from-%s:to-%s from-%s:to-%s", entry.mac.to_string().c_str(), vlan.m_alias.c_str(), oldPort.m_alias.c_str(), port_name.c_str(), oldType.c_str(), type.c_str()); + status = sai_fdb_api->remove_fdb_entry(&fdb_entry); + if (status != SAI_STATUS_SUCCESS) { - status = sai_fdb_api->set_fdb_entry_attribute(&fdb_entry, &itr); - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("macUpdate-Failed for attr.id=0x%x for FDB %s in %s on %s, rv:%d", - itr.id, entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str(), status); - return false; - } + SWSS_LOG_WARN("FdbOrch RemoveFDBEntry: Failed to remove FDB entry. mac=%s, bv_id=0x%lx", + entry.mac.to_string().c_str(), entry.bv_id); } - if (oldPort.m_bridge_port_id != port.m_bridge_port_id) + else { oldPort.m_fdb_count--; m_portsOrch->setPort(oldPort.m_alias, oldPort); - port.m_fdb_count++; - m_portsOrch->setPort(port.m_alias, port); + if (oldPort.m_bridge_port_id == port.m_bridge_port_id) + { + port.m_fdb_count--; + m_portsOrch->setPort(port.m_alias, port); + } + vlan.m_fdb_count--; + m_portsOrch->setPort(vlan.m_alias, vlan); + (void)m_entries.erase(entry); + // Remove in StateDb + m_fdbStateTable.del(key); + + gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); + FdbUpdate update = {entry, port, vlan.m_vlan_info.vlan_id, type, true}; + notify(SUBJECT_TYPE_FDB_CHANGE, &update); } } - else - { - SWSS_LOG_NOTICE("MAC-Create %s FDB %s in %s on %s", type.c_str(), entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str()); + SWSS_LOG_INFO("MAC-Create %s FDB %s in %s on %s", type.c_str(), entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str()); - status = sai_fdb_api->create_fdb_entry(&fdb_entry, (uint32_t)attrs.size(), attrs.data()); - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to create %s FDB %s in %s on %s, rv:%d", - type.c_str(), entry.mac.to_string().c_str(), - vlan.m_alias.c_str(), port_name.c_str(), status); - return false; //FIXME: it should be based on status. Some could be retried, some not - } - port.m_fdb_count++; - m_portsOrch->setPort(port.m_alias, port); - vlan.m_fdb_count++; - m_portsOrch->setPort(vlan.m_alias, vlan); + status = sai_fdb_api->create_fdb_entry(&fdb_entry, (uint32_t)attrs.size(), attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create %s FDB %s on %s, rv:%d", + type.c_str(), entry.mac.to_string().c_str(), + entry.port_name.c_str(), status); + return false; //FIXME: it should be based on status. Some could be retried, some not } + port.m_fdb_count++; + m_portsOrch->setPort(port.m_alias, port); + vlan.m_fdb_count++; + m_portsOrch->setPort(vlan.m_alias, vlan); - FdbData fdbData; - fdbData.bridge_port_id = port.m_bridge_port_id; - fdbData.type = type; - fdbData.origin = origin; + FdbData fdbdata = {port.m_bridge_port_id, type, origin}; // overwrite the type and origin if ((origin == FDB_ORIGIN_MCLAG_ADVERTIZED) && (type == "dynamic_local")) { //If the MAC is dynamic_local change the origin accordingly //MAC is added/updated as dynamic to allow aging. - fdbData.origin = FDB_ORIGIN_LEARN; - fdbData.type = "dynamic"; + fdbdata.origin = FDB_ORIGIN_LEARN; + fdbdata.type = "dynamic"; } SWSS_LOG_NOTICE("Storing FDB entry: [%s, 0x%" PRIx64 "] [ port: %s , type: %s]", entry.mac.to_string().c_str(), entry.bv_id, entry.port_name.c_str(), type.c_str()); - - m_entries[entry] = fdbData; - - string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string(); - - if ( (type == "dynamic_local") || (origin != FDB_ORIGIN_MCLAG_ADVERTIZED)) + m_entries[entry] = fdbdata; + if ( (type == "dynamic_local") || (origin != FDB_ORIGIN_MCLAG_ADVERTIZED)) { /* State-DB is updated only for Local Mac addresses */ // Write to StateDb @@ -1309,12 +1171,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); } - FdbUpdate update; - update.entry = entry; - update.port = port; - update.type = type; - update.add = true; - + FdbUpdate update = {entry, port, vlan.m_vlan_info.vlan_id, type, true}; // overwrite the type to dynamic. if (type == "dynamic_local") update.type = "dynamic"; @@ -1331,17 +1188,16 @@ bool FdbOrch::removeFdbEntry(const FdbEntry& entry, FdbOrigin origin) SWSS_LOG_ENTER(); - SWSS_LOG_NOTICE("FdbOrch RemoveFDBEntry: mac=%s bv_id=0x%lx origin %d", entry.mac.to_string().c_str(), entry.bv_id, origin); if (!m_portsOrch->getPort(entry.bv_id, vlan)) { - SWSS_LOG_DEBUG("FdbOrch notification: Failed to locate vlan port from bv_id 0x%lx", entry.bv_id); + SWSS_LOG_NOTICE("FdbOrch notification: Failed to locate vlan port from bv_id 0x%lx", entry.bv_id); return false; } auto it= m_entries.find(entry); if(it == m_entries.end()) { - SWSS_LOG_NOTICE("FdbOrch RemoveFDBEntry: FDB entry isn't found. mac=%s bv_id=0x%lx", entry.mac.to_string().c_str(), entry.bv_id); + SWSS_LOG_INFO("FdbOrch RemoveFDBEntry: FDB entry isn't found. mac=%s bv_id=0x%lx", entry.mac.to_string().c_str(), entry.bv_id); /* check whether the entry is in the saved fdb, if so delete it from there. */ deleteFdbEntryFromSavedFDB(entry.mac, vlan.m_vlan_info.vlan_id, origin, ""); @@ -1349,14 +1205,13 @@ bool FdbOrch::removeFdbEntry(const FdbEntry& entry, FdbOrigin origin) } FdbData fdbData = it->second; - if (!m_portsOrch->getPortByBridgePortId(fdbData.bridge_port_id, port)) { SWSS_LOG_NOTICE("FdbOrch RemoveFDBEntry: Failed to locate port from bridge_port_id 0x%lx", fdbData.bridge_port_id); return false; } - SWSS_LOG_NOTICE("FdbOrch RemoveFDBEntry: mac=%s bv_id=0x%lx existing origin %d, port oper_status: %s , is malg interface: %s", + SWSS_LOG_INFO("FdbOrch RemoveFDBEntry: mac=%s bv_id=0x%lx existing origin %d, port oper_status: %s , is malg interface: %s", entry.mac.to_string().c_str(), entry.bv_id, fdbData.origin, (port.m_oper_status == SAI_PORT_OPER_STATUS_DOWN) ? "DOWN":"UP", gMlagOrch->isMlagInterface(port.m_alias) ? "true":"false"); if(fdbData.origin != origin) @@ -1366,7 +1221,7 @@ bool FdbOrch::removeFdbEntry(const FdbEntry& entry, FdbOrigin origin) { //check if the local MCLAG port is down, if yes then continue delete the local MAC origin = FDB_ORIGIN_LEARN; - SWSS_LOG_NOTICE("FdbOrch RemoveFDBEntry: mac=%s fdb del origin is MCLAG; delete local mac as port %s is down", + SWSS_LOG_INFO("FdbOrch RemoveFDBEntry: mac=%s fdb del origin is MCLAG; delete local mac as port %s is down", entry.mac.to_string().c_str(), port.m_alias.c_str()); } else @@ -1386,7 +1241,7 @@ bool FdbOrch::removeFdbEntry(const FdbEntry& entry, FdbOrigin origin) string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string(); - sai_status_t status = SAI_STATUS_SUCCESS; + sai_status_t status; sai_fdb_entry_t fdb_entry; fdb_entry.switch_id = gSwitchId; memcpy(fdb_entry.mac_address, entry.mac.getMac(), sizeof(sai_mac_t)); @@ -1395,14 +1250,10 @@ bool FdbOrch::removeFdbEntry(const FdbEntry& entry, FdbOrigin origin) status = sai_fdb_api->remove_fdb_entry(&fdb_entry); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("Failed to remove FDB entry. mac=%s, bv_id=0x%" PRIx64, + SWSS_LOG_ERROR("FdbOrch RemoveFDBEntry: Failed to remove FDB entry. mac=%s, bv_id=0x%lx", entry.mac.to_string().c_str(), entry.bv_id); return true; //FIXME: it should be based on status. Some could be retried. some not } - - SWSS_LOG_NOTICE("Removed mac=%s bv_id=0x%lx port:%s", - entry.mac.to_string().c_str(), entry.bv_id, port.m_alias.c_str()); - port.m_fdb_count--; m_portsOrch->setPort(port.m_alias, port); vlan.m_fdb_count--; @@ -1416,27 +1267,167 @@ bool FdbOrch::removeFdbEntry(const FdbEntry& entry, FdbOrigin origin) } gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); - - SWSS_LOG_INFO("Notifying observers of FDB entry removal"); - FdbUpdate update = {entry, port, fdbData.type, false}; - for (auto observer: m_observers) + + FdbUpdate update = {entry, port, vlan.m_vlan_info.vlan_id, fdbData.type, false}; + + notify(SUBJECT_TYPE_FDB_CHANGE, &update); + + return true; +} + +bool FdbOrch::flushFdbAll(bool flush_static) +{ + sai_status_t status; + sai_attribute_t port_attr; + + if (!flush_static) + { + port_attr.id = SAI_FDB_FLUSH_ATTR_ENTRY_TYPE; + port_attr.value.s32 = SAI_FDB_FLUSH_ENTRY_TYPE_DYNAMIC; + status = sai_fdb_api->flush_fdb_entries(gSwitchId, 1, &port_attr); + } + else + { + status = sai_fdb_api->flush_fdb_entries(gSwitchId, 0, NULL); + } + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Flush fdb failed, return code %x", status); + return false; + } + return true; +} + +bool FdbOrch::flushFdbByPort(const string &alias, bool flush_static) +{ + sai_status_t status; + Port port; + sai_attribute_t port_attr[2]; + + if (!m_portsOrch->getPort(alias, port)) { - observer->update(SUBJECT_TYPE_FDB_CHANGE, &update); + SWSS_LOG_ERROR("could not locate port from alias %s", alias.c_str()); + return false; + } + + if ((port.m_bridge_port_id == SAI_NULL_OBJECT_ID) || !port.m_fdb_count) + { + /* port is not an L2 port or no macs to flush */ + return true; + } + + SWSS_LOG_NOTICE("m_bridge_port_id 0x%lx flush_static %d m_fdb_count %u", port.m_bridge_port_id, flush_static, port.m_fdb_count); + + port_attr[0].id = SAI_FDB_FLUSH_ATTR_BRIDGE_PORT_ID; + port_attr[0].value.oid = port.m_bridge_port_id; + if (!flush_static) + { + port_attr[1].id = SAI_FDB_FLUSH_ATTR_ENTRY_TYPE; + port_attr[1].value.s32 = SAI_FDB_FLUSH_ENTRY_TYPE_DYNAMIC; + status = sai_fdb_api->flush_fdb_entries(gSwitchId, 2, port_attr); + } + else + { + status = sai_fdb_api->flush_fdb_entries(gSwitchId, 1, port_attr); + } + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Flush fdb failed, return code %x", status); + return false; + } + return true; +} + +bool FdbOrch::flushFdbByVlan(const string &alias, bool flush_static) +{ + sai_status_t status; + Port vlan; + sai_attribute_t vlan_attr[2]; + + if (!m_portsOrch->getPort(alias, vlan)) + { + SWSS_LOG_ERROR("could not locate vlan from alias %s", alias.c_str()); + return false; + } + SWSS_LOG_NOTICE("vlan_oid 0x%lx flush_static %d", vlan.m_vlan_info.vlan_oid, flush_static); + + vlan_attr[0].id = SAI_FDB_FLUSH_ATTR_BV_ID; + vlan_attr[0].value.oid = vlan.m_vlan_info.vlan_oid; + if (!flush_static) + { + vlan_attr[1].id = SAI_FDB_FLUSH_ATTR_ENTRY_TYPE; + vlan_attr[1].value.s32 = SAI_FDB_FLUSH_ENTRY_TYPE_DYNAMIC; + status = sai_fdb_api->flush_fdb_entries(gSwitchId, 2, vlan_attr); + } + else + { + status = sai_fdb_api->flush_fdb_entries(gSwitchId, 1, vlan_attr); + } + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Flush fdb failed, return code %x", status); + return false; } return true; } +bool FdbOrch::flushFdbByPortVlan(const string &port_alias, const string &vlan_alias, bool flush_static) +{ + + sai_status_t status; + Port vlan; + Port port; + sai_attribute_t port_vlan_attr[3]; + + SWSS_LOG_NOTICE("port %s vlan %s", port_alias.c_str(), vlan_alias.c_str()); + + if (!m_portsOrch->getPort(port_alias, port)) + { + SWSS_LOG_ERROR("could not locate port from alias %s", port_alias.c_str()); + return false; + } + if (!m_portsOrch->getPort(vlan_alias, vlan)) + { + SWSS_LOG_NOTICE("FdbOrch notification: Failed to locate vlan %s", vlan_alias.c_str()); + return false; + } + + if ((port.m_bridge_port_id == SAI_NULL_OBJECT_ID) || !port.m_fdb_count) + { + /* port is not an L2 port or no macs to flush */ + return true; + } + + SWSS_LOG_NOTICE("vlan_oid 0x%lx m_bridge_port_id 0x%lx flush_static %d m_fdb_count %u", vlan.m_vlan_info.vlan_oid, port.m_bridge_port_id, flush_static, port.m_fdb_count); + + port_vlan_attr[0].id = SAI_FDB_FLUSH_ATTR_BV_ID; + port_vlan_attr[0].value.oid = vlan.m_vlan_info.vlan_oid; + port_vlan_attr[1].id = SAI_FDB_FLUSH_ATTR_BRIDGE_PORT_ID; + port_vlan_attr[1].value.oid = port.m_bridge_port_id; + if (!flush_static) + { + port_vlan_attr[2].id = SAI_FDB_FLUSH_ATTR_ENTRY_TYPE; + port_vlan_attr[2].value.s32 = SAI_FDB_FLUSH_ENTRY_TYPE_DYNAMIC; + status = sai_fdb_api->flush_fdb_entries(gSwitchId, 3, port_vlan_attr); + } + else + { + status = sai_fdb_api->flush_fdb_entries(gSwitchId, 2, port_vlan_attr); + } + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Flush fdb failed, return code %x", status); + return false; + } + + return true; +} void FdbOrch::deleteFdbEntryFromSavedFDB(const MacAddress &mac, const unsigned short &vlanId, FdbOrigin origin, const string portName) { bool found=false; - SavedFdbEntry entry; - entry.mac = mac; - entry.vlanId = vlanId; - entry.type = "static"; - /* Below members are unused during delete compare */ - entry.origin = origin; + SavedFdbEntry entry = {mac, vlanId, "static", origin}; for (auto& itr: saved_fdb_entries) { @@ -1449,7 +1440,7 @@ void FdbOrch::deleteFdbEntryFromSavedFDB(const MacAddress &mac, { if(iter->origin == origin) { - SWSS_LOG_NOTICE("FDB entry found in saved fdb. deleting..." + SWSS_LOG_INFO("FDB entry found in saved fdb. deleting..." "mac=%s vlan_id=0x%x origin:%d port:%s", mac.to_string().c_str(), vlanId, origin, itr.first.c_str()); @@ -1460,7 +1451,7 @@ void FdbOrch::deleteFdbEntryFromSavedFDB(const MacAddress &mac, } else { - SWSS_LOG_NOTICE("FDB entry found in saved fdb, but Origin is " + SWSS_LOG_INFO("FDB entry found in saved fdb, but Origin is " "different mac=%s vlan_id=0x%x reqOrigin:%d " "foundOrigin:%d port:%s, IGNORED", mac.to_string().c_str(), vlanId, origin, diff --git a/orchagent/fdborch.h b/orchagent/fdborch.h index 7d111fc918..7db4ac3971 100644 --- a/orchagent/fdborch.h +++ b/orchagent/fdborch.h @@ -33,16 +33,17 @@ struct FdbUpdate { FdbEntry entry; Port port; + uint16_t vlan_id; string type; bool add; }; - struct FdbData { sai_object_id_t bridge_port_id; string type; FdbOrigin origin; +}; struct FdbFlushUpdate { @@ -80,6 +81,10 @@ class FdbOrch: public Orch, public Subject, public Observer void update(sai_fdb_event_t, const sai_fdb_entry_t *, sai_object_id_t); void update(SubjectType type, void *cntx); bool getPort(const MacAddress&, uint16_t, Port&); + bool flushFdbByPortVlan(const string &, const string &, bool flush_static); + bool flushFdbByVlan(const string &, bool flush_static); + bool flushFdbByPort(const string &, bool flush_static); + bool flushFdbAll(bool flush_static); bool removeFdbEntry(const FdbEntry& entry, FdbOrigin origin=FDB_ORIGIN_PROVISIONED); void flushFDBEntries(sai_object_id_t bridge_port_oid, sai_object_id_t vlan_oid); @@ -100,11 +105,10 @@ class FdbOrch: public Orch, public Subject, public Observer void updateVlanMember(const VlanMemberUpdate&); bool addFdbEntry(const FdbEntry&, const string&, const string&, FdbOrigin origin); - void deleteFdbEntryFromSavedFDB(const MacAddress &mac, const unsigned short - &vlanId, FdbOrigin origin=FDB_ORIGIN_PROVISIONED, const string portName=""); + void deleteFdbEntryFromSavedFDB(const MacAddress &mac, const unsigned short &vlanId, + FdbOrigin origin=FDB_ORIGIN_PROVISIONED, const string portName=""); void updatePortOperState(const PortOperStateUpdate&); bool storeFdbEntryState(const FdbUpdate& update); - }; #endif /* SWSS_FDBORCH_H */ diff --git a/orchagent/observer.h b/orchagent/observer.h index 555a1256a6..12744e497f 100644 --- a/orchagent/observer.h +++ b/orchagent/observer.h @@ -2,12 +2,14 @@ #define SWSS_OBSERVER_H #include +#include using namespace std; using namespace swss; enum SubjectType { + SUBJECT_TYPE_ALL_CHANGES, SUBJECT_TYPE_NEXTHOP_CHANGE, SUBJECT_TYPE_NEIGH_CHANGE, SUBJECT_TYPE_FDB_CHANGE, @@ -16,9 +18,13 @@ enum SubjectType SUBJECT_TYPE_MIRROR_SESSION_CHANGE, SUBJECT_TYPE_INT_SESSION_CHANGE, SUBJECT_TYPE_PORT_CHANGE, - SUBJECT_TYPE_MLAG_INTF_CHANGE, SUBJECT_TYPE_BRIDGE_PORT_CHANGE, SUBJECT_TYPE_PORT_OPER_STATE_CHANGE, + SUBJECT_TYPE_ISOLATION_GROUP_CHANGE, + SUBJECT_TYPE_ISOLATION_GROUP_MEMBER_CHANGE, + SUBJECT_TYPE_ISOLATION_GROUP_BINDING_CHANGE, + SUBJECT_TYPE_MLAG_INTF_CHANGE, + SUBJECT_TYPE_MLAG_ISL_CHANGE, SUBJECT_TYPE_FDB_FLUSH_CHANGE }; @@ -32,26 +38,62 @@ class Observer class Subject { public: + virtual void attach(SubjectType type, Observer *observer) + { + m_observers.emplace_back(type, observer); + } + virtual void attach(Observer *observer) { - m_observers.push_back(observer); + attach(SUBJECT_TYPE_ALL_CHANGES, observer); + } + + virtual void detach(SubjectType type, Observer *observer) + { + pair temp(type, observer); + + auto it = find(m_observers.begin(), m_observers.end(), temp); + if (it != m_observers.end()) + { + m_observers.erase(it); + } } virtual void detach(Observer *observer) { - m_observers.remove(observer); + detach(SUBJECT_TYPE_ALL_CHANGES, observer); + } + + virtual bool isObserver(SubjectType type, Observer *observer) + { + pair temp(type, observer); + + return m_observers.end() != find(m_observers.begin(), m_observers.end(), temp); + } + + virtual bool isObserver(Observer *observer) + { + return isObserver(SUBJECT_TYPE_ALL_CHANGES, observer); + } + + virtual bool hasObservers() + { + return m_observers.size() > 0; } virtual ~Subject() {} protected: - list m_observers; + list> m_observers; virtual void notify(SubjectType type, void *cntx) { - for (auto iter: m_observers) + for (auto &iter: m_observers) { - iter->update(type, cntx); + if ((iter.first == SUBJECT_TYPE_ALL_CHANGES) || (iter.first == type)) + { + iter.second->update(type, cntx); + } } } }; diff --git a/orchagent/port.h b/orchagent/port.h index 7f75e5db92..d18681aec6 100644 --- a/orchagent/port.h +++ b/orchagent/port.h @@ -97,8 +97,8 @@ class Port sai_object_id_t m_tunnel_id = 0; sai_object_id_t m_ingress_acl_table_group_id = 0; sai_object_id_t m_egress_acl_table_group_id = 0; - vlan_members_t m_vlan_members; sai_object_id_t m_parent_port_id = 0; + vlan_members_t m_vlan_members; uint32_t m_dependency_bitmap = 0; sai_port_oper_status_t m_oper_status = SAI_PORT_OPER_STATUS_UNKNOWN; std::set m_members; diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 3416f1d378..1c634d1eb8 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -28,6 +28,7 @@ #include "countercheckorch.h" #include "notifier.h" #include "fdborch.h" +#include "redisclient.h" extern sai_switch_api_t *sai_switch_api; extern sai_bridge_api_t *sai_bridge_api; @@ -206,15 +207,15 @@ PortsOrch::PortsOrch(DBConnector *db, vector &tableNames) /* Initialize counter table */ m_counter_db = shared_ptr(new DBConnector("COUNTERS_DB", 0)); m_counterTable = unique_ptr(new Table(m_counter_db.get(), COUNTERS_PORT_NAME_MAP)); - m_counterLagTable = unique_ptr
(new Table(m_counter_db.get(), COUNTERS_LAG_NAME_MAP)); FieldValueTuple tuple("", ""); vector defaultLagFv; defaultLagFv.push_back(tuple); m_counterLagTable->set("", defaultLagFv); - /* Initialize port table */ + /* Initialize port and vlan table */ m_portTable = unique_ptr
(new Table(db, APP_PORT_TABLE_NAME)); + m_vlanTable = unique_ptr
(new Table(db, APP_VLAN_TABLE_NAME)); /* Initialize gearbox */ m_gearboxTable = unique_ptr
(new Table(db, "_GEARBOX_TABLE")); @@ -234,6 +235,7 @@ PortsOrch::PortsOrch(DBConnector *db, vector &tableNames) 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)); + notifications = new swss::NotificationProducer(db, "VLANSTATE"); initGearbox(); string queueWmSha, pgWmSha; @@ -369,7 +371,19 @@ PortsOrch::PortsOrch(DBConnector *db, vector &tableNames) } m_default1QBridge = attrs[0].value.oid; - m_defaultVlan = attrs[1].value.oid; + m_defaultVlan_ObjId = attrs[1].value.oid; + + memset(&attr, 0x00, sizeof(attr)); + attr.id = SAI_VLAN_ATTR_VLAN_ID; + + status = sai_vlan_api->get_vlan_attribute(m_defaultVlan_ObjId, 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to get default VLAN ID, rv:%d", status); + throw runtime_error("PortsOrch initialization failure"); + } + + m_defaultVlan_Id = attr.value.u16; removeDefaultVlanMembers(); removeDefaultBridgePorts(); @@ -391,7 +405,7 @@ void PortsOrch::removeDefaultVlanMembers() attr.value.objlist.count = (uint32_t)vlan_member_list.size(); attr.value.objlist.list = vlan_member_list.data(); - sai_status_t status = sai_vlan_api->get_vlan_attribute(m_defaultVlan, 1, &attr); + sai_status_t status = sai_vlan_api->get_vlan_attribute(m_defaultVlan_ObjId, 1, &attr); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to get VLAN member list in default VLAN, rv:%d", status); @@ -550,34 +564,12 @@ bool PortsOrch::getPort(sai_object_id_t id, Port &port) { SWSS_LOG_ENTER(); - for (const auto& portIter: m_portList) - { - switch (portIter.second.m_type) - { - case Port::PHY: - if(portIter.second.m_port_id == id) - { - port = portIter.second; - return true; - } - break; - case Port::LAG: - if(portIter.second.m_lag_id == id) - { - port = portIter.second; - return true; - } - break; - case Port::VLAN: - if (portIter.second.m_vlan_info.vlan_oid == id) - { - port = portIter.second; - return true; - } - break; - default: - continue; - } + auto itr = portOidToName.find(id); + if (itr == portOidToName.end()) + return false; + else { + getPort(itr->second, port); + return true; } return false; @@ -599,13 +591,12 @@ bool PortsOrch::getPortByBridgePortId(sai_object_id_t bridge_port_id, Port &port { SWSS_LOG_ENTER(); - for (auto &it: m_portList) - { - if (it.second.m_bridge_port_id == bridge_port_id) - { - port = it.second; - return true; - } + auto itr = portOidToName.find(bridge_port_id); + if (itr == portOidToName.end()) + return false; + else { + getPort(itr->second, port); + return true; } return false; @@ -1744,6 +1735,21 @@ void PortsOrch::updateDbPortOperStatus(const Port& port, sai_port_oper_status_t m_portTable->set(port.m_alias, tuples); } +void PortsOrch::updateDbVlanOperStatus(const Port& vlan, string status) const +{ + SWSS_LOG_NOTICE("vlan %s status %s", vlan.m_alias.c_str(), status.c_str()); + + vector tuples; + FieldValueTuple tuple("oper_status", status); + tuples.push_back(tuple); + + std::vector entry; + + SWSS_LOG_NOTICE("sending oper state notification to VlanMgr"); + + notifications->send(status, vlan.m_alias, entry); +} + bool PortsOrch::addPort(const set &lane_set, uint32_t speed, int an, string fec_mode) { SWSS_LOG_ENTER(); @@ -1847,6 +1853,7 @@ bool PortsOrch::initPort(const string &alias, const int index, const set &l /* Add port to port list */ m_portList[alias] = p; + portOidToName[id] = alias; m_port_ref_count[alias] = 0; m_portOidToIndex[id] = index; @@ -2792,24 +2799,23 @@ void PortsOrch::doVlanMemberTask(Consumer &consumer) } else if (op == DEL_COMMAND) { + int ret = true; if (vlan.m_members.find(port_alias) != vlan.m_members.end()) { - if (removeVlanMember(vlan, port)) - { - if (port.m_vlan_members.empty()) - { - removeBridgePort(port); - } - it = consumer.m_toSync.erase(it); - } - else - { - it++; - } + ret = removeVlanMember(vlan, port); } - else - /* Cannot locate the VLAN */ + if ((ret) && m_portVlanMember[port.m_alias].empty()) + { + ret = removeBridgePort(port); + } + if (ret) + { it = consumer.m_toSync.erase(it); + } + else + { + it++; + } } else { @@ -2835,8 +2841,11 @@ void PortsOrch::doLagTask(Consumer &consumer) { // Retrieve attributes uint32_t mtu = 0; + + string oper_status; string learn_mode; string operation_status; + bool operation_status_changed = false; for (auto i : kfvFieldsValues(t)) { @@ -2857,19 +2866,22 @@ void PortsOrch::doLagTask(Consumer &consumer) it++; continue; } - } - } - // Create a new LAG when the new alias comes - if (m_portList.find(alias) == m_portList.end()) - { - if (!addLag(alias)) - { - it++; - continue; + gNeighOrch->ifChangeInformNextHop(alias, + (operation_status == "up")); + Port lag; + if (getPort(alias, lag)) + { + operation_status_changed = + (string_oper_status.at(operation_status) != + lag.m_oper_status); + } + oper_status = fvValue(i); } } + auto status = addLag(alias); + // Process attributes Port l; if (!getPort(alias, l)) @@ -2885,7 +2897,14 @@ void PortsOrch::doLagTask(Consumer &consumer) m_portList[alias] = l; } - if (mtu != 0) + if (operation_status_changed) + { + PortOperStateUpdate update; + update.port = l; + update.operStatus = string_oper_status.at(operation_status); + notify(SUBJECT_TYPE_PORT_OPER_STATE_CHANGE, static_cast(&update)); + } + if ((mtu != 0) && (mtu != l.m_mtu)) { l.m_mtu = mtu; m_portList[alias] = l; @@ -2897,6 +2916,16 @@ void PortsOrch::doLagTask(Consumer &consumer) updateChildPortsMtu(l, mtu); } + if (!oper_status.empty()) + { + if (oper_status != "up") + gFdbOrch->flushFdbByPort(alias, 0); + + /* Trigger status updated only if it is set */ + sai_port_oper_status_t status = (oper_status == "up") ? SAI_PORT_OPER_STATUS_UP : SAI_PORT_OPER_STATUS_DOWN; + updateLagOperStatus(l, status); + } + if (!learn_mode.empty() && (l.m_learn_mode != learn_mode)) { if (l.m_bridge_port_id != SAI_NULL_OBJECT_ID) @@ -2923,8 +2952,15 @@ void PortsOrch::doLagTask(Consumer &consumer) } } } - - it = consumer.m_toSync.erase(it); + if (!status) + { + it++; + continue; + } + else + { + it = consumer.m_toSync.erase(it); + } } else if (op == DEL_COMMAND) { @@ -3347,8 +3383,40 @@ bool PortsOrch::addBridgePort(Port &port) { SWSS_LOG_ENTER(); + if (port.m_rif_id) + { + SWSS_LOG_ERROR("Adding router interface %s as bridge port is not allowed", port.m_alias.c_str()); + return false; + } if (port.m_bridge_port_id != SAI_NULL_OBJECT_ID) { + /* If the port is being added to the first VLAN, + * set bridge port admin status to UP. + * This can happen if the port was just removed from + * last VLAN and fdb flush is still in progress. + */ + if (m_portVlanMember[port.m_alias].empty()) + { + sai_attribute_t attr; + attr.id = SAI_BRIDGE_PORT_ATTR_ADMIN_STATE; + attr.value.booldata = true; + + sai_status_t status = sai_bridge_api->set_bridge_port_attribute(port.m_bridge_port_id, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set bridge port %s admin status to UP, rv:%d", + port.m_alias.c_str(), status); + return false; + } + port.m_bridge_port_admin_state = true; + m_portList[port.m_alias] = port; + if (!setHostIntfsStripTag(port, SAI_HOSTIF_VLAN_TAG_KEEP)) + { + SWSS_LOG_ERROR("Failed to set %s for hostif of port %s", + hostif_vlan_tag[SAI_HOSTIF_VLAN_TAG_KEEP], port.m_alias.c_str()); + return false; + } + } return true; } @@ -3421,6 +3489,13 @@ bool PortsOrch::addBridgePort(Port &port) port.m_alias.c_str(), status); return false; } + if (!setPortPvid(port, 0)) + { + SWSS_LOG_ERROR("Failed to set pvid for port %s, rv:%d", + port.m_alias.c_str(), status); + return false; + } + port.m_bridge_port_admin_state = true; if (!setHostIntfsStripTag(port, SAI_HOSTIF_VLAN_TAG_KEEP)) { @@ -3429,11 +3504,13 @@ bool PortsOrch::addBridgePort(Port &port) return false; } m_portList[port.m_alias] = port; + portOidToName[port.m_bridge_port_id] = port.m_alias; SWSS_LOG_NOTICE("Add bridge port %s to default 1Q bridge", port.m_alias.c_str()); return true; } + bool PortsOrch::removeBridgePort(Port &port) { SWSS_LOG_ENTER(); @@ -3442,38 +3519,45 @@ bool PortsOrch::removeBridgePort(Port &port) { return true; } - /* Set bridge port admin status to DOWN */ - sai_attribute_t attr; - attr.id = SAI_BRIDGE_PORT_ATTR_ADMIN_STATE; - attr.value.booldata = false; - - sai_status_t status = sai_bridge_api->set_bridge_port_attribute(port.m_bridge_port_id, &attr); - if (status != SAI_STATUS_SUCCESS) + if (port.m_bridge_port_admin_state) { - SWSS_LOG_ERROR("Failed to set bridge port %s admin status to DOWN, rv:%d", - port.m_alias.c_str(), status); - return false; + /* Set bridge port admin status to DOWN */ + sai_attribute_t attr; + attr.id = SAI_BRIDGE_PORT_ATTR_ADMIN_STATE; + attr.value.booldata = false; + + sai_status_t status = sai_bridge_api->set_bridge_port_attribute(port.m_bridge_port_id, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set bridge port %s admin status to DOWN, rv:%d", + port.m_alias.c_str(), status); + return false; + } + port.m_bridge_port_admin_state = false; + m_portList[port.m_alias] = port; + + if (!setHostIntfsStripTag(port, SAI_HOSTIF_VLAN_TAG_STRIP)) + { + SWSS_LOG_ERROR("Failed to set %s for hostif of port %s", + hostif_vlan_tag[SAI_HOSTIF_VLAN_TAG_STRIP], port.m_alias.c_str()); + return false; + } } - if (!setHostIntfsStripTag(port, SAI_HOSTIF_VLAN_TAG_STRIP)) - { - SWSS_LOG_ERROR("Failed to set %s for hostif of port %s", - hostif_vlan_tag[SAI_HOSTIF_VLAN_TAG_STRIP], port.m_alias.c_str()); + if (port.m_fdb_count != 0) { + //SWSS_LOG_NOTICE("Port still has fdb entries, will not remove bridge port for %s", port.m_alias.c_str()); return false; } - //Flush the FDB entires corresponding to the port - gFdbOrch->flushFDBEntries(port.m_bridge_port_id, SAI_NULL_OBJECT_ID); - SWSS_LOG_INFO("Flush FDB entries for port %s", port.m_alias.c_str()); - /* Remove bridge port */ - status = sai_bridge_api->remove_bridge_port(port.m_bridge_port_id); + sai_status_t status = sai_bridge_api->remove_bridge_port(port.m_bridge_port_id); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to remove bridge port %s from default 1Q bridge, rv:%d", port.m_alias.c_str(), status); return false; } + portOidToName.erase(port.m_bridge_port_id); port.m_bridge_port_id = SAI_NULL_OBJECT_ID; SWSS_LOG_NOTICE("Remove bridge port %s from default 1Q bridge", port.m_alias.c_str()); @@ -3526,7 +3610,17 @@ bool PortsOrch::addVlan(string vlan_alias) sai_attribute_t attr; attr.id = SAI_VLAN_ATTR_VLAN_ID; attr.value.u16 = vlan_id; - sai_status_t status = sai_vlan_api->create_vlan(&vlan_oid, gSwitchId, 1, &attr); + sai_status_t status = SAI_STATUS_SUCCESS; + + /* Do not create default VLAN. It is already created by default */ + if (vlan_id != m_defaultVlan_Id) + { + status = sai_vlan_api->create_vlan(&vlan_oid, gSwitchId, 1, &attr); + } + else + { + vlan_oid = m_defaultVlan_ObjId; /* use the default VLAN object id instead */ + } if (status != SAI_STATUS_SUCCESS) { @@ -3541,6 +3635,7 @@ bool PortsOrch::addVlan(string vlan_alias) vlan.m_vlan_info.vlan_id = vlan_id; vlan.m_members = set(); m_portList[vlan_alias] = vlan; + portOidToName[vlan_oid] = vlan_alias; m_port_ref_count[vlan_alias] = 0; return true; @@ -3549,6 +3644,7 @@ bool PortsOrch::addVlan(string vlan_alias) bool PortsOrch::removeVlan(Port vlan) { SWSS_LOG_ENTER(); + if (m_port_ref_count[vlan.m_alias] > 0) { SWSS_LOG_ERROR("Failed to remove ref count %d VLAN %s", @@ -3556,6 +3652,12 @@ bool PortsOrch::removeVlan(Port vlan) vlan.m_alias.c_str()); return false; } + /* If there are still fdb entries associated with the VLAN, + return false for retry */ + if (vlan.m_fdb_count > 0) + { + return false; + } /* Vlan removing is not allowed when the VLAN still has members */ if (vlan.m_members.size() > 0) @@ -3574,10 +3676,16 @@ bool PortsOrch::removeVlan(Port vlan) sai_status_t status = sai_vlan_api->remove_vlan(vlan.m_vlan_info.vlan_oid); if (status != SAI_STATUS_SUCCESS) + /* Do not delete default VLAN from driver, but clear internal state */ + if (vlan.m_vlan_info.vlan_id != m_defaultVlan_Id) { + sai_status_t status = sai_vlan_api->remove_vlan(vlan.m_vlan_info.vlan_oid); + if (status != SAI_STATUS_SUCCESS) + { SWSS_LOG_ERROR("Failed to remove VLAN %s vid:%hu", vlan.m_alias.c_str(), vlan.m_vlan_info.vlan_id); return false; + } } removeAclTableGroup(vlan); @@ -3585,6 +3693,7 @@ bool PortsOrch::removeVlan(Port vlan) SWSS_LOG_NOTICE("Remove VLAN %s vid:%hu", vlan.m_alias.c_str(), vlan.m_vlan_info.vlan_id); + portOidToName.erase(vlan.m_vlan_info.vlan_oid); m_portList.erase(vlan.m_alias); m_port_ref_count.erase(vlan.m_alias); @@ -3656,9 +3765,18 @@ bool PortsOrch::addVlanMember(Port &vlan, Port &port, string &tagging_mode) /* a physical port may join multiple vlans */ VlanMemberEntry vme = {vlan.m_alias, vlan_member_id, sai_tagging_mode}; - port.m_vlan_members[vlan.m_vlan_info.vlan_id] = vme; + m_portVlanMember[port.m_alias][vlan.m_vlan_info.vlan_id] = vme; m_portList[port.m_alias] = port; vlan.m_members.insert(port.m_alias); + if (port.m_oper_status == SAI_PORT_OPER_STATUS_UP) + { + auto old_count = vlan.m_up_member_count; + vlan.m_up_member_count++; + if (old_count == 0) + { + updateDbVlanOperStatus(vlan, "up"); + } + } m_portList[vlan.m_alias] = vlan; VlanMemberUpdate update = { vlan, port, true }; @@ -3673,10 +3791,10 @@ bool PortsOrch::removeVlanMember(Port &vlan, Port &port) sai_object_id_t vlan_member_id; sai_vlan_tagging_mode_t sai_tagging_mode; - auto vlan_member = port.m_vlan_members.find(vlan.m_vlan_info.vlan_id); + auto vlan_member = m_portVlanMember[port.m_alias].find(vlan.m_vlan_info.vlan_id); /* Assert the port belongs to this VLAN */ - assert (vlan_member != port.m_vlan_members.end()); + assert (vlan_member != m_portVlanMember[port.m_alias].end()); sai_tagging_mode = vlan_member->second.vlan_mode; vlan_member_id = vlan_member->second.vlan_member_id; @@ -3687,14 +3805,16 @@ bool PortsOrch::removeVlanMember(Port &vlan, Port &port) port.m_alias.c_str(), vlan.m_alias.c_str(), vlan.m_vlan_info.vlan_id, vlan_member_id); return false; } - port.m_vlan_members.erase(vlan_member); + m_portVlanMember[port.m_alias].erase(vlan_member); + if (m_portVlanMember[port.m_alias].empty()) + m_portVlanMember.erase(port.m_alias); SWSS_LOG_NOTICE("Remove member %s from VLAN %s lid:%hx vmid:%" PRIx64, port.m_alias.c_str(), vlan.m_alias.c_str(), vlan.m_vlan_info.vlan_id, vlan_member_id); /* Restore to default pvid if this port joined this VLAN in untagged mode previously */ if (sai_tagging_mode == SAI_VLAN_TAGGING_MODE_UNTAGGED) { - if (!setPortPvid(port, DEFAULT_PORT_VLAN_ID)) + if (!setPortPvid(port, 0)) { return false; } @@ -3702,6 +3822,14 @@ bool PortsOrch::removeVlanMember(Port &vlan, Port &port) m_portList[port.m_alias] = port; vlan.m_members.erase(port.m_alias); + if (port.m_oper_status == SAI_PORT_OPER_STATUS_UP) + { + vlan.m_up_member_count--; + if (vlan.m_up_member_count == 0) + { + updateDbVlanOperStatus(vlan, "down"); + } + } m_portList[vlan.m_alias] = vlan; VlanMemberUpdate update = { vlan, port, false }; @@ -3722,6 +3850,17 @@ bool PortsOrch::addLag(string lag_alias) { SWSS_LOG_ENTER(); + auto lagport = m_portList.find(lag_alias); + if (lagport != m_portList.end()) + { + if ((m_portList[lag_alias].m_bridge_port_id != SAI_NULL_OBJECT_ID) && + (m_portVlanMember[lag_alias].empty())) + { + return false; + } + return true; + } + sai_object_id_t lag_id; sai_status_t status = sai_lag_api->create_lag(&lag_id, gSwitchId, 0, NULL); @@ -3737,16 +3876,18 @@ bool PortsOrch::addLag(string lag_alias) lag.m_lag_id = lag_id; lag.m_members = set(); m_portList[lag_alias] = lag; + portOidToName[lag_id] = lag_alias; m_port_ref_count[lag_alias] = 0; - PortUpdate update = { lag, true }; - notify(SUBJECT_TYPE_PORT_CHANGE, static_cast(&update)); - + /* Add lag name map to counter table */ FieldValueTuple tuple(lag_alias, sai_serialize_object_id(lag_id)); vector fields; fields.push_back(tuple); m_counterLagTable->set("", fields); + PortUpdate update = { lag, true }; + notify(SUBJECT_TYPE_PORT_CHANGE, static_cast(&update)); + return true; } @@ -3768,11 +3909,15 @@ bool PortsOrch::removeLag(Port lag) SWSS_LOG_ERROR("Failed to remove non-empty LAG %s", lag.m_alias.c_str()); return false; } - if (lag.m_vlan_members.size() > 0) + if (m_portVlanMember[lag.m_alias].size() > 0) { SWSS_LOG_ERROR("Failed to remove LAG %s, it is still in VLAN", lag.m_alias.c_str()); return false; } + if (lag.m_bridge_port_id != SAI_NULL_OBJECT_ID) + { + return false; + } sai_status_t status = sai_lag_api->remove_lag(lag.m_lag_id); if (status != SAI_STATUS_SUCCESS) @@ -3781,8 +3926,10 @@ bool PortsOrch::removeLag(Port lag) return false; } + SWSS_LOG_NOTICE("Remove LAG %s lid:%" PRIx64, lag.m_alias.c_str(), lag.m_lag_id); + portOidToName.erase(lag.m_lag_id); m_portList.erase(lag.m_alias); m_port_ref_count.erase(lag.m_alias); @@ -4210,7 +4357,26 @@ void PortsOrch::updatePortOperStatus(Port &port, sai_port_oper_status_t status) } bool isUp = status == SAI_PORT_OPER_STATUS_UP; - if (port.m_type == Port::PHY) + + for(auto vlan_member: m_portVlanMember[port.m_alias]) + { + auto Vlan = m_portList[vlan_member.second.alias]; + auto old_count = Vlan.m_up_member_count; + isUp ? Vlan.m_up_member_count++ : Vlan.m_up_member_count--; + if (Vlan.m_up_member_count == 0) + { + updateDbVlanOperStatus(Vlan, "down"); + } + else if ((old_count == 0) && (Vlan.m_up_member_count == 1)) + { + updateDbVlanOperStatus(Vlan, "up"); + } + SWSS_LOG_NOTICE("Vlan %s Port %s state %s m_up_member_count %d", + vlan_member.second.alias.c_str(), port.m_alias.c_str(), oper_status_strings.at(port.m_oper_status).c_str(), Vlan.m_up_member_count); + + m_portList[Vlan.m_alias] = Vlan; + } + if (!setHostIntfsOperStatus(port, isUp)) { if (!setHostIntfsOperStatus(port, isUp)) { @@ -4222,6 +4388,7 @@ void PortsOrch::updatePortOperStatus(Port &port, sai_port_oper_status_t status) { SWSS_LOG_WARN("Inform nexthop operation failed for interface %s", port.m_alias.c_str()); } + for (const auto &child_port : port.m_child_ports) { if (!gNeighOrch->ifChangeInformNextHop(child_port, isUp)) @@ -4229,6 +4396,46 @@ void PortsOrch::updatePortOperStatus(Port &port, sai_port_oper_status_t status) SWSS_LOG_WARN("Inform nexthop operation failed for sub interface %s", child_port.c_str()); } } + /* flush all dynamic FDB on this port */ + if (status == SAI_PORT_OPER_STATUS_DOWN) + { + gFdbOrch->flushFdbByPort(port.m_alias, 0); + } +} + +void PortsOrch::updateLagOperStatus(Port &port, sai_port_oper_status_t status) +{ + if (status == port.m_oper_status) + { + return ; + } + SWSS_LOG_NOTICE("Port %s oper state set from %s to %s", + port.m_alias.c_str(), oper_status_strings.at(port.m_oper_status).c_str(), + oper_status_strings.at(status).c_str()); + + port.m_oper_status = status; + m_portList[port.m_alias] = port; + + bool isUp = status == SAI_PORT_OPER_STATUS_UP; + + for(auto vlan_member: m_portVlanMember[port.m_alias]) + { + auto Vlan = m_portList[vlan_member.second.alias]; + auto old_count = Vlan.m_up_member_count; + isUp ? Vlan.m_up_member_count++ : Vlan.m_up_member_count--; + if (Vlan.m_up_member_count == 0) + { + updateDbVlanOperStatus(Vlan, "down"); + } + else if ((old_count == 0) && (Vlan.m_up_member_count == 1)) + { + updateDbVlanOperStatus(Vlan, "up"); + } + SWSS_LOG_NOTICE("Vlan %s Port %s state %s m_up_member_count %d", + vlan_member.second.alias.c_str(), port.m_alias.c_str(), oper_status_strings.at(port.m_oper_status).c_str(), Vlan.m_up_member_count); + + m_portList[Vlan.m_alias] = Vlan; + } PortOperStateUpdate update = {port, status}; notify(SUBJECT_TYPE_PORT_OPER_STATE_CHANGE, static_cast(&update)); @@ -4437,7 +4644,7 @@ bool PortsOrch::initGearboxPort(Port &port) { if (m_gearboxInterfaceMap.find(port.m_index) != m_gearboxInterfaceMap.end()) { - SWSS_LOG_NOTICE("BOX: port_id:0x%" PRIx64 " index:%d alias:%s", port.m_port_id, port.m_index, port.m_alias.c_str()); + SWSS_LOG_NOTICE("BOX: port_id:0x%lx index:%d alias:%s", port.m_port_id, port.m_index, port.m_alias.c_str()); phy_id = m_gearboxInterfaceMap[port.m_index].phy_id; phyOidStr = m_gearboxPhyMap[phy_id].phy_oid; @@ -4494,11 +4701,11 @@ bool PortsOrch::initGearboxPort(Port &port) status = sai_port_api->create_port(&systemPort, phyOid, static_cast(attrs.size()), attrs.data()); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("BOX: Failed to create Gearbox system-side port for alias:%s port_id:0x%" PRIx64 " index:%d status:%d", + SWSS_LOG_ERROR("BOX: Failed to create Gearbox system-side port for alias:%s port_id:0x%lx index:%d status:%d", port.m_alias.c_str(), port.m_port_id, port.m_index, status); return false; } - SWSS_LOG_NOTICE("BOX: Created Gearbox system-side port 0x%" PRIx64 " for alias:%s index:%d", + SWSS_LOG_NOTICE("BOX: Created Gearbox system-side port 0x%lx for alias:%s index:%d", systemPort, port.m_alias.c_str(), port.m_index); /* Create LINE-SIDE port */ @@ -4577,11 +4784,11 @@ bool PortsOrch::initGearboxPort(Port &port) status = sai_port_api->create_port(&linePort, phyOid, static_cast(attrs.size()), attrs.data()); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("BOX: Failed to create Gearbox line-side port for alias:%s port_id:0x%" PRIx64 " index:%d status:%d", + SWSS_LOG_ERROR("BOX: Failed to create Gearbox line-side port for alias:%s port_id:0x%lx index:%d status:%d", port.m_alias.c_str(), port.m_port_id, port.m_index, status); return false; } - SWSS_LOG_NOTICE("BOX: Created Gearbox line-side port 0x%" PRIx64 " for alias:%s index:%d", + SWSS_LOG_NOTICE("BOX: Created Gearbox line-side port 0x%lx for alias:%s index:%d", linePort, port.m_alias.c_str(), port.m_index); /* Connect SYSTEM-SIDE to LINE-SIDE */ @@ -4597,14 +4804,13 @@ bool PortsOrch::initGearboxPort(Port &port) status = sai_port_api->create_port_connector(&connector, phyOid, static_cast(attrs.size()), attrs.data()); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("BOX: Failed to connect Gearbox system-side:0x%" PRIx64 " to line-side:0x%" PRIx64 "; status:%d", systemPort, linePort, status); + SWSS_LOG_ERROR("BOX: Failed to connect Gearbox system-side:0x%lx to line-side:0x%lx; status:%d", systemPort, linePort, status); return false; } - SWSS_LOG_NOTICE("BOX: Connected Gearbox ports; system-side:0x%" PRIx64 " to line-side:0x%" PRIx64, systemPort, linePort); + SWSS_LOG_NOTICE("BOX: Connected Gearbox ports; system-side:0x%lx to line-side:0x%lx", systemPort, linePort); m_gearboxPortListLaneMap[port.m_port_id] = make_tuple(systemPort, linePort); } } return true; } - diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index 35e3af2627..2520307b72 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -9,6 +9,7 @@ #include "observer.h" #include "macaddress.h" #include "producertable.h" +#include "notificationproducer.h" #include "flex_counter_manager.h" #include "gearboxutils.h" #include "saihelper.h" @@ -91,11 +92,14 @@ class PortsOrch : public Orch, public Subject void decreasePortRefCount(const string &alias); bool getPortByBridgePortId(sai_object_id_t bridge_port_id, Port &port); void setPort(string alias, Port port); + void erasePort(string alias); void getCpuPort(Port &port); bool getVlanByVlanId(sai_vlan_id_t vlan_id, Port &vlan); bool setHostIntfsOperStatus(const Port& port, bool up) const; void updateDbPortOperStatus(const Port& port, sai_port_oper_status_t status) const; + void updateDbVlanOperStatus(const Port& port, string status) const; + bool createBindAclTableGroup(sai_object_id_t port_oid, sai_object_id_t acl_table_oid, sai_object_id_t &group_oid, @@ -113,7 +117,7 @@ class PortsOrch : public Orch, public Subject acl_stage_type_t acl_stage); bool bindUnbindAclTableGroup(Port &port, bool ingress, - bool bind); + bool bind); bool getPortPfc(sai_object_id_t portId, uint8_t *pfc_bitmask); bool setPortPfc(sai_object_id_t portId, uint8_t pfc_bitmask); @@ -141,6 +145,7 @@ class PortsOrch : public Orch, public Subject unique_ptr
m_counterTable; unique_ptr
m_counterLagTable; unique_ptr
m_portTable; + unique_ptr
m_vlanTable; unique_ptr
m_gearboxTable; unique_ptr
m_queueTable; unique_ptr
m_queuePortTable; @@ -151,6 +156,7 @@ class PortsOrch : public Orch, public Subject unique_ptr
m_pgIndexTable; unique_ptr m_flexCounterTable; unique_ptr m_flexCounterGroupTable; + NotificationProducer* notifications; std::string getQueueWatermarkFlexCounterTableKey(std::string s); std::string getPriorityGroupWatermarkFlexCounterTableKey(std::string s); @@ -169,7 +175,8 @@ class PortsOrch : public Orch, public Subject Port m_cpuPort; // TODO: Add Bridge/Vlan class sai_object_id_t m_default1QBridge; - sai_object_id_t m_defaultVlan; + sai_object_id_t m_defaultVlan_ObjId; + sai_vlan_id_t m_defaultVlan_Id; typedef enum { @@ -197,6 +204,15 @@ class PortsOrch : public Orch, public Subject map, sai_object_id_t> m_portListLaneMap; map, tuple> m_lanesAliasSpeedMap; map m_portList; + map m_portVlanMember; + + /* mapping from SAI object ID to Name for faster + retrieval of Port/VLAN from object ID for events + + coming from SAI + */ + unordered_map portOidToName; + unordered_map m_portOidToIndex; map m_port_ref_count; unordered_set m_pendingPortSet; @@ -279,6 +295,7 @@ class PortsOrch : public Orch, public Subject bool setPortSerdesAttribute(sai_object_id_t port_id, sai_attr_id_t attr_id, vector &serdes_val); + void updateLagOperStatus(Port &port, sai_port_oper_status_t status); bool getSaiAclBindPointType(Port::Type type, sai_acl_bind_point_type_t &sai_acl_bind_type); void initGearbox(); diff --git a/tests/mock_tests/aclorch_ut.cpp b/tests/mock_tests/aclorch_ut.cpp index 72f11dbb23..4ba22df0a2 100644 --- a/tests/mock_tests/aclorch_ut.cpp +++ b/tests/mock_tests/aclorch_ut.cpp @@ -313,11 +313,17 @@ namespace aclorch_test ASSERT_EQ(gIntfsOrch, nullptr); gIntfsOrch = new IntfsOrch(m_app_db.get(), APP_INTF_TABLE_NAME, gVrfOrch); - TableConnector applDbFdb(m_app_db.get(), APP_FDB_TABLE_NAME); - TableConnector stateDbFdb(m_state_db.get(), STATE_FDB_TABLE_NAME); + const int fdborch_pri = 20; + + vector app_fdb_tables = { + { APP_FDB_TABLE_NAME, fdborch_pri}, + { APP_MCLAG_FDB_TABLE_NAME, fdborch_pri} + }; + TableConnector stateDbFdb(m_state_db.get(), STATE_FDB_TABLE_NAME); + TableConnector stateMclagDbFdb(m_state_db.get(), STATE_MCLAG_REMOTE_FDB_TABLE_NAME); ASSERT_EQ(gFdbOrch, nullptr); - gFdbOrch = new FdbOrch(applDbFdb, stateDbFdb, gPortsOrch); + gFdbOrch = new FdbOrch(m_app_db.get(), app_fdb_tables, stateDbFdb, stateMclagDbFdb, gPortsOrch); ASSERT_EQ(gNeighOrch, nullptr); gNeighOrch = new NeighOrch(m_app_db.get(), APP_NEIGH_TABLE_NAME, gIntfsOrch, gFdbOrch, gPortsOrch); From 25f10994f88a2bfb37d314eceeeea77e4c730540 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Mon, 4 Jan 2021 15:09:59 -0800 Subject: [PATCH 06/54] Updating fdbsyncd files. --- .gitignore | 1 - Makefile.am | 2 +- configure.ac | 1 - fdbsyncd/fdbsync.cpp | 1489 +++++++++++++++++++---------------------- fdbsyncd/fdbsync.h | 285 ++++---- fdbsyncd/fdbsyncd.cpp | 215 +++--- 6 files changed, 928 insertions(+), 1065 deletions(-) diff --git a/.gitignore b/.gitignore index cd2f5522e5..d020b57058 100644 --- a/.gitignore +++ b/.gitignore @@ -54,7 +54,6 @@ cfgmgr/sflowmgrd fpmsyncd/fpmsyncd gearsyncd/gearsyncd mclagsyncd/mclagsyncd -fdbsyncd/fdbsyncd natsyncd/natsyncd neighsyncd/neighsyncd fdbsyncd/fdbsyncd diff --git a/Makefile.am b/Makefile.am index c65daac646..da3dcb319f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = fpmsyncd neighsyncd portsyncd mclagsyncd fdbsyncd natsyncd orchagent swssconfig cfgmgr tests gearsyncd +SUBDIRS = fpmsyncd neighsyncd fdbsyncd portsyncd mclagsyncd natsyncd orchagent swssconfig cfgmgr tests gearsyncd if HAVE_LIBTEAM SUBDIRS += teamsyncd tlm_teamd diff --git a/configure.ac b/configure.ac index 60eced7afc..d7816b6f17 100644 --- a/configure.ac +++ b/configure.ac @@ -98,7 +98,6 @@ AC_CONFIG_FILES([ teamsyncd/Makefile tlm_teamd/Makefile mclagsyncd/Makefile - fdbsyncd/Makefile swssconfig/Makefile cfgmgr/Makefile tests/Makefile diff --git a/fdbsyncd/fdbsync.cpp b/fdbsyncd/fdbsync.cpp index 3dfc2d078e..9a88e557bf 100644 --- a/fdbsyncd/fdbsync.cpp +++ b/fdbsyncd/fdbsync.cpp @@ -1,803 +1,686 @@ -#include -#include -#include -#include -#include -#include - -#include "logger.h" -#include "dbconnector.h" -#include "producerstatetable.h" -#include "ipaddress.h" -#include "netmsg.h" -#include "macaddress.h" -#include "exec.h" -#include "fdbsync.h" -#include "warm_restart.h" -#include "errno.h" - -using namespace std; -using namespace swss; - -#define VXLAN_BR_IF_NAME_PREFIX "Brvxlan" - -FdbSync::FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db) : - m_fdbTable(pipelineAppDB, APP_VXLAN_FDB_TABLE_NAME), - m_imetTable(pipelineAppDB, APP_VXLAN_REMOTE_VNI_TABLE_NAME), - m_fdbStateTable(stateDb, STATE_FDB_TABLE_NAME), - m_mclagRemoteFdbStateTable(stateDb, STATE_MCLAG_REMOTE_FDB_TABLE_NAME), - m_cfgEvpnNvoTable(config_db, CFG_VXLAN_EVPN_NVO_TABLE_NAME) -{ - m_AppRestartAssist = new AppRestartAssist(pipelineAppDB, "fdbsyncd", "swss", DEFAULT_FDBSYNC_WARMSTART_TIMER); - if (m_AppRestartAssist) - { - m_AppRestartAssist->registerAppTable(APP_VXLAN_FDB_TABLE_NAME, &m_fdbTable); - m_AppRestartAssist->registerAppTable(APP_VXLAN_REMOTE_VNI_TABLE_NAME, &m_imetTable); - } -} - -FdbSync::~FdbSync() -{ - if (m_AppRestartAssist) - { - delete m_AppRestartAssist; - } -} - -void FdbSync::processCfgEvpnNvo() -{ - std::deque entries; - m_cfgEvpnNvoTable.pops(entries); - bool lastNvoState = m_isEvpnNvoExist; - - for (auto entry: entries) - { - std::string op = kfvOp(entry); - - if (op == SET_COMMAND) - { - m_isEvpnNvoExist = true; - } - else if (op == DEL_COMMAND) - { - m_isEvpnNvoExist = false; - } - - if (lastNvoState != m_isEvpnNvoExist) - { - updateAllLocalMac(); - } - } - return; -} - -void FdbSync::updateAllLocalMac() -{ - for ( auto it = m_fdb_mac.begin(); it != m_fdb_mac.end(); ++it ) - { - if (m_isEvpnNvoExist) - { - /* Add the Local FDB entry into Kernel */ - addLocalMac(it->first, "replace"); - } - else - { - /* Delete the Local FDB entry from Kernel */ - addLocalMac(it->first, "del"); - } - } -} - -void FdbSync::processStateFdb() -{ - struct m_fdb_info info; - std::deque entries; - - m_fdbStateTable.pops(entries); - - int count =0 ; - for (auto entry: entries) - { - count++; - std::string key = kfvKey(entry); - std::string op = kfvOp(entry); - - std::size_t delimiter = key.find_first_of(":"); - auto vlan_name = key.substr(0, delimiter); - auto mac_address = key.substr(delimiter+1); - - info.vid = vlan_name; - info.mac = mac_address; - - if(op == "SET") - { - info.op_type = FDB_OPER_ADD ; - } - else - { - info.op_type = FDB_OPER_DEL ; - } - - SWSS_LOG_INFO("FDBSYNCD STATE FDB updates key=%s, operation=%s\n", key.c_str(), op.c_str()); - - for (auto i : kfvFieldsValues(entry)) - { - SWSS_LOG_INFO(" FDBSYNCD STATE FDB updates : " - "FvFiels %s, FvValues: %s \n", fvField(i).c_str(), fvValue(i).c_str()); - - if(fvField(i) == "port") - { - info.port_name = fvValue(i); - } - - if(fvField(i) == "type") - { - if(fvValue(i) == "dynamic") - { - info.type = FDB_TYPE_DYNAMIC; - } - else if (fvValue(i) == "static") - { - info.type = FDB_TYPE_STATIC; - } - } - } - - if (op != "SET" && macCheckSrcDB(&info) == false) - { - continue; - } - updateLocalMac(&info); - } -} - -void FdbSync::processStateMclagRemoteFdb() -{ - struct m_fdb_info info; - std::deque entries; - - m_mclagRemoteFdbStateTable.pops(entries); - - int count =0 ; - for (auto entry: entries) - { - count++; - std::string key = kfvKey(entry); - std::string op = kfvOp(entry); - - std::size_t delimiter = key.find_first_of(":"); - auto vlan_name = key.substr(0, delimiter); - auto mac_address = key.substr(delimiter+1); - - info.vid = vlan_name; - memcpy(info.mac, mac_address.c_str(),mac_address.length()); - - if(op == "SET") - { - info.op_type = FDB_OPER_ADD ; - } - else - { - info.op_type = FDB_OPER_DEL ; - } - - SWSS_LOG_INFO("FDBSYNCD STATE FDB updates key=%s, operation=%s\n", key.c_str(), op.c_str()); - - for (auto i : kfvFieldsValues(entry)) - { - SWSS_LOG_INFO(" FDBSYNCD STATE FDB updates : " - "FvFiels %s, FvValues: %s \n", fvField(i).c_str(), fvValue(i).c_str()); - - if(fvField(i) == "port") - { - memcpy(info.port_name, fvValue(i).c_str(), fvValue(i).length()); - } - - if(fvField(i) == "type") - { - if(fvValue(i) == "dynamic") - { - info.type = FDB_TYPE_DYNAMIC; - } - else if (fvValue(i) == "static") - { - info.type = FDB_TYPE_STATIC; - } - } - } - - if (op != "SET" && macCheckSrcDB(&info) == false) - { - continue; - } - updateMclagRemoteMac(&info); - } -} - -void FdbSync::macUpdateCache(struct m_fdb_info *info) -{ - string key = info->vid + ":" + info->mac; - m_fdb_mac[key].port_name = info->port_name; - m_fdb_mac[key].type = info->type; - - return; -} - -void FdbSync::macUpdateMclagRemoteCache(struct m_fdb_info *info) -{ - string key = info->vid + ":" + info->mac; - m_mclag_remote_fdb_mac[key].port_name = info->port_name; - m_mclag_remote_fdb_mac[key].type = info->type; - - return; -} - -bool FdbSync::macCheckSrcDB(struct m_fdb_info *info) -{ - string key = info->vid + ":" + info->mac; - if (m_fdb_mac.find(key) != m_fdb_mac.end()) - { - SWSS_LOG_INFO("DEL_KEY %s ", key.c_str()); - return true; - } - - return false; -} - -void FdbSync::macDelVxlanEntry(string auxkey, struct m_fdb_info *info) -{ - std::string vtep = m_mac[auxkey].vtep; - - const std::string cmds = std::string("") - + " bridge fdb del " + info->mac + " dev " - + m_mac[auxkey].ifname + " dst " + vtep + " vlan " + info->vid.substr(4); - - std::string res; - int ret = swss::exec(cmds, res); - if (ret != 0) - { - SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - - SWSS_LOG_INFO("Success cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - - return; -} - -void FdbSync::updateLocalMac (struct m_fdb_info *info) -{ - char *op; - char *type; - string port_name = ""; - string key = info->vid + ":" + info->mac; - short fdb_type; /*dynamic or static*/ - - if (info->op_type == FDB_OPER_ADD) - { - macUpdateCache(info); - op = "replace"; - port_name = info->port_name; - fdb_type = info->type; - /* Check if this vlan+key is also learned by vxlan neighbor then delete learned on */ - if (m_mac.find(key) != m_mac.end()) - { - macDelVxlanEntry(key, info); - SWSS_LOG_INFO("Local learn event deleting from VXLAN table DEL_KEY %s", key.c_str()); - macDelVxlan(key); - } - } - else - { - op = "del"; - port_name = m_fdb_mac[key].port_name; - fdb_type = m_fdb_mac[key].type; - m_fdb_mac.erase(key); - } - - if (!m_isEvpnNvoExist) - { - SWSS_LOG_INFO("Ignore kernel update EVPN NVO is not configured MAC %s", key.c_str()); - return; - } - - if (fdb_type == FDB_TYPE_DYNAMIC) - { - type = "dynamic"; - } - else - { - type = "static"; - } - - const std::string cmds = std::string("") - + " bridge fdb " + op + " " + info->mac + " dev " - + port_name + " master " + type + " vlan " + info->vid.substr(4); - - std::string res; - int ret = swss::exec(cmds, res); - - SWSS_LOG_INFO("cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - - return; -} - -void FdbSync::addLocalMac(string key, string op) -{ - char *type; - string port_name = ""; - string mac = ""; - string vlan = ""; - size_t str_loc = string::npos; - - str_loc = key.find(":"); - if (str_loc == string::npos) - { - SWSS_LOG_ERROR("Local MAC issue with Key:%s", key.c_str()); - return; - } - vlan = key.substr(4, str_loc-4); - mac = key.substr(str_loc+1, std::string::npos); - - SWSS_LOG_INFO("Local route Vlan:%s MAC:%s Key:%s Op:%s", vlan.c_str(), mac.c_str(), key.c_str(), op.c_str()); - - if (m_fdb_mac.find(key)!=m_fdb_mac.end()) - { - port_name = m_fdb_mac[key].port_name; - if (port_name.empty()) - { - SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); - return; - } - - if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) - { - type = "dynamic"; - } - else - { - type = "static"; - } - - const std::string cmds = std::string("") - + " bridge fdb " + op + " " + mac + " dev " - + port_name + " master " + type + " vlan " + vlan; - - std::string res; - int ret = swss::exec(cmds, res); - if (ret != 0) - { - SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - - SWSS_LOG_INFO("Config triggered cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - return; -} - -void FdbSync::updateMclagRemoteMac (struct m_fdb_info *info) -{ - char *op; - char *type; - string port_name = ""; - string key = info->vid + ":" + info->mac; - short fdb_type; /*dynamic or static*/ - - if (info->op_type == FDB_OPER_ADD) - { - macUpdateMclagRemoteCache(info); - op = "replace"; - port_name = info->port_name; - fdb_type = info->type; - } - else - { - op = "del"; - port_name = m_mclag_remote_fdb_mac[key].port_name; - fdb_type = m_mclag_remote_fdb_mac[key].type; - m_mclag_remote_fdb_mac.erase(key); - } - - if (fdb_type == FDB_TYPE_DYNAMIC) - { - type = "dynamic"; - } - else - { - type = "static"; - } - - const std::string cmds = std::string("") - + " bridge fdb " + op + " " + info->mac + " dev " - + port_name + " master " + type + " vlan " + info->vid.substr(4); - - std::string res; - int ret = swss::exec(cmds, res); - - SWSS_LOG_INFO("cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - - return; -} - -/* - * This is a special case handling where mac is learned in the ASIC. - * Then MAC is learned in the Kernel, Since this mac is learned in the Kernel - * This MAC will age out, when MAC delete is received from the Kernel. - * If MAC is still present in the state DB cache then fdbsyncd will be - * re-programmed with MAC in the Kernel - */ -void FdbSync::macRefreshStateDB(int vlan, string kmac) -{ - string key = "Vlan" + to_string(vlan) + ":" + kmac; - char *type; - string port_name = ""; - - SWSS_LOG_INFO("Refreshing Vlan:%d MAC route MAC:%s Key %s", vlan, kmac.c_str(), key.c_str()); - - if (m_fdb_mac.find(key)!=m_fdb_mac.end()) - { - port_name = m_fdb_mac[key].port_name; - if (port_name.empty()) - { - SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); - return; - } - - if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) - { - type = "dynamic"; - } - else - { - type = "static"; - } - - const std::string cmds = std::string("") - + " bridge fdb " + "replace" + " " + kmac + " dev " - + port_name + " master " + type + " vlan " + to_string(vlan); - - std::string res; - int ret = swss::exec(cmds, res); - if (ret != 0) - { - SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - - SWSS_LOG_INFO("Refreshing cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - return; -} - -bool FdbSync::checkImetExist(string key, uint32_t vni) -{ - if (m_imet_route.find(key) != m_imet_route.end()) - { - SWSS_LOG_INFO("IMET exist key:%s Vni:%d", key.c_str(), vni); - return false; - } - m_imet_route[key].vni = vni; - return true; -} - -bool FdbSync::checkDelImet(string key, uint32_t vni) -{ - int ret = false; - - SWSS_LOG_INFO("Del IMET key:%s Vni:%d", key.c_str(), vni); - if (m_imet_route.find(key) != m_imet_route.end()) - { - ret = true; - m_imet_route.erase(key); - } - return ret; -} - -void FdbSync::imetAddRoute(struct in_addr vtep, string vlan_str, uint32_t vni) -{ - string vlan_id = "Vlan" + vlan_str; - string key = vlan_id + ":" + inet_ntoa(vtep); - - if (!checkImetExist(key, vni)) - { - return; - } - - SWSS_LOG_INFO("%sIMET Add route key:%s vtep:%s %s", - m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", - key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); - - std::vector fvVector; - FieldValueTuple f("vni", to_string(vni)); - fvVector.push_back(f); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, false); - return; - } - - m_imetTable.set(key, fvVector); - return; -} - -void FdbSync::imetDelRoute(struct in_addr vtep, string vlan_str, uint32_t vni) -{ - string vlan_id = "Vlan" + vlan_str; - string key = vlan_id + ":" + inet_ntoa(vtep); - - if (!checkDelImet(key, vni)) - { - return; - } - - SWSS_LOG_INFO("%sIMET Del route key:%s vtep:%s %s", - m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", - key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); - - std::vector fvVector; - FieldValueTuple f("vni", to_string(vni)); - fvVector.push_back(f); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, true); - return; - } - - m_imetTable.del(key); - return; -} - -void FdbSync::macDelVxlanDB(string key) -{ - string vtep = m_mac[key].vtep; - string type; - string vni = to_string(m_mac[key].vni); - type = m_mac[key].type; - - std::vector fvVector; - FieldValueTuple rv("remote_vtep", vtep); - FieldValueTuple t("type", type); - FieldValueTuple v("vni", vni); - fvVector.push_back(rv); - fvVector.push_back(t); - fvVector.push_back(v); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, true); - return; - } - - SWSS_LOG_INFO("VXLAN_FDB_TABLE: DEL_KEY %s vtep:%s type:%s", key.c_str(), vtep.c_str(), type.c_str()); - m_fdbTable.del(key); - return; - -} - -void FdbSync::macAddVxlan(string key, struct in_addr vtep, string type, uint32_t vni, string intf_name) -{ - string svtep = inet_ntoa(vtep); - string svni = to_string(vni); - - /* Update the DB with Vxlan MAC */ - m_mac[key] = {svtep, type, vni, intf_name}; - - std::vector fvVector; - FieldValueTuple rv("remote_vtep", svtep); - FieldValueTuple t("type", type); - FieldValueTuple v("vni", svni); - fvVector.push_back(rv); - fvVector.push_back(t); - fvVector.push_back(v); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, false); - return; - } - - SWSS_LOG_INFO("VXLAN_FDB_TABLE: ADD_KEY %s vtep:%s type:%s", key.c_str(), svtep.c_str(), type.c_str()); - m_fdbTable.set(key, fvVector); - - return; -} - -void FdbSync::macDelVxlan(string key) -{ - if (m_mac.find(key) != m_mac.end()) - { - SWSS_LOG_INFO("DEL_KEY %s vtep:%s type:%s", key.c_str(), m_mac[key].vtep.c_str(), m_mac[key].type.c_str()); - macDelVxlanDB(key); - m_mac.erase(key); - } - return; -} - -void FdbSync::onMsgNbr(int nlmsg_type, struct nl_object *obj) -{ - char macStr[MAX_ADDR_SIZE + 1] = {0}; - struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj; - struct in_addr vtep = {0}; - int vlan = 0, ifindex = 0; - uint32_t vni = 0; - nl_addr *vtep_addr; - string ifname; - string key; - bool delete_key = false; - size_t str_loc = string::npos; - string type = ""; - string vlan_id = ""; - bool isVxlanIntf = false; - - if ((nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_GETNEIGH) && - (nlmsg_type != RTM_DELNEIGH)) - { - return; - } - - /* Only MAC route is to be supported */ - if (rtnl_neigh_get_family(neigh) != AF_BRIDGE) - { - return; - } - ifindex = rtnl_neigh_get_ifindex(neigh); - if (m_intf_info.find(ifindex) != m_intf_info.end()) - { - isVxlanIntf = true; - ifname = m_intf_info[ifindex].ifname; - } - - nl_addr2str(rtnl_neigh_get_lladdr(neigh), macStr, MAX_ADDR_SIZE); - - if (isVxlanIntf == false) - { - if (nlmsg_type != RTM_DELNEIGH) - { - return; - } - } - else - { - /* If this is for vnet bridge vxlan interface, then return */ - if (ifname.find(VXLAN_BR_IF_NAME_PREFIX) != string::npos) - { - return; - } - - /* VxLan netdevice should be in - format */ - str_loc = ifname.rfind("-"); - if (str_loc == string::npos) - { - return; - } - - vlan_id = "Vlan" + ifname.substr(str_loc+1, std::string::npos); - vni = m_intf_info[ifindex].vni; - } - - - if (isVxlanIntf == false) - { - vlan = rtnl_neigh_get_vlan(neigh); - if (m_isEvpnNvoExist) - { - macRefreshStateDB(vlan, macStr); - } - return; - } - - vtep_addr = rtnl_neigh_get_dst(neigh); - if (vtep_addr == NULL) - { - return; - } - else - { - /* Currently we only support ipv4 tunnel endpoints */ - vtep.s_addr = *(uint32_t *)nl_addr_get_binary_addr(vtep_addr); - SWSS_LOG_INFO("Tunnel IP %s Int%d", inet_ntoa(vtep), *(uint32_t *)nl_addr_get_binary_addr(vtep_addr)); - } - - int state = rtnl_neigh_get_state(neigh); - if ((nlmsg_type == RTM_DELNEIGH) || (state == NUD_INCOMPLETE) || - (state == NUD_FAILED)) - { - delete_key = true; - } - - if (state & NUD_NOARP) - { - /* This is a static route */ - type = "static"; - } - else - { - type = "dynamic"; - } - - /* Handling IMET routes */ - if (MacAddress(macStr) == MacAddress("00:00:00:00:00:00")) - { - if (vtep.s_addr) - { - string vlan_str = ifname.substr(str_loc+1, string::npos); - - if (!delete_key) - { - imetAddRoute(vtep, vlan_str, vni); - } - else - { - imetDelRoute(vtep, vlan_str, vni); - } - } - return; - } - - key+= vlan_id; - key+= ":"; - key+= macStr; - - if (!delete_key) - { - macAddVxlan(key, vtep, type, vni, ifname); - } - else - { - macDelVxlan(key); - } - return; -} - -void FdbSync::onMsgLink(int nlmsg_type, struct nl_object *obj) -{ - struct rtnl_link *link; - char *ifname = NULL; - char *nil = "NULL"; - int ifindex; - unsigned int vni; - - link = (struct rtnl_link *)obj; - ifname = rtnl_link_get_name(link); - ifindex = rtnl_link_get_ifindex(link); - if (rtnl_link_is_vxlan(link) == 0) - { - return; - } - - if (rtnl_link_vxlan_get_id(link, &vni) != 0) - { - SWSS_LOG_INFO("Op:%d VxLAN dev:%s index:%d vni:%d. Not found", nlmsg_type, ifname? ifname: nil, ifindex, vni); - return; - } - SWSS_LOG_INFO("Op:%d VxLAN dev %s index:%d vni:%d", nlmsg_type, ifname? ifname: nil, ifindex, vni); - if (nlmsg_type == RTM_NEWLINK) - { - m_intf_info[ifindex].vni = vni; - m_intf_info[ifindex].ifname = ifname; - } - return; -} - -void FdbSync::onMsg(int nlmsg_type, struct nl_object *obj) -{ - if ((nlmsg_type != RTM_NEWLINK) && - (nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_DELNEIGH)) - { - SWSS_LOG_DEBUG("netlink: unhandled event: %d", nlmsg_type); - return; - } - if (nlmsg_type == RTM_NEWLINK) - { - onMsgLink(nlmsg_type, obj); - } - else - { - onMsgNbr(nlmsg_type, obj); - } -} - +#include +#include +#include +#include +#include +#include + +#include "logger.h" +#include "dbconnector.h" +#include "producerstatetable.h" +#include "ipaddress.h" +#include "netmsg.h" +#include "macaddress.h" +#include "exec.h" +#include "fdbsync.h" +#include "warm_restart.h" +#include "errno.h" + +using namespace std; +using namespace swss; + +#define VXLAN_BR_IF_NAME_PREFIX "Brvxlan" + +FdbSync::FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db) : + m_fdbTable(pipelineAppDB, APP_VXLAN_FDB_TABLE_NAME), + m_imetTable(pipelineAppDB, APP_VXLAN_REMOTE_VNI_TABLE_NAME), + m_fdbStateTable(stateDb, STATE_FDB_TABLE_NAME), + m_cfgEvpnNvoTable(config_db, CFG_VXLAN_EVPN_NVO_TABLE_NAME) +{ + m_AppRestartAssist = new AppRestartAssist(pipelineAppDB, "fdbsyncd", "swss", DEFAULT_FDBSYNC_WARMSTART_TIMER); + if (m_AppRestartAssist) + { + m_AppRestartAssist->registerAppTable(APP_VXLAN_FDB_TABLE_NAME, &m_fdbTable); + m_AppRestartAssist->registerAppTable(APP_VXLAN_REMOTE_VNI_TABLE_NAME, &m_imetTable); + } +} + +FdbSync::~FdbSync() +{ + if (m_AppRestartAssist) + { + delete m_AppRestartAssist; + } +} + +void FdbSync::processCfgEvpnNvo() +{ + std::deque entries; + m_cfgEvpnNvoTable.pops(entries); + bool lastNvoState = m_isEvpnNvoExist; + + for (auto entry: entries) + { + std::string op = kfvOp(entry); + + if (op == SET_COMMAND) + { + m_isEvpnNvoExist = true; + } + else if (op == DEL_COMMAND) + { + m_isEvpnNvoExist = false; + } + + if (lastNvoState != m_isEvpnNvoExist) + { + updateAllLocalMac(); + } + } + return; +} + +void FdbSync::updateAllLocalMac() +{ + for ( auto it = m_fdb_mac.begin(); it != m_fdb_mac.end(); ++it ) + { + if (m_isEvpnNvoExist) + { + /* Add the Local FDB entry into Kernel */ + addLocalMac(it->first, "replace"); + } + else + { + /* Delete the Local FDB entry from Kernel */ + addLocalMac(it->first, "del"); + } + } +} + +void FdbSync::processStateFdb() +{ + struct m_fdb_info info; + std::deque entries; + + m_fdbStateTable.pops(entries); + + int count =0 ; + for (auto entry: entries) + { + count++; + std::string key = kfvKey(entry); + std::string op = kfvOp(entry); + + std::size_t delimiter = key.find_first_of(":"); + auto vlan_name = key.substr(0, delimiter); + auto mac_address = key.substr(delimiter+1); + + info.vid = vlan_name; + info.mac = mac_address; + + if(op == "SET") + { + info.op_type = FDB_OPER_ADD ; + } + else + { + info.op_type = FDB_OPER_DEL ; + } + + SWSS_LOG_INFO("FDBSYNCD STATE FDB updates key=%s, operation=%s\n", key.c_str(), op.c_str()); + + for (auto i : kfvFieldsValues(entry)) + { + SWSS_LOG_INFO(" FDBSYNCD STATE FDB updates : " + "FvFiels %s, FvValues: %s \n", fvField(i).c_str(), fvValue(i).c_str()); + + if(fvField(i) == "port") + { + info.port_name = fvValue(i); + } + + if(fvField(i) == "type") + { + if(fvValue(i) == "dynamic") + { + info.type = FDB_TYPE_DYNAMIC; + } + else if (fvValue(i) == "static") + { + info.type = FDB_TYPE_STATIC; + } + } + } + + if (op != "SET" && macCheckSrcDB(&info) == false) + { + continue; + } + updateLocalMac(&info); + } +} + +void FdbSync::macUpdateCache(struct m_fdb_info *info) +{ + string key = info->vid + ":" + info->mac; + m_fdb_mac[key].port_name = info->port_name; + m_fdb_mac[key].type = info->type; + + return; +} + +bool FdbSync::macCheckSrcDB(struct m_fdb_info *info) +{ + string key = info->vid + ":" + info->mac; + if (m_fdb_mac.find(key) != m_fdb_mac.end()) + { + SWSS_LOG_INFO("DEL_KEY %s ", key.c_str()); + return true; + } + + return false; +} + +void FdbSync::macDelVxlanEntry(string auxkey, struct m_fdb_info *info) +{ + std::string vtep = m_mac[auxkey].vtep; + + const std::string cmds = std::string("") + + " bridge fdb del " + info->mac + " dev " + + m_mac[auxkey].ifname + " dst " + vtep + " vlan " + info->vid.substr(4); + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_INFO("Success cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + + return; +} + +void FdbSync::updateLocalMac (struct m_fdb_info *info) +{ + char *op; + char *type; + string port_name = ""; + string key = info->vid + ":" + info->mac; + short fdb_type; /*dynamic or static*/ + + if (info->op_type == FDB_OPER_ADD) + { + macUpdateCache(info); + op = "replace"; + port_name = info->port_name; + fdb_type = info->type; + /* Check if this vlan+key is also learned by vxlan neighbor then delete learned on */ + if (m_mac.find(key) != m_mac.end()) + { + macDelVxlanEntry(key, info); + SWSS_LOG_INFO("Local learn event deleting from VXLAN table DEL_KEY %s", key.c_str()); + macDelVxlan(key); + } + } + else + { + op = "del"; + port_name = m_fdb_mac[key].port_name; + fdb_type = m_fdb_mac[key].type; + m_fdb_mac.erase(key); + } + + if (!m_isEvpnNvoExist) + { + SWSS_LOG_INFO("Ignore kernel update EVPN NVO is not configured MAC %s", key.c_str()); + return; + } + + if (fdb_type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + op + " " + info->mac + " dev " + + port_name + " master " + type + " vlan " + info->vid.substr(4); + + std::string res; + int ret = swss::exec(cmds, res); + + SWSS_LOG_INFO("cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + + return; +} + +void FdbSync::addLocalMac(string key, string op) +{ + char *type; + string port_name = ""; + string mac = ""; + string vlan = ""; + size_t str_loc = string::npos; + + str_loc = key.find(":"); + if (str_loc == string::npos) + { + SWSS_LOG_ERROR("Local MAC issue with Key:%s", key.c_str()); + return; + } + vlan = key.substr(4, str_loc-4); + mac = key.substr(str_loc+1, std::string::npos); + + SWSS_LOG_INFO("Local route Vlan:%s MAC:%s Key:%s Op:%s", vlan.c_str(), mac.c_str(), key.c_str(), op.c_str()); + + if (m_fdb_mac.find(key)!=m_fdb_mac.end()) + { + port_name = m_fdb_mac[key].port_name; + if (port_name.empty()) + { + SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); + return; + } + + if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + op + " " + mac + " dev " + + port_name + " master " + type + " vlan " + vlan; + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_INFO("Config triggered cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + return; +} + +/* + * This is a special case handling where mac is learned in the ASIC. + * Then MAC is learned in the Kernel, Since this mac is learned in the Kernel + * This MAC will age out, when MAC delete is received from the Kernel. + * If MAC is still present in the state DB cache then fdbsyncd will be + * re-programmed with MAC in the Kernel + */ +void FdbSync::macRefreshStateDB(int vlan, string kmac) +{ + string key = "Vlan" + to_string(vlan) + ":" + kmac; + char *type; + string port_name = ""; + + SWSS_LOG_INFO("Refreshing Vlan:%d MAC route MAC:%s Key %s", vlan, kmac.c_str(), key.c_str()); + + if (m_fdb_mac.find(key)!=m_fdb_mac.end()) + { + port_name = m_fdb_mac[key].port_name; + if (port_name.empty()) + { + SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); + return; + } + + if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + "replace" + " " + kmac + " dev " + + port_name + " master " + type + " vlan " + to_string(vlan); + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_INFO("Refreshing cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + return; +} + +bool FdbSync::checkImetExist(string key, uint32_t vni) +{ + if (m_imet_route.find(key) != m_imet_route.end()) + { + SWSS_LOG_INFO("IMET exist key:%s Vni:%d", key.c_str(), vni); + return false; + } + m_imet_route[key].vni = vni; + return true; +} + +bool FdbSync::checkDelImet(string key, uint32_t vni) +{ + int ret = false; + + SWSS_LOG_INFO("Del IMET key:%s Vni:%d", key.c_str(), vni); + if (m_imet_route.find(key) != m_imet_route.end()) + { + ret = true; + m_imet_route.erase(key); + } + return ret; +} + +void FdbSync::imetAddRoute(struct in_addr vtep, string vlan_str, uint32_t vni) +{ + string vlan_id = "Vlan" + vlan_str; + string key = vlan_id + ":" + inet_ntoa(vtep); + + if (!checkImetExist(key, vni)) + { + return; + } + + SWSS_LOG_INFO("%sIMET Add route key:%s vtep:%s %s", + m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", + key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); + + std::vector fvVector; + FieldValueTuple f("vni", to_string(vni)); + fvVector.push_back(f); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, false); + return; + } + + m_imetTable.set(key, fvVector); + return; +} + +void FdbSync::imetDelRoute(struct in_addr vtep, string vlan_str, uint32_t vni) +{ + string vlan_id = "Vlan" + vlan_str; + string key = vlan_id + ":" + inet_ntoa(vtep); + + if (!checkDelImet(key, vni)) + { + return; + } + + SWSS_LOG_INFO("%sIMET Del route key:%s vtep:%s %s", + m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", + key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); + + std::vector fvVector; + FieldValueTuple f("vni", to_string(vni)); + fvVector.push_back(f); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, true); + return; + } + + m_imetTable.del(key); + return; +} + +void FdbSync::macDelVxlanDB(string key) +{ + string vtep = m_mac[key].vtep; + string type; + string vni = to_string(m_mac[key].vni); + type = m_mac[key].type; + + std::vector fvVector; + FieldValueTuple rv("remote_vtep", vtep); + FieldValueTuple t("type", type); + FieldValueTuple v("vni", vni); + fvVector.push_back(rv); + fvVector.push_back(t); + fvVector.push_back(v); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, true); + return; + } + + SWSS_LOG_INFO("VXLAN_FDB_TABLE: DEL_KEY %s vtep:%s type:%s", key.c_str(), vtep.c_str(), type.c_str()); + m_fdbTable.del(key); + return; + +} + +void FdbSync::macAddVxlan(string key, struct in_addr vtep, string type, uint32_t vni, string intf_name) +{ + string svtep = inet_ntoa(vtep); + string svni = to_string(vni); + + /* Update the DB with Vxlan MAC */ + m_mac[key] = {svtep, type, vni, intf_name}; + + std::vector fvVector; + FieldValueTuple rv("remote_vtep", svtep); + FieldValueTuple t("type", type); + FieldValueTuple v("vni", svni); + fvVector.push_back(rv); + fvVector.push_back(t); + fvVector.push_back(v); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, false); + return; + } + + SWSS_LOG_INFO("VXLAN_FDB_TABLE: ADD_KEY %s vtep:%s type:%s", key.c_str(), svtep.c_str(), type.c_str()); + m_fdbTable.set(key, fvVector); + + return; +} + +void FdbSync::macDelVxlan(string key) +{ + if (m_mac.find(key) != m_mac.end()) + { + SWSS_LOG_INFO("DEL_KEY %s vtep:%s type:%s", key.c_str(), m_mac[key].vtep.c_str(), m_mac[key].type.c_str()); + macDelVxlanDB(key); + m_mac.erase(key); + } + return; +} + +void FdbSync::onMsgNbr(int nlmsg_type, struct nl_object *obj) +{ + char macStr[MAX_ADDR_SIZE + 1] = {0}; + struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj; + struct in_addr vtep = {0}; + int vlan = 0, ifindex = 0; + uint32_t vni = 0; + nl_addr *vtep_addr; + string ifname; + string key; + bool delete_key = false; + size_t str_loc = string::npos; + string type = ""; + string vlan_id = ""; + bool isVxlanIntf = false; + + if ((nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_GETNEIGH) && + (nlmsg_type != RTM_DELNEIGH)) + { + return; + } + + /* Only MAC route is to be supported */ + if (rtnl_neigh_get_family(neigh) != AF_BRIDGE) + { + return; + } + ifindex = rtnl_neigh_get_ifindex(neigh); + if (m_intf_info.find(ifindex) != m_intf_info.end()) + { + isVxlanIntf = true; + ifname = m_intf_info[ifindex].ifname; + } + + nl_addr2str(rtnl_neigh_get_lladdr(neigh), macStr, MAX_ADDR_SIZE); + + if (isVxlanIntf == false) + { + if (nlmsg_type != RTM_DELNEIGH) + { + return; + } + } + else + { + /* If this is for vnet bridge vxlan interface, then return */ + if (ifname.find(VXLAN_BR_IF_NAME_PREFIX) != string::npos) + { + return; + } + + /* VxLan netdevice should be in - format */ + str_loc = ifname.rfind("-"); + if (str_loc == string::npos) + { + return; + } + + vlan_id = "Vlan" + ifname.substr(str_loc+1, std::string::npos); + vni = m_intf_info[ifindex].vni; + } + + + if (isVxlanIntf == false) + { + vlan = rtnl_neigh_get_vlan(neigh); + if (m_isEvpnNvoExist) + { + macRefreshStateDB(vlan, macStr); + } + return; + } + + vtep_addr = rtnl_neigh_get_dst(neigh); + if (vtep_addr == NULL) + { + return; + } + else + { + /* Currently we only support ipv4 tunnel endpoints */ + vtep.s_addr = *(uint32_t *)nl_addr_get_binary_addr(vtep_addr); + SWSS_LOG_INFO("Tunnel IP %s Int%d", inet_ntoa(vtep), *(uint32_t *)nl_addr_get_binary_addr(vtep_addr)); + } + + int state = rtnl_neigh_get_state(neigh); + if ((nlmsg_type == RTM_DELNEIGH) || (state == NUD_INCOMPLETE) || + (state == NUD_FAILED)) + { + delete_key = true; + } + + if (state & NUD_NOARP) + { + /* This is a static route */ + type = "static"; + } + else + { + type = "dynamic"; + } + + /* Handling IMET routes */ + if (MacAddress(macStr) == MacAddress("00:00:00:00:00:00")) + { + if (vtep.s_addr) + { + string vlan_str = ifname.substr(str_loc+1, string::npos); + + if (!delete_key) + { + imetAddRoute(vtep, vlan_str, vni); + } + else + { + imetDelRoute(vtep, vlan_str, vni); + } + } + return; + } + + key+= vlan_id; + key+= ":"; + key+= macStr; + + if (!delete_key) + { + macAddVxlan(key, vtep, type, vni, ifname); + } + else + { + macDelVxlan(key); + } + return; +} + +void FdbSync::onMsgLink(int nlmsg_type, struct nl_object *obj) +{ + struct rtnl_link *link; + char *ifname = NULL; + char *nil = "NULL"; + int ifindex; + unsigned int vni; + + link = (struct rtnl_link *)obj; + ifname = rtnl_link_get_name(link); + ifindex = rtnl_link_get_ifindex(link); + if (rtnl_link_is_vxlan(link) == 0) + { + return; + } + + if (rtnl_link_vxlan_get_id(link, &vni) != 0) + { + SWSS_LOG_INFO("Op:%d VxLAN dev:%s index:%d vni:%d. Not found", nlmsg_type, ifname? ifname: nil, ifindex, vni); + return; + } + SWSS_LOG_INFO("Op:%d VxLAN dev %s index:%d vni:%d", nlmsg_type, ifname? ifname: nil, ifindex, vni); + if (nlmsg_type == RTM_NEWLINK) + { + m_intf_info[ifindex].vni = vni; + m_intf_info[ifindex].ifname = ifname; + } + return; +} + +void FdbSync::onMsg(int nlmsg_type, struct nl_object *obj) +{ + if ((nlmsg_type != RTM_NEWLINK) && + (nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_DELNEIGH)) + { + SWSS_LOG_DEBUG("netlink: unhandled event: %d", nlmsg_type); + return; + } + if (nlmsg_type == RTM_NEWLINK) + { + onMsgLink(nlmsg_type, obj); + } + else + { + onMsgNbr(nlmsg_type, obj); + } +} + diff --git a/fdbsyncd/fdbsync.h b/fdbsyncd/fdbsync.h index e95421f27b..c8248ffefb 100644 --- a/fdbsyncd/fdbsync.h +++ b/fdbsyncd/fdbsync.h @@ -1,149 +1,136 @@ -#ifndef __FDBSYNC__ -#define __FDBSYNC__ - -#include -#include -#include "dbconnector.h" -#include "producerstatetable.h" -#include "subscriberstatetable.h" -#include "netmsg.h" -#include "warmRestartAssist.h" - -// The timeout value (in seconds) for fdbsyncd reconcilation logic -#define DEFAULT_FDBSYNC_WARMSTART_TIMER 30 - -namespace swss { - -enum FDB_OP_TYPE { - FDB_OPER_ADD =1, - FDB_OPER_DEL = 2, -}; - -enum FDB_TYPE { - FDB_TYPE_STATIC = 1, - FDB_TYPE_DYNAMIC = 2, -}; - -struct m_fdb_info -{ - std::string mac; - std::string vid; /*Store as Vlan */ - std::string port_name; - short type; /*dynamic or static*/ - short op_type; /*add or del*/ -}; - -class FdbSync : public NetMsg -{ -public: - enum { MAX_ADDR_SIZE = 64 }; - - FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db); - ~FdbSync(); - - virtual void onMsg(int nlmsg_type, struct nl_object *obj); - - bool isFdbRestoreDone(); - - AppRestartAssist *getRestartAssist() - { - return m_AppRestartAssist; - } - - SubscriberStateTable *getFdbStateTable() - { - return &m_fdbStateTable; - } - - SubscriberStateTable *getMclagRemoteFdbStateTable() - { - return &m_mclagRemoteFdbStateTable; - } - - SubscriberStateTable *getCfgEvpnNvoTable() - { - return &m_cfgEvpnNvoTable; - } - - void processStateFdb(); - - void processStateMclagRemoteFdb(); - - void processCfgEvpnNvo(); - - bool m_reconcileDone = false; - - bool m_isEvpnNvoExist = false; - -private: - ProducerStateTable m_fdbTable; - ProducerStateTable m_imetTable; - SubscriberStateTable m_fdbStateTable; - SubscriberStateTable m_mclagRemoteFdbStateTable; - AppRestartAssist *m_AppRestartAssist; - SubscriberStateTable m_cfgEvpnNvoTable; - - struct m_local_fdb_info - { - std::string port_name; - short type;/*dynamic or static*/ - }; - std::unordered_map m_fdb_mac; - - std::unordered_map m_mclag_remote_fdb_mac; - - void macDelVxlanEntry(std::string auxkey, struct m_fdb_info *info); - - void macUpdateCache(struct m_fdb_info *info); - - bool macCheckSrcDB(struct m_fdb_info *info); - - void updateLocalMac(struct m_fdb_info *info); - - void updateAllLocalMac(); - - void macRefreshStateDB(int vlan, std::string kmac); - - void updateMclagRemoteMac(struct m_fdb_info *info); - - void macUpdateMclagRemoteCache(struct m_fdb_info *info); - - bool checkImetExist(std::string key, uint32_t vni); - - bool checkDelImet(std::string key, uint32_t vni); - - struct m_mac_info - { - std::string vtep; - std::string type; - unsigned int vni; - std::string ifname; - }; - std::unordered_map m_mac; - - struct m_imet_info - { - unsigned int vni; - }; - std::unordered_map m_imet_route; - - struct intf - { - std::string ifname; - unsigned int vni; - }; - std::unordered_map m_intf_info; - - void addLocalMac(std::string key, std::string op); - void macAddVxlan(std::string key, struct in_addr vtep, std::string type, uint32_t vni, std::string intf_name); - void macDelVxlan(std::string auxkey); - void macDelVxlanDB(std::string key); - void imetAddRoute(struct in_addr vtep, std::string ifname, uint32_t vni); - void imetDelRoute(struct in_addr vtep, std::string ifname, uint32_t vni); - void onMsgNbr(int nlmsg_type, struct nl_object *obj); - void onMsgLink(int nlmsg_type, struct nl_object *obj); -}; - -} - -#endif +#ifndef __FDBSYNC__ +#define __FDBSYNC__ + +#include +#include +#include "dbconnector.h" +#include "producerstatetable.h" +#include "subscriberstatetable.h" +#include "netmsg.h" +#include "warmRestartAssist.h" + +// The timeout value (in seconds) for fdbsyncd reconcilation logic +#define DEFAULT_FDBSYNC_WARMSTART_TIMER 30 + +namespace swss { + +enum FDB_OP_TYPE { + FDB_OPER_ADD =1, + FDB_OPER_DEL = 2, +}; + +enum FDB_TYPE { + FDB_TYPE_STATIC = 1, + FDB_TYPE_DYNAMIC = 2, +}; + +struct m_fdb_info +{ + std::string mac; + std::string vid; /*Store as Vlan */ + std::string port_name; + short type; /*dynamic or static*/ + short op_type; /*add or del*/ +}; + +class FdbSync : public NetMsg +{ +public: + enum { MAX_ADDR_SIZE = 64 }; + + FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db); + ~FdbSync(); + + virtual void onMsg(int nlmsg_type, struct nl_object *obj); + + bool isFdbRestoreDone(); + + AppRestartAssist *getRestartAssist() + { + return m_AppRestartAssist; + } + + SubscriberStateTable *getFdbStateTable() + { + return &m_fdbStateTable; + } + + SubscriberStateTable *getCfgEvpnNvoTable() + { + return &m_cfgEvpnNvoTable; + } + + void processStateFdb(); + + void processCfgEvpnNvo(); + + bool m_reconcileDone = false; + + bool m_isEvpnNvoExist = false; + +private: + ProducerStateTable m_fdbTable; + ProducerStateTable m_imetTable; + SubscriberStateTable m_fdbStateTable; + AppRestartAssist *m_AppRestartAssist; + SubscriberStateTable m_cfgEvpnNvoTable; + + struct m_local_fdb_info + { + std::string port_name; + short type;/*dynamic or static*/ + }; + std::unordered_map m_fdb_mac; + + void macDelVxlanEntry(std::string auxkey, struct m_fdb_info *info); + + void macUpdateCache(struct m_fdb_info *info); + + bool macCheckSrcDB(struct m_fdb_info *info); + + void updateLocalMac(struct m_fdb_info *info); + + void updateAllLocalMac(); + + void macRefreshStateDB(int vlan, std::string kmac); + + bool checkImetExist(std::string key, uint32_t vni); + + bool checkDelImet(std::string key, uint32_t vni); + + struct m_mac_info + { + std::string vtep; + std::string type; + unsigned int vni; + std::string ifname; + }; + std::unordered_map m_mac; + + struct m_imet_info + { + unsigned int vni; + }; + std::unordered_map m_imet_route; + + struct intf + { + std::string ifname; + unsigned int vni; + }; + std::unordered_map m_intf_info; + + void addLocalMac(std::string key, std::string op); + void macAddVxlan(std::string key, struct in_addr vtep, std::string type, uint32_t vni, std::string intf_name); + void macDelVxlan(std::string auxkey); + void macDelVxlanDB(std::string key); + void imetAddRoute(struct in_addr vtep, std::string ifname, uint32_t vni); + void imetDelRoute(struct in_addr vtep, std::string ifname, uint32_t vni); + void onMsgNbr(int nlmsg_type, struct nl_object *obj); + void onMsgLink(int nlmsg_type, struct nl_object *obj); +}; + +} + +#endif + diff --git a/fdbsyncd/fdbsyncd.cpp b/fdbsyncd/fdbsyncd.cpp index 99492df184..eeffeb68c1 100644 --- a/fdbsyncd/fdbsyncd.cpp +++ b/fdbsyncd/fdbsyncd.cpp @@ -1,110 +1,105 @@ -#include -#include -#include -#include -#include "logger.h" -#include "select.h" -#include "netdispatcher.h" -#include "netlink.h" -#include "fdbsyncd/fdbsync.h" - -using namespace std; -using namespace swss; - -int main(int argc, char **argv) -{ - Logger::linkToDbNative("fdbsyncd"); - - DBConnector appDb(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - RedisPipeline pipelineAppDB(&appDb); - DBConnector stateDb(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - DBConnector log_db(LOGLEVEL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - DBConnector config_db(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - - FdbSync sync(&pipelineAppDB, &stateDb, &config_db); - - NetDispatcher::getInstance().registerMessageHandler(RTM_NEWNEIGH, &sync); - NetDispatcher::getInstance().registerMessageHandler(RTM_DELNEIGH, &sync); - NetDispatcher::getInstance().registerMessageHandler(RTM_NEWLINK, &sync); - - while (1) - { - try - { - NetLink netlink; - Selectable *temps; - int ret; - Select s; - - using namespace std::chrono; - - /* - * If WarmStart is enabled, restore the VXLAN-FDB and VNI - * tables and start a reconcillation timer - */ - if (sync.getRestartAssist()->isWarmStartInProgress()) - { - sync.getRestartAssist()->readTablesToMap(); - SWSS_LOG_NOTICE("Starting ReconcileTimer"); - } - - netlink.registerGroup(RTNLGRP_LINK); - netlink.registerGroup(RTNLGRP_NEIGH); - SWSS_LOG_NOTICE("Listens to link and neigh messages..."); - netlink.dumpRequest(RTM_GETLINK); - s.addSelectable(&netlink); - ret = s.select(&temps, 1); - if (ret == Select::ERROR) - { - SWSS_LOG_ERROR("Error in RTM_GETLINK dump"); - } - - netlink.dumpRequest(RTM_GETNEIGH); - - s.addSelectable(sync.getFdbStateTable()); - s.addSelectable(sync.getMclagRemoteFdbStateTable()); - s.addSelectable(sync.getCfgEvpnNvoTable()); - while (true) - { - s.select(&temps); - - if(temps == (Selectable *)sync.getFdbStateTable()) - { - sync.processStateFdb(); - } - else if(temps == (Selectable *)sync.getMclagRemoteFdbStateTable()) - { - sync.processStateMclagRemoteFdb(); - } - else if (temps == (Selectable *)sync.getCfgEvpnNvoTable()) - { - sync.processCfgEvpnNvo(); - } - else - { - /* - * If warmstart is in progress, we check the reconcile timer, - * if timer expired, we stop the timer and start the reconcile process - */ - if (sync.getRestartAssist()->isWarmStartInProgress()) - { - if (sync.getRestartAssist()->checkReconcileTimer(temps)) - { - sync.m_reconcileDone = true; - sync.getRestartAssist()->stopReconcileTimer(s); - sync.getRestartAssist()->reconcile(); - SWSS_LOG_NOTICE("VXLAN FDB VNI Reconcillation Complete (Timer)"); - } - } - } - } - } - catch (const std::exception& e) - { - cout << "Exception \"" << e.what() << "\" had been thrown in deamon" << endl; - return 0; - } - } - - return 1; -} +#include +#include +#include +#include +#include "logger.h" +#include "select.h" +#include "netdispatcher.h" +#include "netlink.h" +#include "fdbsyncd/fdbsync.h" + +using namespace std; +using namespace swss; + +int main(int argc, char **argv) +{ + Logger::linkToDbNative("fdbsyncd"); + + DBConnector appDb(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + RedisPipeline pipelineAppDB(&appDb); + DBConnector stateDb(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + DBConnector log_db(LOGLEVEL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + DBConnector config_db(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + + FdbSync sync(&pipelineAppDB, &stateDb, &config_db); + + NetDispatcher::getInstance().registerMessageHandler(RTM_NEWNEIGH, &sync); + NetDispatcher::getInstance().registerMessageHandler(RTM_DELNEIGH, &sync); + NetDispatcher::getInstance().registerMessageHandler(RTM_NEWLINK, &sync); + + while (1) + { + try + { + NetLink netlink; + Selectable *temps; + int ret; + Select s; + + using namespace std::chrono; + + /* + * If WarmStart is enabled, restore the VXLAN-FDB and VNI + * tables and start a reconcillation timer + */ + if (sync.getRestartAssist()->isWarmStartInProgress()) + { + sync.getRestartAssist()->readTablesToMap(); + SWSS_LOG_NOTICE("Starting ReconcileTimer"); + } + + netlink.registerGroup(RTNLGRP_LINK); + netlink.registerGroup(RTNLGRP_NEIGH); + SWSS_LOG_NOTICE("Listens to link and neigh messages..."); + netlink.dumpRequest(RTM_GETLINK); + s.addSelectable(&netlink); + ret = s.select(&temps, 1); + if (ret == Select::ERROR) + { + SWSS_LOG_ERROR("Error in RTM_GETLINK dump"); + } + + netlink.dumpRequest(RTM_GETNEIGH); + + s.addSelectable(sync.getFdbStateTable()); + s.addSelectable(sync.getCfgEvpnNvoTable()); + while (true) + { + s.select(&temps); + + if(temps == (Selectable *)sync.getFdbStateTable()) + { + sync.processStateFdb(); + } + else if (temps == (Selectable *)sync.getCfgEvpnNvoTable()) + { + sync.processCfgEvpnNvo(); + } + else + { + /* + * If warmstart is in progress, we check the reconcile timer, + * if timer expired, we stop the timer and start the reconcile process + */ + if (sync.getRestartAssist()->isWarmStartInProgress()) + { + if (sync.getRestartAssist()->checkReconcileTimer(temps)) + { + sync.m_reconcileDone = true; + sync.getRestartAssist()->stopReconcileTimer(s); + sync.getRestartAssist()->reconcile(); + SWSS_LOG_NOTICE("VXLAN FDB VNI Reconcillation Complete (Timer)"); + } + } + } + } + } + catch (const std::exception& e) + { + cout << "Exception \"" << e.what() << "\" had been thrown in deamon" << endl; + return 0; + } + } + + return 1; +} From 5d6fed5cd20c84312460a7d4ed247f8b1e216de7 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Mon, 4 Jan 2021 15:53:22 -0800 Subject: [PATCH 07/54] Updating the Fdbsyncd and fixing compilation. --- fdbsyncd/fdbsync.cpp | 1490 +++++++++++++++++++++------------------ fdbsyncd/fdbsync.h | 285 ++++---- fdbsyncd/fdbsyncd.cpp | 216 +++--- orchagent/portsorch.cpp | 1 - 4 files changed, 1064 insertions(+), 928 deletions(-) diff --git a/fdbsyncd/fdbsync.cpp b/fdbsyncd/fdbsync.cpp index 9a88e557bf..d0b1d902d3 100644 --- a/fdbsyncd/fdbsync.cpp +++ b/fdbsyncd/fdbsync.cpp @@ -1,686 +1,804 @@ -#include -#include -#include -#include -#include -#include - -#include "logger.h" -#include "dbconnector.h" -#include "producerstatetable.h" -#include "ipaddress.h" -#include "netmsg.h" -#include "macaddress.h" -#include "exec.h" -#include "fdbsync.h" -#include "warm_restart.h" -#include "errno.h" - -using namespace std; -using namespace swss; - -#define VXLAN_BR_IF_NAME_PREFIX "Brvxlan" - -FdbSync::FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db) : - m_fdbTable(pipelineAppDB, APP_VXLAN_FDB_TABLE_NAME), - m_imetTable(pipelineAppDB, APP_VXLAN_REMOTE_VNI_TABLE_NAME), - m_fdbStateTable(stateDb, STATE_FDB_TABLE_NAME), - m_cfgEvpnNvoTable(config_db, CFG_VXLAN_EVPN_NVO_TABLE_NAME) -{ - m_AppRestartAssist = new AppRestartAssist(pipelineAppDB, "fdbsyncd", "swss", DEFAULT_FDBSYNC_WARMSTART_TIMER); - if (m_AppRestartAssist) - { - m_AppRestartAssist->registerAppTable(APP_VXLAN_FDB_TABLE_NAME, &m_fdbTable); - m_AppRestartAssist->registerAppTable(APP_VXLAN_REMOTE_VNI_TABLE_NAME, &m_imetTable); - } -} - -FdbSync::~FdbSync() -{ - if (m_AppRestartAssist) - { - delete m_AppRestartAssist; - } -} - -void FdbSync::processCfgEvpnNvo() -{ - std::deque entries; - m_cfgEvpnNvoTable.pops(entries); - bool lastNvoState = m_isEvpnNvoExist; - - for (auto entry: entries) - { - std::string op = kfvOp(entry); - - if (op == SET_COMMAND) - { - m_isEvpnNvoExist = true; - } - else if (op == DEL_COMMAND) - { - m_isEvpnNvoExist = false; - } - - if (lastNvoState != m_isEvpnNvoExist) - { - updateAllLocalMac(); - } - } - return; -} - -void FdbSync::updateAllLocalMac() -{ - for ( auto it = m_fdb_mac.begin(); it != m_fdb_mac.end(); ++it ) - { - if (m_isEvpnNvoExist) - { - /* Add the Local FDB entry into Kernel */ - addLocalMac(it->first, "replace"); - } - else - { - /* Delete the Local FDB entry from Kernel */ - addLocalMac(it->first, "del"); - } - } -} - -void FdbSync::processStateFdb() -{ - struct m_fdb_info info; - std::deque entries; - - m_fdbStateTable.pops(entries); - - int count =0 ; - for (auto entry: entries) - { - count++; - std::string key = kfvKey(entry); - std::string op = kfvOp(entry); - - std::size_t delimiter = key.find_first_of(":"); - auto vlan_name = key.substr(0, delimiter); - auto mac_address = key.substr(delimiter+1); - - info.vid = vlan_name; - info.mac = mac_address; - - if(op == "SET") - { - info.op_type = FDB_OPER_ADD ; - } - else - { - info.op_type = FDB_OPER_DEL ; - } - - SWSS_LOG_INFO("FDBSYNCD STATE FDB updates key=%s, operation=%s\n", key.c_str(), op.c_str()); - - for (auto i : kfvFieldsValues(entry)) - { - SWSS_LOG_INFO(" FDBSYNCD STATE FDB updates : " - "FvFiels %s, FvValues: %s \n", fvField(i).c_str(), fvValue(i).c_str()); - - if(fvField(i) == "port") - { - info.port_name = fvValue(i); - } - - if(fvField(i) == "type") - { - if(fvValue(i) == "dynamic") - { - info.type = FDB_TYPE_DYNAMIC; - } - else if (fvValue(i) == "static") - { - info.type = FDB_TYPE_STATIC; - } - } - } - - if (op != "SET" && macCheckSrcDB(&info) == false) - { - continue; - } - updateLocalMac(&info); - } -} - -void FdbSync::macUpdateCache(struct m_fdb_info *info) -{ - string key = info->vid + ":" + info->mac; - m_fdb_mac[key].port_name = info->port_name; - m_fdb_mac[key].type = info->type; - - return; -} - -bool FdbSync::macCheckSrcDB(struct m_fdb_info *info) -{ - string key = info->vid + ":" + info->mac; - if (m_fdb_mac.find(key) != m_fdb_mac.end()) - { - SWSS_LOG_INFO("DEL_KEY %s ", key.c_str()); - return true; - } - - return false; -} - -void FdbSync::macDelVxlanEntry(string auxkey, struct m_fdb_info *info) -{ - std::string vtep = m_mac[auxkey].vtep; - - const std::string cmds = std::string("") - + " bridge fdb del " + info->mac + " dev " - + m_mac[auxkey].ifname + " dst " + vtep + " vlan " + info->vid.substr(4); - - std::string res; - int ret = swss::exec(cmds, res); - if (ret != 0) - { - SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - - SWSS_LOG_INFO("Success cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - - return; -} - -void FdbSync::updateLocalMac (struct m_fdb_info *info) -{ - char *op; - char *type; - string port_name = ""; - string key = info->vid + ":" + info->mac; - short fdb_type; /*dynamic or static*/ - - if (info->op_type == FDB_OPER_ADD) - { - macUpdateCache(info); - op = "replace"; - port_name = info->port_name; - fdb_type = info->type; - /* Check if this vlan+key is also learned by vxlan neighbor then delete learned on */ - if (m_mac.find(key) != m_mac.end()) - { - macDelVxlanEntry(key, info); - SWSS_LOG_INFO("Local learn event deleting from VXLAN table DEL_KEY %s", key.c_str()); - macDelVxlan(key); - } - } - else - { - op = "del"; - port_name = m_fdb_mac[key].port_name; - fdb_type = m_fdb_mac[key].type; - m_fdb_mac.erase(key); - } - - if (!m_isEvpnNvoExist) - { - SWSS_LOG_INFO("Ignore kernel update EVPN NVO is not configured MAC %s", key.c_str()); - return; - } - - if (fdb_type == FDB_TYPE_DYNAMIC) - { - type = "dynamic"; - } - else - { - type = "static"; - } - - const std::string cmds = std::string("") - + " bridge fdb " + op + " " + info->mac + " dev " - + port_name + " master " + type + " vlan " + info->vid.substr(4); - - std::string res; - int ret = swss::exec(cmds, res); - - SWSS_LOG_INFO("cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - - return; -} - -void FdbSync::addLocalMac(string key, string op) -{ - char *type; - string port_name = ""; - string mac = ""; - string vlan = ""; - size_t str_loc = string::npos; - - str_loc = key.find(":"); - if (str_loc == string::npos) - { - SWSS_LOG_ERROR("Local MAC issue with Key:%s", key.c_str()); - return; - } - vlan = key.substr(4, str_loc-4); - mac = key.substr(str_loc+1, std::string::npos); - - SWSS_LOG_INFO("Local route Vlan:%s MAC:%s Key:%s Op:%s", vlan.c_str(), mac.c_str(), key.c_str(), op.c_str()); - - if (m_fdb_mac.find(key)!=m_fdb_mac.end()) - { - port_name = m_fdb_mac[key].port_name; - if (port_name.empty()) - { - SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); - return; - } - - if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) - { - type = "dynamic"; - } - else - { - type = "static"; - } - - const std::string cmds = std::string("") - + " bridge fdb " + op + " " + mac + " dev " - + port_name + " master " + type + " vlan " + vlan; - - std::string res; - int ret = swss::exec(cmds, res); - if (ret != 0) - { - SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - - SWSS_LOG_INFO("Config triggered cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - return; -} - -/* - * This is a special case handling where mac is learned in the ASIC. - * Then MAC is learned in the Kernel, Since this mac is learned in the Kernel - * This MAC will age out, when MAC delete is received from the Kernel. - * If MAC is still present in the state DB cache then fdbsyncd will be - * re-programmed with MAC in the Kernel - */ -void FdbSync::macRefreshStateDB(int vlan, string kmac) -{ - string key = "Vlan" + to_string(vlan) + ":" + kmac; - char *type; - string port_name = ""; - - SWSS_LOG_INFO("Refreshing Vlan:%d MAC route MAC:%s Key %s", vlan, kmac.c_str(), key.c_str()); - - if (m_fdb_mac.find(key)!=m_fdb_mac.end()) - { - port_name = m_fdb_mac[key].port_name; - if (port_name.empty()) - { - SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); - return; - } - - if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) - { - type = "dynamic"; - } - else - { - type = "static"; - } - - const std::string cmds = std::string("") - + " bridge fdb " + "replace" + " " + kmac + " dev " - + port_name + " master " + type + " vlan " + to_string(vlan); - - std::string res; - int ret = swss::exec(cmds, res); - if (ret != 0) - { - SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - - SWSS_LOG_INFO("Refreshing cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - return; -} - -bool FdbSync::checkImetExist(string key, uint32_t vni) -{ - if (m_imet_route.find(key) != m_imet_route.end()) - { - SWSS_LOG_INFO("IMET exist key:%s Vni:%d", key.c_str(), vni); - return false; - } - m_imet_route[key].vni = vni; - return true; -} - -bool FdbSync::checkDelImet(string key, uint32_t vni) -{ - int ret = false; - - SWSS_LOG_INFO("Del IMET key:%s Vni:%d", key.c_str(), vni); - if (m_imet_route.find(key) != m_imet_route.end()) - { - ret = true; - m_imet_route.erase(key); - } - return ret; -} - -void FdbSync::imetAddRoute(struct in_addr vtep, string vlan_str, uint32_t vni) -{ - string vlan_id = "Vlan" + vlan_str; - string key = vlan_id + ":" + inet_ntoa(vtep); - - if (!checkImetExist(key, vni)) - { - return; - } - - SWSS_LOG_INFO("%sIMET Add route key:%s vtep:%s %s", - m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", - key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); - - std::vector fvVector; - FieldValueTuple f("vni", to_string(vni)); - fvVector.push_back(f); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, false); - return; - } - - m_imetTable.set(key, fvVector); - return; -} - -void FdbSync::imetDelRoute(struct in_addr vtep, string vlan_str, uint32_t vni) -{ - string vlan_id = "Vlan" + vlan_str; - string key = vlan_id + ":" + inet_ntoa(vtep); - - if (!checkDelImet(key, vni)) - { - return; - } - - SWSS_LOG_INFO("%sIMET Del route key:%s vtep:%s %s", - m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", - key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); - - std::vector fvVector; - FieldValueTuple f("vni", to_string(vni)); - fvVector.push_back(f); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, true); - return; - } - - m_imetTable.del(key); - return; -} - -void FdbSync::macDelVxlanDB(string key) -{ - string vtep = m_mac[key].vtep; - string type; - string vni = to_string(m_mac[key].vni); - type = m_mac[key].type; - - std::vector fvVector; - FieldValueTuple rv("remote_vtep", vtep); - FieldValueTuple t("type", type); - FieldValueTuple v("vni", vni); - fvVector.push_back(rv); - fvVector.push_back(t); - fvVector.push_back(v); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, true); - return; - } - - SWSS_LOG_INFO("VXLAN_FDB_TABLE: DEL_KEY %s vtep:%s type:%s", key.c_str(), vtep.c_str(), type.c_str()); - m_fdbTable.del(key); - return; - -} - -void FdbSync::macAddVxlan(string key, struct in_addr vtep, string type, uint32_t vni, string intf_name) -{ - string svtep = inet_ntoa(vtep); - string svni = to_string(vni); - - /* Update the DB with Vxlan MAC */ - m_mac[key] = {svtep, type, vni, intf_name}; - - std::vector fvVector; - FieldValueTuple rv("remote_vtep", svtep); - FieldValueTuple t("type", type); - FieldValueTuple v("vni", svni); - fvVector.push_back(rv); - fvVector.push_back(t); - fvVector.push_back(v); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, false); - return; - } - - SWSS_LOG_INFO("VXLAN_FDB_TABLE: ADD_KEY %s vtep:%s type:%s", key.c_str(), svtep.c_str(), type.c_str()); - m_fdbTable.set(key, fvVector); - - return; -} - -void FdbSync::macDelVxlan(string key) -{ - if (m_mac.find(key) != m_mac.end()) - { - SWSS_LOG_INFO("DEL_KEY %s vtep:%s type:%s", key.c_str(), m_mac[key].vtep.c_str(), m_mac[key].type.c_str()); - macDelVxlanDB(key); - m_mac.erase(key); - } - return; -} - -void FdbSync::onMsgNbr(int nlmsg_type, struct nl_object *obj) -{ - char macStr[MAX_ADDR_SIZE + 1] = {0}; - struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj; - struct in_addr vtep = {0}; - int vlan = 0, ifindex = 0; - uint32_t vni = 0; - nl_addr *vtep_addr; - string ifname; - string key; - bool delete_key = false; - size_t str_loc = string::npos; - string type = ""; - string vlan_id = ""; - bool isVxlanIntf = false; - - if ((nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_GETNEIGH) && - (nlmsg_type != RTM_DELNEIGH)) - { - return; - } - - /* Only MAC route is to be supported */ - if (rtnl_neigh_get_family(neigh) != AF_BRIDGE) - { - return; - } - ifindex = rtnl_neigh_get_ifindex(neigh); - if (m_intf_info.find(ifindex) != m_intf_info.end()) - { - isVxlanIntf = true; - ifname = m_intf_info[ifindex].ifname; - } - - nl_addr2str(rtnl_neigh_get_lladdr(neigh), macStr, MAX_ADDR_SIZE); - - if (isVxlanIntf == false) - { - if (nlmsg_type != RTM_DELNEIGH) - { - return; - } - } - else - { - /* If this is for vnet bridge vxlan interface, then return */ - if (ifname.find(VXLAN_BR_IF_NAME_PREFIX) != string::npos) - { - return; - } - - /* VxLan netdevice should be in - format */ - str_loc = ifname.rfind("-"); - if (str_loc == string::npos) - { - return; - } - - vlan_id = "Vlan" + ifname.substr(str_loc+1, std::string::npos); - vni = m_intf_info[ifindex].vni; - } - - - if (isVxlanIntf == false) - { - vlan = rtnl_neigh_get_vlan(neigh); - if (m_isEvpnNvoExist) - { - macRefreshStateDB(vlan, macStr); - } - return; - } - - vtep_addr = rtnl_neigh_get_dst(neigh); - if (vtep_addr == NULL) - { - return; - } - else - { - /* Currently we only support ipv4 tunnel endpoints */ - vtep.s_addr = *(uint32_t *)nl_addr_get_binary_addr(vtep_addr); - SWSS_LOG_INFO("Tunnel IP %s Int%d", inet_ntoa(vtep), *(uint32_t *)nl_addr_get_binary_addr(vtep_addr)); - } - - int state = rtnl_neigh_get_state(neigh); - if ((nlmsg_type == RTM_DELNEIGH) || (state == NUD_INCOMPLETE) || - (state == NUD_FAILED)) - { - delete_key = true; - } - - if (state & NUD_NOARP) - { - /* This is a static route */ - type = "static"; - } - else - { - type = "dynamic"; - } - - /* Handling IMET routes */ - if (MacAddress(macStr) == MacAddress("00:00:00:00:00:00")) - { - if (vtep.s_addr) - { - string vlan_str = ifname.substr(str_loc+1, string::npos); - - if (!delete_key) - { - imetAddRoute(vtep, vlan_str, vni); - } - else - { - imetDelRoute(vtep, vlan_str, vni); - } - } - return; - } - - key+= vlan_id; - key+= ":"; - key+= macStr; - - if (!delete_key) - { - macAddVxlan(key, vtep, type, vni, ifname); - } - else - { - macDelVxlan(key); - } - return; -} - -void FdbSync::onMsgLink(int nlmsg_type, struct nl_object *obj) -{ - struct rtnl_link *link; - char *ifname = NULL; - char *nil = "NULL"; - int ifindex; - unsigned int vni; - - link = (struct rtnl_link *)obj; - ifname = rtnl_link_get_name(link); - ifindex = rtnl_link_get_ifindex(link); - if (rtnl_link_is_vxlan(link) == 0) - { - return; - } - - if (rtnl_link_vxlan_get_id(link, &vni) != 0) - { - SWSS_LOG_INFO("Op:%d VxLAN dev:%s index:%d vni:%d. Not found", nlmsg_type, ifname? ifname: nil, ifindex, vni); - return; - } - SWSS_LOG_INFO("Op:%d VxLAN dev %s index:%d vni:%d", nlmsg_type, ifname? ifname: nil, ifindex, vni); - if (nlmsg_type == RTM_NEWLINK) - { - m_intf_info[ifindex].vni = vni; - m_intf_info[ifindex].ifname = ifname; - } - return; -} - -void FdbSync::onMsg(int nlmsg_type, struct nl_object *obj) -{ - if ((nlmsg_type != RTM_NEWLINK) && - (nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_DELNEIGH)) - { - SWSS_LOG_DEBUG("netlink: unhandled event: %d", nlmsg_type); - return; - } - if (nlmsg_type == RTM_NEWLINK) - { - onMsgLink(nlmsg_type, obj); - } - else - { - onMsgNbr(nlmsg_type, obj); - } -} - +#include +#include +#include +#include +#include +#include + +#include "logger.h" +#include "dbconnector.h" +#include "producerstatetable.h" +#include "ipaddress.h" +#include "netmsg.h" +#include "macaddress.h" +#include "exec.h" +#include "fdbsync.h" +#include "warm_restart.h" +#include "errno.h" + +using namespace std; +using namespace swss; + +#define VXLAN_BR_IF_NAME_PREFIX "Brvxlan" + +FdbSync::FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db) : + m_fdbTable(pipelineAppDB, APP_VXLAN_FDB_TABLE_NAME), + m_imetTable(pipelineAppDB, APP_VXLAN_REMOTE_VNI_TABLE_NAME), + m_fdbStateTable(stateDb, STATE_FDB_TABLE_NAME), + m_mclagRemoteFdbStateTable(stateDb, STATE_MCLAG_REMOTE_FDB_TABLE_NAME), + m_cfgEvpnNvoTable(config_db, CFG_VXLAN_EVPN_NVO_TABLE_NAME) +{ + m_AppRestartAssist = new AppRestartAssist(pipelineAppDB, "fdbsyncd", "swss", DEFAULT_FDBSYNC_WARMSTART_TIMER); + if (m_AppRestartAssist) + { + m_AppRestartAssist->registerAppTable(APP_VXLAN_FDB_TABLE_NAME, &m_fdbTable); + m_AppRestartAssist->registerAppTable(APP_VXLAN_REMOTE_VNI_TABLE_NAME, &m_imetTable); + } +} + +FdbSync::~FdbSync() +{ + if (m_AppRestartAssist) + { + delete m_AppRestartAssist; + } +} + +void FdbSync::processCfgEvpnNvo() +{ + std::deque entries; + m_cfgEvpnNvoTable.pops(entries); + bool lastNvoState = m_isEvpnNvoExist; + + for (auto entry: entries) + { + std::string op = kfvOp(entry); + + if (op == SET_COMMAND) + { + m_isEvpnNvoExist = true; + } + else if (op == DEL_COMMAND) + { + m_isEvpnNvoExist = false; + } + + if (lastNvoState != m_isEvpnNvoExist) + { + updateAllLocalMac(); + } + } + return; +} + +void FdbSync::updateAllLocalMac() +{ + for ( auto it = m_fdb_mac.begin(); it != m_fdb_mac.end(); ++it ) + { + if (m_isEvpnNvoExist) + { + /* Add the Local FDB entry into Kernel */ + addLocalMac(it->first, "replace"); + } + else + { + /* Delete the Local FDB entry from Kernel */ + addLocalMac(it->first, "del"); + } + } +} + +void FdbSync::processStateFdb() +{ + struct m_fdb_info info; + std::deque entries; + + m_fdbStateTable.pops(entries); + + int count =0 ; + for (auto entry: entries) + { + count++; + std::string key = kfvKey(entry); + std::string op = kfvOp(entry); + + std::size_t delimiter = key.find_first_of(":"); + auto vlan_name = key.substr(0, delimiter); + auto mac_address = key.substr(delimiter+1); + + info.vid = vlan_name; + info.mac = mac_address; + + if(op == "SET") + { + info.op_type = FDB_OPER_ADD ; + } + else + { + info.op_type = FDB_OPER_DEL ; + } + + SWSS_LOG_INFO("FDBSYNCD STATE FDB updates key=%s, operation=%s\n", key.c_str(), op.c_str()); + + for (auto i : kfvFieldsValues(entry)) + { + SWSS_LOG_INFO(" FDBSYNCD STATE FDB updates : " + "FvFiels %s, FvValues: %s \n", fvField(i).c_str(), fvValue(i).c_str()); + + if(fvField(i) == "port") + { + info.port_name = fvValue(i); + } + + if(fvField(i) == "type") + { + if(fvValue(i) == "dynamic") + { + info.type = FDB_TYPE_DYNAMIC; + } + else if (fvValue(i) == "static") + { + info.type = FDB_TYPE_STATIC; + } + } + } + + if (op != "SET" && macCheckSrcDB(&info) == false) + { + continue; + } + updateLocalMac(&info); + } +} + +void FdbSync::processStateMclagRemoteFdb() +{ + struct m_fdb_info info; + std::deque entries; + + m_mclagRemoteFdbStateTable.pops(entries); + + int count =0 ; + for (auto entry: entries) + { + count++; + std::string key = kfvKey(entry); + std::string op = kfvOp(entry); + + std::size_t delimiter = key.find_first_of(":"); + auto vlan_name = key.substr(0, delimiter); + auto mac_address = key.substr(delimiter+1); + + info.vid = vlan_name; + memcpy(info.mac, mac_address.c_str(),mac_address.length()); + + if(op == "SET") + { + info.op_type = FDB_OPER_ADD ; + } + else + { + info.op_type = FDB_OPER_DEL ; + } + + SWSS_LOG_INFO("FDBSYNCD STATE FDB updates key=%s, operation=%s\n", key.c_str(), op.c_str()); + + for (auto i : kfvFieldsValues(entry)) + { + SWSS_LOG_INFO(" FDBSYNCD STATE FDB updates : " + "FvFiels %s, FvValues: %s \n", fvField(i).c_str(), fvValue(i).c_str()); + + if(fvField(i) == "port") + { + memcpy(info.port_name, fvValue(i).c_str(), fvValue(i).length()); + } + + if(fvField(i) == "type") + { + if(fvValue(i) == "dynamic") + { + info.type = FDB_TYPE_DYNAMIC; + } + else if (fvValue(i) == "static") + { + info.type = FDB_TYPE_STATIC; + } + } + } + + if (op != "SET" && macCheckSrcDB(&info) == false) + { + continue; + } + updateMclagRemoteMac(&info); + } +} + +void FdbSync::macUpdateCache(struct m_fdb_info *info) +{ + string key = info->vid + ":" + info->mac; + m_fdb_mac[key].port_name = info->port_name; + m_fdb_mac[key].type = info->type; + + return; +} + +void FdbSync::macUpdateMclagRemoteCache(struct m_fdb_info *info) +{ + string key = info->vid + ":" + info->mac; + m_mclag_remote_fdb_mac[key].port_name = info->port_name; + m_mclag_remote_fdb_mac[key].type = info->type; + + return; +} + +bool FdbSync::macCheckSrcDB(struct m_fdb_info *info) +{ + string key = info->vid + ":" + info->mac; + if (m_fdb_mac.find(key) != m_fdb_mac.end()) + { + SWSS_LOG_INFO("DEL_KEY %s ", key.c_str()); + return true; + } + + return false; +} + +void FdbSync::macDelVxlanEntry(string auxkey, struct m_fdb_info *info) +{ + std::string vtep = m_mac[auxkey].vtep; + + const std::string cmds = std::string("") + + " bridge fdb del " + info->mac + " dev " + + m_mac[auxkey].ifname + " dst " + vtep + " vlan " + info->vid.substr(4); + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_INFO("Success cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + + return; +} + +void FdbSync::updateLocalMac (struct m_fdb_info *info) +{ + char *op; + char *type; + string port_name = ""; + string key = info->vid + ":" + info->mac; + short fdb_type; /*dynamic or static*/ + + if (info->op_type == FDB_OPER_ADD) + { + macUpdateCache(info); + op = "replace"; + port_name = info->port_name; + fdb_type = info->type; + /* Check if this vlan+key is also learned by vxlan neighbor then delete learned on */ + if (m_mac.find(key) != m_mac.end()) + { + macDelVxlanEntry(key, info); + SWSS_LOG_INFO("Local learn event deleting from VXLAN table DEL_KEY %s", key.c_str()); + macDelVxlan(key); + } + } + else + { + op = "del"; + port_name = m_fdb_mac[key].port_name; + fdb_type = m_fdb_mac[key].type; + m_fdb_mac.erase(key); + } + + if (!m_isEvpnNvoExist) + { + SWSS_LOG_INFO("Ignore kernel update EVPN NVO is not configured MAC %s", key.c_str()); + return; + } + + if (fdb_type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + op + " " + info->mac + " dev " + + port_name + " master " + type + " vlan " + info->vid.substr(4); + + std::string res; + int ret = swss::exec(cmds, res); + + SWSS_LOG_INFO("cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + + return; +} + +void FdbSync::addLocalMac(string key, string op) +{ + char *type; + string port_name = ""; + string mac = ""; + string vlan = ""; + size_t str_loc = string::npos; + + str_loc = key.find(":"); + if (str_loc == string::npos) + { + SWSS_LOG_ERROR("Local MAC issue with Key:%s", key.c_str()); + return; + } + vlan = key.substr(4, str_loc-4); + mac = key.substr(str_loc+1, std::string::npos); + + SWSS_LOG_INFO("Local route Vlan:%s MAC:%s Key:%s Op:%s", vlan.c_str(), mac.c_str(), key.c_str(), op.c_str()); + + if (m_fdb_mac.find(key)!=m_fdb_mac.end()) + { + port_name = m_fdb_mac[key].port_name; + if (port_name.empty()) + { + SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); + return; + } + + if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + op + " " + mac + " dev " + + port_name + " master " + type + " vlan " + vlan; + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_INFO("Config triggered cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + return; +} + +void FdbSync::updateMclagRemoteMac (struct m_fdb_info *info) +{ + char *op; + char *type; + string port_name = ""; + string key = info->vid + ":" + info->mac; + short fdb_type; /*dynamic or static*/ + + if (info->op_type == FDB_OPER_ADD) + { + macUpdateMclagRemoteCache(info); + op = "replace"; + port_name = info->port_name; + fdb_type = info->type; + } + else + { + op = "del"; + port_name = m_mclag_remote_fdb_mac[key].port_name; + fdb_type = m_mclag_remote_fdb_mac[key].type; + m_mclag_remote_fdb_mac.erase(key); + } + + if (fdb_type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + op + " " + info->mac + " dev " + + port_name + " master " + type + " vlan " + info->vid.substr(4); + + std::string res; + int ret = swss::exec(cmds, res); + + SWSS_LOG_INFO("cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + + return; +} + +/* + * This is a special case handling where mac is learned in the ASIC. + * Then MAC is learned in the Kernel, Since this mac is learned in the Kernel + * This MAC will age out, when MAC delete is received from the Kernel. + * If MAC is still present in the state DB cache then fdbsyncd will be + * re-programmed with MAC in the Kernel + */ +void FdbSync::macRefreshStateDB(int vlan, string kmac) +{ + string key = "Vlan" + to_string(vlan) + ":" + kmac; + char *type; + string port_name = ""; + + SWSS_LOG_INFO("Refreshing Vlan:%d MAC route MAC:%s Key %s", vlan, kmac.c_str(), key.c_str()); + + if (m_fdb_mac.find(key)!=m_fdb_mac.end()) + { + port_name = m_fdb_mac[key].port_name; + if (port_name.empty()) + { + SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); + return; + } + + if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + "replace" + " " + kmac + " dev " + + port_name + " master " + type + " vlan " + to_string(vlan); + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_INFO("Refreshing cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + return; +} + +bool FdbSync::checkImetExist(string key, uint32_t vni) +{ + if (m_imet_route.find(key) != m_imet_route.end()) + { + SWSS_LOG_INFO("IMET exist key:%s Vni:%d", key.c_str(), vni); + return false; + } + m_imet_route[key].vni = vni; + return true; +} + +bool FdbSync::checkDelImet(string key, uint32_t vni) +{ + int ret = false; + + SWSS_LOG_INFO("Del IMET key:%s Vni:%d", key.c_str(), vni); + if (m_imet_route.find(key) != m_imet_route.end()) + { + ret = true; + m_imet_route.erase(key); + } + return ret; +} + +void FdbSync::imetAddRoute(struct in_addr vtep, string vlan_str, uint32_t vni) +{ + string vlan_id = "Vlan" + vlan_str; + string key = vlan_id + ":" + inet_ntoa(vtep); + + if (!checkImetExist(key, vni)) + { + return; + } + + SWSS_LOG_INFO("%sIMET Add route key:%s vtep:%s %s", + m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", + key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); + + std::vector fvVector; + FieldValueTuple f("vni", to_string(vni)); + fvVector.push_back(f); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, false); + return; + } + + m_imetTable.set(key, fvVector); + return; +} + +void FdbSync::imetDelRoute(struct in_addr vtep, string vlan_str, uint32_t vni) +{ + string vlan_id = "Vlan" + vlan_str; + string key = vlan_id + ":" + inet_ntoa(vtep); + + if (!checkDelImet(key, vni)) + { + return; + } + + SWSS_LOG_INFO("%sIMET Del route key:%s vtep:%s %s", + m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", + key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); + + std::vector fvVector; + FieldValueTuple f("vni", to_string(vni)); + fvVector.push_back(f); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, true); + return; + } + + m_imetTable.del(key); + return; +} + +void FdbSync::macDelVxlanDB(string key) +{ + string vtep = m_mac[key].vtep; + string type; + string vni = to_string(m_mac[key].vni); + type = m_mac[key].type; + + std::vector fvVector; + FieldValueTuple rv("remote_vtep", vtep); + FieldValueTuple t("type", type); + FieldValueTuple v("vni", vni); + fvVector.push_back(rv); + fvVector.push_back(t); + fvVector.push_back(v); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, true); + return; + } + + SWSS_LOG_INFO("VXLAN_FDB_TABLE: DEL_KEY %s vtep:%s type:%s", key.c_str(), vtep.c_str(), type.c_str()); + m_fdbTable.del(key); + return; + +} + +void FdbSync::macAddVxlan(string key, struct in_addr vtep, string type, uint32_t vni, string intf_name) +{ + string svtep = inet_ntoa(vtep); + string svni = to_string(vni); + + /* Update the DB with Vxlan MAC */ + m_mac[key] = {svtep, type, vni, intf_name}; + + std::vector fvVector; + FieldValueTuple rv("remote_vtep", svtep); + FieldValueTuple t("type", type); + FieldValueTuple v("vni", svni); + fvVector.push_back(rv); + fvVector.push_back(t); + fvVector.push_back(v); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, false); + return; + } + + SWSS_LOG_INFO("VXLAN_FDB_TABLE: ADD_KEY %s vtep:%s type:%s", key.c_str(), svtep.c_str(), type.c_str()); + m_fdbTable.set(key, fvVector); + + return; +} + +void FdbSync::macDelVxlan(string key) +{ + if (m_mac.find(key) != m_mac.end()) + { + SWSS_LOG_INFO("DEL_KEY %s vtep:%s type:%s", key.c_str(), m_mac[key].vtep.c_str(), m_mac[key].type.c_str()); + macDelVxlanDB(key); + m_mac.erase(key); + } + return; +} + +void FdbSync::onMsgNbr(int nlmsg_type, struct nl_object *obj) +{ + char macStr[MAX_ADDR_SIZE + 1] = {0}; + struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj; + struct in_addr vtep = {0}; + int vlan = 0, ifindex = 0; + uint32_t vni = 0; + nl_addr *vtep_addr; + string ifname; + string key; + bool delete_key = false; + size_t str_loc = string::npos; + string type = ""; + string vlan_id = ""; + bool isVxlanIntf = false; + + if ((nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_GETNEIGH) && + (nlmsg_type != RTM_DELNEIGH)) + { + return; + } + + /* Only MAC route is to be supported */ + if (rtnl_neigh_get_family(neigh) != AF_BRIDGE) + { + return; + } + ifindex = rtnl_neigh_get_ifindex(neigh); + if (m_intf_info.find(ifindex) != m_intf_info.end()) + { + isVxlanIntf = true; + ifname = m_intf_info[ifindex].ifname; + } + + nl_addr2str(rtnl_neigh_get_lladdr(neigh), macStr, MAX_ADDR_SIZE); + + if (isVxlanIntf == false) + { + if (nlmsg_type != RTM_DELNEIGH) + { + return; + } + } + else + { + /* If this is for vnet bridge vxlan interface, then return */ + if (ifname.find(VXLAN_BR_IF_NAME_PREFIX) != string::npos) + { + return; + } + + /* VxLan netdevice should be in - format */ + str_loc = ifname.rfind("-"); + if (str_loc == string::npos) + { + return; + } + + vlan_id = "Vlan" + ifname.substr(str_loc+1, std::string::npos); + vni = m_intf_info[ifindex].vni; + } + + + if (isVxlanIntf == false) + { + vlan = rtnl_neigh_get_vlan(neigh); + if (m_isEvpnNvoExist) + { + macRefreshStateDB(vlan, macStr); + } + return; + } + + vtep_addr = rtnl_neigh_get_dst(neigh); + if (vtep_addr == NULL) + { + return; + } + else + { + /* Currently we only support ipv4 tunnel endpoints */ + vtep.s_addr = *(uint32_t *)nl_addr_get_binary_addr(vtep_addr); + SWSS_LOG_INFO("Tunnel IP %s Int%d", inet_ntoa(vtep), *(uint32_t *)nl_addr_get_binary_addr(vtep_addr)); + } + + int state = rtnl_neigh_get_state(neigh); + if ((nlmsg_type == RTM_DELNEIGH) || (state == NUD_INCOMPLETE) || + (state == NUD_FAILED)) + { + delete_key = true; + } + + if (state & NUD_NOARP) + { + /* This is a static route */ + type = "static"; + } + else + { + type = "dynamic"; + } + + /* Handling IMET routes */ + if (MacAddress(macStr) == MacAddress("00:00:00:00:00:00")) + { + if (vtep.s_addr) + { + string vlan_str = ifname.substr(str_loc+1, string::npos); + + if (!delete_key) + { + imetAddRoute(vtep, vlan_str, vni); + } + else + { + imetDelRoute(vtep, vlan_str, vni); + } + } + return; + } + + key+= vlan_id; + key+= ":"; + key+= macStr; + + if (!delete_key) + { + macAddVxlan(key, vtep, type, vni, ifname); + } + else + { + macDelVxlan(key); + } + return; +} + +void FdbSync::onMsgLink(int nlmsg_type, struct nl_object *obj) +{ + struct rtnl_link *link; + char *ifname = NULL; + char *nil = "NULL"; + int ifindex; + unsigned int vni; + + link = (struct rtnl_link *)obj; + ifname = rtnl_link_get_name(link); + ifindex = rtnl_link_get_ifindex(link); + if (rtnl_link_is_vxlan(link) == 0) + { + return; + } + + if (rtnl_link_vxlan_get_id(link, &vni) != 0) + { + SWSS_LOG_INFO("Op:%d VxLAN dev:%s index:%d vni:%d. Not found", nlmsg_type, ifname? ifname: nil, ifindex, vni); + return; + } + SWSS_LOG_INFO("Op:%d VxLAN dev %s index:%d vni:%d", nlmsg_type, ifname? ifname: nil, ifindex, vni); + if (nlmsg_type == RTM_NEWLINK) + { + m_intf_info[ifindex].vni = vni; + m_intf_info[ifindex].ifname = ifname; + } + return; +} + +void FdbSync::onMsg(int nlmsg_type, struct nl_object *obj) +{ + if ((nlmsg_type != RTM_NEWLINK) && + (nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_DELNEIGH)) + { + SWSS_LOG_DEBUG("netlink: unhandled event: %d", nlmsg_type); + return; + } + if (nlmsg_type == RTM_NEWLINK) + { + onMsgLink(nlmsg_type, obj); + } + else + { + onMsgNbr(nlmsg_type, obj); + } +} + + diff --git a/fdbsyncd/fdbsync.h b/fdbsyncd/fdbsync.h index c8248ffefb..e95421f27b 100644 --- a/fdbsyncd/fdbsync.h +++ b/fdbsyncd/fdbsync.h @@ -1,136 +1,149 @@ -#ifndef __FDBSYNC__ -#define __FDBSYNC__ - -#include -#include -#include "dbconnector.h" -#include "producerstatetable.h" -#include "subscriberstatetable.h" -#include "netmsg.h" -#include "warmRestartAssist.h" - -// The timeout value (in seconds) for fdbsyncd reconcilation logic -#define DEFAULT_FDBSYNC_WARMSTART_TIMER 30 - -namespace swss { - -enum FDB_OP_TYPE { - FDB_OPER_ADD =1, - FDB_OPER_DEL = 2, -}; - -enum FDB_TYPE { - FDB_TYPE_STATIC = 1, - FDB_TYPE_DYNAMIC = 2, -}; - -struct m_fdb_info -{ - std::string mac; - std::string vid; /*Store as Vlan */ - std::string port_name; - short type; /*dynamic or static*/ - short op_type; /*add or del*/ -}; - -class FdbSync : public NetMsg -{ -public: - enum { MAX_ADDR_SIZE = 64 }; - - FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db); - ~FdbSync(); - - virtual void onMsg(int nlmsg_type, struct nl_object *obj); - - bool isFdbRestoreDone(); - - AppRestartAssist *getRestartAssist() - { - return m_AppRestartAssist; - } - - SubscriberStateTable *getFdbStateTable() - { - return &m_fdbStateTable; - } - - SubscriberStateTable *getCfgEvpnNvoTable() - { - return &m_cfgEvpnNvoTable; - } - - void processStateFdb(); - - void processCfgEvpnNvo(); - - bool m_reconcileDone = false; - - bool m_isEvpnNvoExist = false; - -private: - ProducerStateTable m_fdbTable; - ProducerStateTable m_imetTable; - SubscriberStateTable m_fdbStateTable; - AppRestartAssist *m_AppRestartAssist; - SubscriberStateTable m_cfgEvpnNvoTable; - - struct m_local_fdb_info - { - std::string port_name; - short type;/*dynamic or static*/ - }; - std::unordered_map m_fdb_mac; - - void macDelVxlanEntry(std::string auxkey, struct m_fdb_info *info); - - void macUpdateCache(struct m_fdb_info *info); - - bool macCheckSrcDB(struct m_fdb_info *info); - - void updateLocalMac(struct m_fdb_info *info); - - void updateAllLocalMac(); - - void macRefreshStateDB(int vlan, std::string kmac); - - bool checkImetExist(std::string key, uint32_t vni); - - bool checkDelImet(std::string key, uint32_t vni); - - struct m_mac_info - { - std::string vtep; - std::string type; - unsigned int vni; - std::string ifname; - }; - std::unordered_map m_mac; - - struct m_imet_info - { - unsigned int vni; - }; - std::unordered_map m_imet_route; - - struct intf - { - std::string ifname; - unsigned int vni; - }; - std::unordered_map m_intf_info; - - void addLocalMac(std::string key, std::string op); - void macAddVxlan(std::string key, struct in_addr vtep, std::string type, uint32_t vni, std::string intf_name); - void macDelVxlan(std::string auxkey); - void macDelVxlanDB(std::string key); - void imetAddRoute(struct in_addr vtep, std::string ifname, uint32_t vni); - void imetDelRoute(struct in_addr vtep, std::string ifname, uint32_t vni); - void onMsgNbr(int nlmsg_type, struct nl_object *obj); - void onMsgLink(int nlmsg_type, struct nl_object *obj); -}; - -} - -#endif - +#ifndef __FDBSYNC__ +#define __FDBSYNC__ + +#include +#include +#include "dbconnector.h" +#include "producerstatetable.h" +#include "subscriberstatetable.h" +#include "netmsg.h" +#include "warmRestartAssist.h" + +// The timeout value (in seconds) for fdbsyncd reconcilation logic +#define DEFAULT_FDBSYNC_WARMSTART_TIMER 30 + +namespace swss { + +enum FDB_OP_TYPE { + FDB_OPER_ADD =1, + FDB_OPER_DEL = 2, +}; + +enum FDB_TYPE { + FDB_TYPE_STATIC = 1, + FDB_TYPE_DYNAMIC = 2, +}; + +struct m_fdb_info +{ + std::string mac; + std::string vid; /*Store as Vlan */ + std::string port_name; + short type; /*dynamic or static*/ + short op_type; /*add or del*/ +}; + +class FdbSync : public NetMsg +{ +public: + enum { MAX_ADDR_SIZE = 64 }; + + FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db); + ~FdbSync(); + + virtual void onMsg(int nlmsg_type, struct nl_object *obj); + + bool isFdbRestoreDone(); + + AppRestartAssist *getRestartAssist() + { + return m_AppRestartAssist; + } + + SubscriberStateTable *getFdbStateTable() + { + return &m_fdbStateTable; + } + + SubscriberStateTable *getMclagRemoteFdbStateTable() + { + return &m_mclagRemoteFdbStateTable; + } + + SubscriberStateTable *getCfgEvpnNvoTable() + { + return &m_cfgEvpnNvoTable; + } + + void processStateFdb(); + + void processStateMclagRemoteFdb(); + + void processCfgEvpnNvo(); + + bool m_reconcileDone = false; + + bool m_isEvpnNvoExist = false; + +private: + ProducerStateTable m_fdbTable; + ProducerStateTable m_imetTable; + SubscriberStateTable m_fdbStateTable; + SubscriberStateTable m_mclagRemoteFdbStateTable; + AppRestartAssist *m_AppRestartAssist; + SubscriberStateTable m_cfgEvpnNvoTable; + + struct m_local_fdb_info + { + std::string port_name; + short type;/*dynamic or static*/ + }; + std::unordered_map m_fdb_mac; + + std::unordered_map m_mclag_remote_fdb_mac; + + void macDelVxlanEntry(std::string auxkey, struct m_fdb_info *info); + + void macUpdateCache(struct m_fdb_info *info); + + bool macCheckSrcDB(struct m_fdb_info *info); + + void updateLocalMac(struct m_fdb_info *info); + + void updateAllLocalMac(); + + void macRefreshStateDB(int vlan, std::string kmac); + + void updateMclagRemoteMac(struct m_fdb_info *info); + + void macUpdateMclagRemoteCache(struct m_fdb_info *info); + + bool checkImetExist(std::string key, uint32_t vni); + + bool checkDelImet(std::string key, uint32_t vni); + + struct m_mac_info + { + std::string vtep; + std::string type; + unsigned int vni; + std::string ifname; + }; + std::unordered_map m_mac; + + struct m_imet_info + { + unsigned int vni; + }; + std::unordered_map m_imet_route; + + struct intf + { + std::string ifname; + unsigned int vni; + }; + std::unordered_map m_intf_info; + + void addLocalMac(std::string key, std::string op); + void macAddVxlan(std::string key, struct in_addr vtep, std::string type, uint32_t vni, std::string intf_name); + void macDelVxlan(std::string auxkey); + void macDelVxlanDB(std::string key); + void imetAddRoute(struct in_addr vtep, std::string ifname, uint32_t vni); + void imetDelRoute(struct in_addr vtep, std::string ifname, uint32_t vni); + void onMsgNbr(int nlmsg_type, struct nl_object *obj); + void onMsgLink(int nlmsg_type, struct nl_object *obj); +}; + +} + +#endif diff --git a/fdbsyncd/fdbsyncd.cpp b/fdbsyncd/fdbsyncd.cpp index eeffeb68c1..60e88477d1 100644 --- a/fdbsyncd/fdbsyncd.cpp +++ b/fdbsyncd/fdbsyncd.cpp @@ -1,105 +1,111 @@ -#include -#include -#include -#include -#include "logger.h" -#include "select.h" -#include "netdispatcher.h" -#include "netlink.h" -#include "fdbsyncd/fdbsync.h" - -using namespace std; -using namespace swss; - -int main(int argc, char **argv) -{ - Logger::linkToDbNative("fdbsyncd"); - - DBConnector appDb(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - RedisPipeline pipelineAppDB(&appDb); - DBConnector stateDb(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - DBConnector log_db(LOGLEVEL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - DBConnector config_db(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - - FdbSync sync(&pipelineAppDB, &stateDb, &config_db); - - NetDispatcher::getInstance().registerMessageHandler(RTM_NEWNEIGH, &sync); - NetDispatcher::getInstance().registerMessageHandler(RTM_DELNEIGH, &sync); - NetDispatcher::getInstance().registerMessageHandler(RTM_NEWLINK, &sync); - - while (1) - { - try - { - NetLink netlink; - Selectable *temps; - int ret; - Select s; - - using namespace std::chrono; - - /* - * If WarmStart is enabled, restore the VXLAN-FDB and VNI - * tables and start a reconcillation timer - */ - if (sync.getRestartAssist()->isWarmStartInProgress()) - { - sync.getRestartAssist()->readTablesToMap(); - SWSS_LOG_NOTICE("Starting ReconcileTimer"); - } - - netlink.registerGroup(RTNLGRP_LINK); - netlink.registerGroup(RTNLGRP_NEIGH); - SWSS_LOG_NOTICE("Listens to link and neigh messages..."); - netlink.dumpRequest(RTM_GETLINK); - s.addSelectable(&netlink); - ret = s.select(&temps, 1); - if (ret == Select::ERROR) - { - SWSS_LOG_ERROR("Error in RTM_GETLINK dump"); - } - - netlink.dumpRequest(RTM_GETNEIGH); - - s.addSelectable(sync.getFdbStateTable()); - s.addSelectable(sync.getCfgEvpnNvoTable()); - while (true) - { - s.select(&temps); - - if(temps == (Selectable *)sync.getFdbStateTable()) - { - sync.processStateFdb(); - } - else if (temps == (Selectable *)sync.getCfgEvpnNvoTable()) - { - sync.processCfgEvpnNvo(); - } - else - { - /* - * If warmstart is in progress, we check the reconcile timer, - * if timer expired, we stop the timer and start the reconcile process - */ - if (sync.getRestartAssist()->isWarmStartInProgress()) - { - if (sync.getRestartAssist()->checkReconcileTimer(temps)) - { - sync.m_reconcileDone = true; - sync.getRestartAssist()->stopReconcileTimer(s); - sync.getRestartAssist()->reconcile(); - SWSS_LOG_NOTICE("VXLAN FDB VNI Reconcillation Complete (Timer)"); - } - } - } - } - } - catch (const std::exception& e) - { - cout << "Exception \"" << e.what() << "\" had been thrown in deamon" << endl; - return 0; - } - } - - return 1; -} +#include +#include +#include +#include +#include "logger.h" +#include "select.h" +#include "netdispatcher.h" +#include "netlink.h" +#include "fdbsyncd/fdbsync.h" + +using namespace std; +using namespace swss; + +int main(int argc, char **argv) +{ + Logger::linkToDbNative("fdbsyncd"); + + DBConnector appDb(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + RedisPipeline pipelineAppDB(&appDb); + DBConnector stateDb(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + DBConnector log_db(LOGLEVEL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + DBConnector config_db(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + + FdbSync sync(&pipelineAppDB, &stateDb, &config_db); + + NetDispatcher::getInstance().registerMessageHandler(RTM_NEWNEIGH, &sync); + NetDispatcher::getInstance().registerMessageHandler(RTM_DELNEIGH, &sync); + NetDispatcher::getInstance().registerMessageHandler(RTM_NEWLINK, &sync); + + while (1) + { + try + { + NetLink netlink; + Selectable *temps; + int ret; + Select s; + + using namespace std::chrono; + + /* + * If WarmStart is enabled, restore the VXLAN-FDB and VNI + * tables and start a reconcillation timer + */ + if (sync.getRestartAssist()->isWarmStartInProgress()) + { + sync.getRestartAssist()->readTablesToMap(); + SWSS_LOG_NOTICE("Starting ReconcileTimer"); + } + + netlink.registerGroup(RTNLGRP_LINK); + netlink.registerGroup(RTNLGRP_NEIGH); + SWSS_LOG_NOTICE("Listens to link and neigh messages..."); + netlink.dumpRequest(RTM_GETLINK); + s.addSelectable(&netlink); + ret = s.select(&temps, 1); + if (ret == Select::ERROR) + { + SWSS_LOG_ERROR("Error in RTM_GETLINK dump"); + } + + netlink.dumpRequest(RTM_GETNEIGH); + + s.addSelectable(sync.getFdbStateTable()); + s.addSelectable(sync.getMclagRemoteFdbStateTable()); + s.addSelectable(sync.getCfgEvpnNvoTable()); + while (true) + { + s.select(&temps); + + if(temps == (Selectable *)sync.getFdbStateTable()) + { + sync.processStateFdb(); + } + else if(temps == (Selectable *)sync.getMclagRemoteFdbStateTable()) + { + sync.processStateMclagRemoteFdb(); + } + else if (temps == (Selectable *)sync.getCfgEvpnNvoTable()) + { + sync.processCfgEvpnNvo(); + } + else + { + /* + * If warmstart is in progress, we check the reconcile timer, + * if timer expired, we stop the timer and start the reconcile process + */ + if (sync.getRestartAssist()->isWarmStartInProgress()) + { + if (sync.getRestartAssist()->checkReconcileTimer(temps)) + { + sync.m_reconcileDone = true; + sync.getRestartAssist()->stopReconcileTimer(s); + sync.getRestartAssist()->reconcile(); + SWSS_LOG_NOTICE("VXLAN FDB VNI Reconcillation Complete (Timer)"); + } + } + } + } + } + catch (const std::exception& e) + { + cout << "Exception \"" << e.what() << "\" had been thrown in deamon" << endl; + return 0; + } + } + + return 1; +} + diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index ac3b8e30bf..7e54199dac 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -28,7 +28,6 @@ #include "countercheckorch.h" #include "notifier.h" #include "fdborch.h" -#include "redisclient.h" extern sai_switch_api_t *sai_switch_api; extern sai_bridge_api_t *sai_bridge_api; From 625befce704335e4fe88ce559b16876ef6c60da8 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Mon, 4 Jan 2021 16:26:19 -0800 Subject: [PATCH 08/54] Updating the change from PR1276 and PR885. --- fdbsyncd/fdbsync.cpp | 1607 +++++++++++++++++------------------ fdbsyncd/fdbsync.h | 299 +++---- fdbsyncd/fdbsyncd.cpp | 221 +++-- orchagent/notifications.cpp | 2 +- orchagent/portsorch.h | 2 +- 5 files changed, 1065 insertions(+), 1066 deletions(-) diff --git a/fdbsyncd/fdbsync.cpp b/fdbsyncd/fdbsync.cpp index d0b1d902d3..f2c4b1fb34 100644 --- a/fdbsyncd/fdbsync.cpp +++ b/fdbsyncd/fdbsync.cpp @@ -1,804 +1,803 @@ -#include -#include -#include -#include -#include -#include - -#include "logger.h" -#include "dbconnector.h" -#include "producerstatetable.h" -#include "ipaddress.h" -#include "netmsg.h" -#include "macaddress.h" -#include "exec.h" -#include "fdbsync.h" -#include "warm_restart.h" -#include "errno.h" - -using namespace std; -using namespace swss; - -#define VXLAN_BR_IF_NAME_PREFIX "Brvxlan" - -FdbSync::FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db) : - m_fdbTable(pipelineAppDB, APP_VXLAN_FDB_TABLE_NAME), - m_imetTable(pipelineAppDB, APP_VXLAN_REMOTE_VNI_TABLE_NAME), - m_fdbStateTable(stateDb, STATE_FDB_TABLE_NAME), - m_mclagRemoteFdbStateTable(stateDb, STATE_MCLAG_REMOTE_FDB_TABLE_NAME), - m_cfgEvpnNvoTable(config_db, CFG_VXLAN_EVPN_NVO_TABLE_NAME) -{ - m_AppRestartAssist = new AppRestartAssist(pipelineAppDB, "fdbsyncd", "swss", DEFAULT_FDBSYNC_WARMSTART_TIMER); - if (m_AppRestartAssist) - { - m_AppRestartAssist->registerAppTable(APP_VXLAN_FDB_TABLE_NAME, &m_fdbTable); - m_AppRestartAssist->registerAppTable(APP_VXLAN_REMOTE_VNI_TABLE_NAME, &m_imetTable); - } -} - -FdbSync::~FdbSync() -{ - if (m_AppRestartAssist) - { - delete m_AppRestartAssist; - } -} - -void FdbSync::processCfgEvpnNvo() -{ - std::deque entries; - m_cfgEvpnNvoTable.pops(entries); - bool lastNvoState = m_isEvpnNvoExist; - - for (auto entry: entries) - { - std::string op = kfvOp(entry); - - if (op == SET_COMMAND) - { - m_isEvpnNvoExist = true; - } - else if (op == DEL_COMMAND) - { - m_isEvpnNvoExist = false; - } - - if (lastNvoState != m_isEvpnNvoExist) - { - updateAllLocalMac(); - } - } - return; -} - -void FdbSync::updateAllLocalMac() -{ - for ( auto it = m_fdb_mac.begin(); it != m_fdb_mac.end(); ++it ) - { - if (m_isEvpnNvoExist) - { - /* Add the Local FDB entry into Kernel */ - addLocalMac(it->first, "replace"); - } - else - { - /* Delete the Local FDB entry from Kernel */ - addLocalMac(it->first, "del"); - } - } -} - -void FdbSync::processStateFdb() -{ - struct m_fdb_info info; - std::deque entries; - - m_fdbStateTable.pops(entries); - - int count =0 ; - for (auto entry: entries) - { - count++; - std::string key = kfvKey(entry); - std::string op = kfvOp(entry); - - std::size_t delimiter = key.find_first_of(":"); - auto vlan_name = key.substr(0, delimiter); - auto mac_address = key.substr(delimiter+1); - - info.vid = vlan_name; - info.mac = mac_address; - - if(op == "SET") - { - info.op_type = FDB_OPER_ADD ; - } - else - { - info.op_type = FDB_OPER_DEL ; - } - - SWSS_LOG_INFO("FDBSYNCD STATE FDB updates key=%s, operation=%s\n", key.c_str(), op.c_str()); - - for (auto i : kfvFieldsValues(entry)) - { - SWSS_LOG_INFO(" FDBSYNCD STATE FDB updates : " - "FvFiels %s, FvValues: %s \n", fvField(i).c_str(), fvValue(i).c_str()); - - if(fvField(i) == "port") - { - info.port_name = fvValue(i); - } - - if(fvField(i) == "type") - { - if(fvValue(i) == "dynamic") - { - info.type = FDB_TYPE_DYNAMIC; - } - else if (fvValue(i) == "static") - { - info.type = FDB_TYPE_STATIC; - } - } - } - - if (op != "SET" && macCheckSrcDB(&info) == false) - { - continue; - } - updateLocalMac(&info); - } -} - -void FdbSync::processStateMclagRemoteFdb() -{ - struct m_fdb_info info; - std::deque entries; - - m_mclagRemoteFdbStateTable.pops(entries); - - int count =0 ; - for (auto entry: entries) - { - count++; - std::string key = kfvKey(entry); - std::string op = kfvOp(entry); - - std::size_t delimiter = key.find_first_of(":"); - auto vlan_name = key.substr(0, delimiter); - auto mac_address = key.substr(delimiter+1); - - info.vid = vlan_name; - memcpy(info.mac, mac_address.c_str(),mac_address.length()); - - if(op == "SET") - { - info.op_type = FDB_OPER_ADD ; - } - else - { - info.op_type = FDB_OPER_DEL ; - } - - SWSS_LOG_INFO("FDBSYNCD STATE FDB updates key=%s, operation=%s\n", key.c_str(), op.c_str()); - - for (auto i : kfvFieldsValues(entry)) - { - SWSS_LOG_INFO(" FDBSYNCD STATE FDB updates : " - "FvFiels %s, FvValues: %s \n", fvField(i).c_str(), fvValue(i).c_str()); - - if(fvField(i) == "port") - { - memcpy(info.port_name, fvValue(i).c_str(), fvValue(i).length()); - } - - if(fvField(i) == "type") - { - if(fvValue(i) == "dynamic") - { - info.type = FDB_TYPE_DYNAMIC; - } - else if (fvValue(i) == "static") - { - info.type = FDB_TYPE_STATIC; - } - } - } - - if (op != "SET" && macCheckSrcDB(&info) == false) - { - continue; - } - updateMclagRemoteMac(&info); - } -} - -void FdbSync::macUpdateCache(struct m_fdb_info *info) -{ - string key = info->vid + ":" + info->mac; - m_fdb_mac[key].port_name = info->port_name; - m_fdb_mac[key].type = info->type; - - return; -} - -void FdbSync::macUpdateMclagRemoteCache(struct m_fdb_info *info) -{ - string key = info->vid + ":" + info->mac; - m_mclag_remote_fdb_mac[key].port_name = info->port_name; - m_mclag_remote_fdb_mac[key].type = info->type; - - return; -} - -bool FdbSync::macCheckSrcDB(struct m_fdb_info *info) -{ - string key = info->vid + ":" + info->mac; - if (m_fdb_mac.find(key) != m_fdb_mac.end()) - { - SWSS_LOG_INFO("DEL_KEY %s ", key.c_str()); - return true; - } - - return false; -} - -void FdbSync::macDelVxlanEntry(string auxkey, struct m_fdb_info *info) -{ - std::string vtep = m_mac[auxkey].vtep; - - const std::string cmds = std::string("") - + " bridge fdb del " + info->mac + " dev " - + m_mac[auxkey].ifname + " dst " + vtep + " vlan " + info->vid.substr(4); - - std::string res; - int ret = swss::exec(cmds, res); - if (ret != 0) - { - SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - - SWSS_LOG_INFO("Success cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - - return; -} - -void FdbSync::updateLocalMac (struct m_fdb_info *info) -{ - char *op; - char *type; - string port_name = ""; - string key = info->vid + ":" + info->mac; - short fdb_type; /*dynamic or static*/ - - if (info->op_type == FDB_OPER_ADD) - { - macUpdateCache(info); - op = "replace"; - port_name = info->port_name; - fdb_type = info->type; - /* Check if this vlan+key is also learned by vxlan neighbor then delete learned on */ - if (m_mac.find(key) != m_mac.end()) - { - macDelVxlanEntry(key, info); - SWSS_LOG_INFO("Local learn event deleting from VXLAN table DEL_KEY %s", key.c_str()); - macDelVxlan(key); - } - } - else - { - op = "del"; - port_name = m_fdb_mac[key].port_name; - fdb_type = m_fdb_mac[key].type; - m_fdb_mac.erase(key); - } - - if (!m_isEvpnNvoExist) - { - SWSS_LOG_INFO("Ignore kernel update EVPN NVO is not configured MAC %s", key.c_str()); - return; - } - - if (fdb_type == FDB_TYPE_DYNAMIC) - { - type = "dynamic"; - } - else - { - type = "static"; - } - - const std::string cmds = std::string("") - + " bridge fdb " + op + " " + info->mac + " dev " - + port_name + " master " + type + " vlan " + info->vid.substr(4); - - std::string res; - int ret = swss::exec(cmds, res); - - SWSS_LOG_INFO("cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - - return; -} - -void FdbSync::addLocalMac(string key, string op) -{ - char *type; - string port_name = ""; - string mac = ""; - string vlan = ""; - size_t str_loc = string::npos; - - str_loc = key.find(":"); - if (str_loc == string::npos) - { - SWSS_LOG_ERROR("Local MAC issue with Key:%s", key.c_str()); - return; - } - vlan = key.substr(4, str_loc-4); - mac = key.substr(str_loc+1, std::string::npos); - - SWSS_LOG_INFO("Local route Vlan:%s MAC:%s Key:%s Op:%s", vlan.c_str(), mac.c_str(), key.c_str(), op.c_str()); - - if (m_fdb_mac.find(key)!=m_fdb_mac.end()) - { - port_name = m_fdb_mac[key].port_name; - if (port_name.empty()) - { - SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); - return; - } - - if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) - { - type = "dynamic"; - } - else - { - type = "static"; - } - - const std::string cmds = std::string("") - + " bridge fdb " + op + " " + mac + " dev " - + port_name + " master " + type + " vlan " + vlan; - - std::string res; - int ret = swss::exec(cmds, res); - if (ret != 0) - { - SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - - SWSS_LOG_INFO("Config triggered cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - return; -} - -void FdbSync::updateMclagRemoteMac (struct m_fdb_info *info) -{ - char *op; - char *type; - string port_name = ""; - string key = info->vid + ":" + info->mac; - short fdb_type; /*dynamic or static*/ - - if (info->op_type == FDB_OPER_ADD) - { - macUpdateMclagRemoteCache(info); - op = "replace"; - port_name = info->port_name; - fdb_type = info->type; - } - else - { - op = "del"; - port_name = m_mclag_remote_fdb_mac[key].port_name; - fdb_type = m_mclag_remote_fdb_mac[key].type; - m_mclag_remote_fdb_mac.erase(key); - } - - if (fdb_type == FDB_TYPE_DYNAMIC) - { - type = "dynamic"; - } - else - { - type = "static"; - } - - const std::string cmds = std::string("") - + " bridge fdb " + op + " " + info->mac + " dev " - + port_name + " master " + type + " vlan " + info->vid.substr(4); - - std::string res; - int ret = swss::exec(cmds, res); - - SWSS_LOG_INFO("cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - - return; -} - -/* - * This is a special case handling where mac is learned in the ASIC. - * Then MAC is learned in the Kernel, Since this mac is learned in the Kernel - * This MAC will age out, when MAC delete is received from the Kernel. - * If MAC is still present in the state DB cache then fdbsyncd will be - * re-programmed with MAC in the Kernel - */ -void FdbSync::macRefreshStateDB(int vlan, string kmac) -{ - string key = "Vlan" + to_string(vlan) + ":" + kmac; - char *type; - string port_name = ""; - - SWSS_LOG_INFO("Refreshing Vlan:%d MAC route MAC:%s Key %s", vlan, kmac.c_str(), key.c_str()); - - if (m_fdb_mac.find(key)!=m_fdb_mac.end()) - { - port_name = m_fdb_mac[key].port_name; - if (port_name.empty()) - { - SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); - return; - } - - if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) - { - type = "dynamic"; - } - else - { - type = "static"; - } - - const std::string cmds = std::string("") - + " bridge fdb " + "replace" + " " + kmac + " dev " - + port_name + " master " + type + " vlan " + to_string(vlan); - - std::string res; - int ret = swss::exec(cmds, res); - if (ret != 0) - { - SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - - SWSS_LOG_INFO("Refreshing cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - return; -} - -bool FdbSync::checkImetExist(string key, uint32_t vni) -{ - if (m_imet_route.find(key) != m_imet_route.end()) - { - SWSS_LOG_INFO("IMET exist key:%s Vni:%d", key.c_str(), vni); - return false; - } - m_imet_route[key].vni = vni; - return true; -} - -bool FdbSync::checkDelImet(string key, uint32_t vni) -{ - int ret = false; - - SWSS_LOG_INFO("Del IMET key:%s Vni:%d", key.c_str(), vni); - if (m_imet_route.find(key) != m_imet_route.end()) - { - ret = true; - m_imet_route.erase(key); - } - return ret; -} - -void FdbSync::imetAddRoute(struct in_addr vtep, string vlan_str, uint32_t vni) -{ - string vlan_id = "Vlan" + vlan_str; - string key = vlan_id + ":" + inet_ntoa(vtep); - - if (!checkImetExist(key, vni)) - { - return; - } - - SWSS_LOG_INFO("%sIMET Add route key:%s vtep:%s %s", - m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", - key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); - - std::vector fvVector; - FieldValueTuple f("vni", to_string(vni)); - fvVector.push_back(f); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, false); - return; - } - - m_imetTable.set(key, fvVector); - return; -} - -void FdbSync::imetDelRoute(struct in_addr vtep, string vlan_str, uint32_t vni) -{ - string vlan_id = "Vlan" + vlan_str; - string key = vlan_id + ":" + inet_ntoa(vtep); - - if (!checkDelImet(key, vni)) - { - return; - } - - SWSS_LOG_INFO("%sIMET Del route key:%s vtep:%s %s", - m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", - key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); - - std::vector fvVector; - FieldValueTuple f("vni", to_string(vni)); - fvVector.push_back(f); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, true); - return; - } - - m_imetTable.del(key); - return; -} - -void FdbSync::macDelVxlanDB(string key) -{ - string vtep = m_mac[key].vtep; - string type; - string vni = to_string(m_mac[key].vni); - type = m_mac[key].type; - - std::vector fvVector; - FieldValueTuple rv("remote_vtep", vtep); - FieldValueTuple t("type", type); - FieldValueTuple v("vni", vni); - fvVector.push_back(rv); - fvVector.push_back(t); - fvVector.push_back(v); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, true); - return; - } - - SWSS_LOG_INFO("VXLAN_FDB_TABLE: DEL_KEY %s vtep:%s type:%s", key.c_str(), vtep.c_str(), type.c_str()); - m_fdbTable.del(key); - return; - -} - -void FdbSync::macAddVxlan(string key, struct in_addr vtep, string type, uint32_t vni, string intf_name) -{ - string svtep = inet_ntoa(vtep); - string svni = to_string(vni); - - /* Update the DB with Vxlan MAC */ - m_mac[key] = {svtep, type, vni, intf_name}; - - std::vector fvVector; - FieldValueTuple rv("remote_vtep", svtep); - FieldValueTuple t("type", type); - FieldValueTuple v("vni", svni); - fvVector.push_back(rv); - fvVector.push_back(t); - fvVector.push_back(v); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, false); - return; - } - - SWSS_LOG_INFO("VXLAN_FDB_TABLE: ADD_KEY %s vtep:%s type:%s", key.c_str(), svtep.c_str(), type.c_str()); - m_fdbTable.set(key, fvVector); - - return; -} - -void FdbSync::macDelVxlan(string key) -{ - if (m_mac.find(key) != m_mac.end()) - { - SWSS_LOG_INFO("DEL_KEY %s vtep:%s type:%s", key.c_str(), m_mac[key].vtep.c_str(), m_mac[key].type.c_str()); - macDelVxlanDB(key); - m_mac.erase(key); - } - return; -} - -void FdbSync::onMsgNbr(int nlmsg_type, struct nl_object *obj) -{ - char macStr[MAX_ADDR_SIZE + 1] = {0}; - struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj; - struct in_addr vtep = {0}; - int vlan = 0, ifindex = 0; - uint32_t vni = 0; - nl_addr *vtep_addr; - string ifname; - string key; - bool delete_key = false; - size_t str_loc = string::npos; - string type = ""; - string vlan_id = ""; - bool isVxlanIntf = false; - - if ((nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_GETNEIGH) && - (nlmsg_type != RTM_DELNEIGH)) - { - return; - } - - /* Only MAC route is to be supported */ - if (rtnl_neigh_get_family(neigh) != AF_BRIDGE) - { - return; - } - ifindex = rtnl_neigh_get_ifindex(neigh); - if (m_intf_info.find(ifindex) != m_intf_info.end()) - { - isVxlanIntf = true; - ifname = m_intf_info[ifindex].ifname; - } - - nl_addr2str(rtnl_neigh_get_lladdr(neigh), macStr, MAX_ADDR_SIZE); - - if (isVxlanIntf == false) - { - if (nlmsg_type != RTM_DELNEIGH) - { - return; - } - } - else - { - /* If this is for vnet bridge vxlan interface, then return */ - if (ifname.find(VXLAN_BR_IF_NAME_PREFIX) != string::npos) - { - return; - } - - /* VxLan netdevice should be in - format */ - str_loc = ifname.rfind("-"); - if (str_loc == string::npos) - { - return; - } - - vlan_id = "Vlan" + ifname.substr(str_loc+1, std::string::npos); - vni = m_intf_info[ifindex].vni; - } - - - if (isVxlanIntf == false) - { - vlan = rtnl_neigh_get_vlan(neigh); - if (m_isEvpnNvoExist) - { - macRefreshStateDB(vlan, macStr); - } - return; - } - - vtep_addr = rtnl_neigh_get_dst(neigh); - if (vtep_addr == NULL) - { - return; - } - else - { - /* Currently we only support ipv4 tunnel endpoints */ - vtep.s_addr = *(uint32_t *)nl_addr_get_binary_addr(vtep_addr); - SWSS_LOG_INFO("Tunnel IP %s Int%d", inet_ntoa(vtep), *(uint32_t *)nl_addr_get_binary_addr(vtep_addr)); - } - - int state = rtnl_neigh_get_state(neigh); - if ((nlmsg_type == RTM_DELNEIGH) || (state == NUD_INCOMPLETE) || - (state == NUD_FAILED)) - { - delete_key = true; - } - - if (state & NUD_NOARP) - { - /* This is a static route */ - type = "static"; - } - else - { - type = "dynamic"; - } - - /* Handling IMET routes */ - if (MacAddress(macStr) == MacAddress("00:00:00:00:00:00")) - { - if (vtep.s_addr) - { - string vlan_str = ifname.substr(str_loc+1, string::npos); - - if (!delete_key) - { - imetAddRoute(vtep, vlan_str, vni); - } - else - { - imetDelRoute(vtep, vlan_str, vni); - } - } - return; - } - - key+= vlan_id; - key+= ":"; - key+= macStr; - - if (!delete_key) - { - macAddVxlan(key, vtep, type, vni, ifname); - } - else - { - macDelVxlan(key); - } - return; -} - -void FdbSync::onMsgLink(int nlmsg_type, struct nl_object *obj) -{ - struct rtnl_link *link; - char *ifname = NULL; - char *nil = "NULL"; - int ifindex; - unsigned int vni; - - link = (struct rtnl_link *)obj; - ifname = rtnl_link_get_name(link); - ifindex = rtnl_link_get_ifindex(link); - if (rtnl_link_is_vxlan(link) == 0) - { - return; - } - - if (rtnl_link_vxlan_get_id(link, &vni) != 0) - { - SWSS_LOG_INFO("Op:%d VxLAN dev:%s index:%d vni:%d. Not found", nlmsg_type, ifname? ifname: nil, ifindex, vni); - return; - } - SWSS_LOG_INFO("Op:%d VxLAN dev %s index:%d vni:%d", nlmsg_type, ifname? ifname: nil, ifindex, vni); - if (nlmsg_type == RTM_NEWLINK) - { - m_intf_info[ifindex].vni = vni; - m_intf_info[ifindex].ifname = ifname; - } - return; -} - -void FdbSync::onMsg(int nlmsg_type, struct nl_object *obj) -{ - if ((nlmsg_type != RTM_NEWLINK) && - (nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_DELNEIGH)) - { - SWSS_LOG_DEBUG("netlink: unhandled event: %d", nlmsg_type); - return; - } - if (nlmsg_type == RTM_NEWLINK) - { - onMsgLink(nlmsg_type, obj); - } - else - { - onMsgNbr(nlmsg_type, obj); - } -} - - +#include +#include +#include +#include +#include +#include + +#include "logger.h" +#include "dbconnector.h" +#include "producerstatetable.h" +#include "ipaddress.h" +#include "netmsg.h" +#include "macaddress.h" +#include "exec.h" +#include "fdbsync.h" +#include "warm_restart.h" +#include "errno.h" + +using namespace std; +using namespace swss; + +#define VXLAN_BR_IF_NAME_PREFIX "Brvxlan" + +FdbSync::FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db) : + m_fdbTable(pipelineAppDB, APP_VXLAN_FDB_TABLE_NAME), + m_imetTable(pipelineAppDB, APP_VXLAN_REMOTE_VNI_TABLE_NAME), + m_fdbStateTable(stateDb, STATE_FDB_TABLE_NAME), + m_mclagRemoteFdbStateTable(stateDb, STATE_MCLAG_REMOTE_FDB_TABLE_NAME), + m_cfgEvpnNvoTable(config_db, CFG_VXLAN_EVPN_NVO_TABLE_NAME) +{ + m_AppRestartAssist = new AppRestartAssist(pipelineAppDB, "fdbsyncd", "swss", DEFAULT_FDBSYNC_WARMSTART_TIMER); + if (m_AppRestartAssist) + { + m_AppRestartAssist->registerAppTable(APP_VXLAN_FDB_TABLE_NAME, &m_fdbTable); + m_AppRestartAssist->registerAppTable(APP_VXLAN_REMOTE_VNI_TABLE_NAME, &m_imetTable); + } +} + +FdbSync::~FdbSync() +{ + if (m_AppRestartAssist) + { + delete m_AppRestartAssist; + } +} + +void FdbSync::processCfgEvpnNvo() +{ + std::deque entries; + m_cfgEvpnNvoTable.pops(entries); + bool lastNvoState = m_isEvpnNvoExist; + + for (auto entry: entries) + { + std::string op = kfvOp(entry); + + if (op == SET_COMMAND) + { + m_isEvpnNvoExist = true; + } + else if (op == DEL_COMMAND) + { + m_isEvpnNvoExist = false; + } + + if (lastNvoState != m_isEvpnNvoExist) + { + updateAllLocalMac(); + } + } + return; +} + +void FdbSync::updateAllLocalMac() +{ + for ( auto it = m_fdb_mac.begin(); it != m_fdb_mac.end(); ++it ) + { + if (m_isEvpnNvoExist) + { + /* Add the Local FDB entry into Kernel */ + addLocalMac(it->first, "replace"); + } + else + { + /* Delete the Local FDB entry from Kernel */ + addLocalMac(it->first, "del"); + } + } +} + +void FdbSync::processStateFdb() +{ + struct m_fdb_info info; + std::deque entries; + + m_fdbStateTable.pops(entries); + + int count =0 ; + for (auto entry: entries) + { + count++; + std::string key = kfvKey(entry); + std::string op = kfvOp(entry); + + std::size_t delimiter = key.find_first_of(":"); + auto vlan_name = key.substr(0, delimiter); + auto mac_address = key.substr(delimiter+1); + + info.vid = vlan_name; + info.mac = mac_address; + + if(op == "SET") + { + info.op_type = FDB_OPER_ADD ; + } + else + { + info.op_type = FDB_OPER_DEL ; + } + + SWSS_LOG_INFO("FDBSYNCD STATE FDB updates key=%s, operation=%s\n", key.c_str(), op.c_str()); + + for (auto i : kfvFieldsValues(entry)) + { + SWSS_LOG_INFO(" FDBSYNCD STATE FDB updates : " + "FvFiels %s, FvValues: %s \n", fvField(i).c_str(), fvValue(i).c_str()); + + if(fvField(i) == "port") + { + info.port_name = fvValue(i); + } + + if(fvField(i) == "type") + { + if(fvValue(i) == "dynamic") + { + info.type = FDB_TYPE_DYNAMIC; + } + else if (fvValue(i) == "static") + { + info.type = FDB_TYPE_STATIC; + } + } + } + + if (op != "SET" && macCheckSrcDB(&info) == false) + { + continue; + } + updateLocalMac(&info); + } +} + +void FdbSync::processStateMclagRemoteFdb() +{ + struct m_fdb_info info; + std::deque entries; + + m_mclagRemoteFdbStateTable.pops(entries); + + int count =0 ; + for (auto entry: entries) + { + count++; + std::string key = kfvKey(entry); + std::string op = kfvOp(entry); + + std::size_t delimiter = key.find_first_of(":"); + auto vlan_name = key.substr(0, delimiter); + auto mac_address = key.substr(delimiter+1); + + info.vid = vlan_name; + memcpy(info.mac, mac_address.c_str(),mac_address.length()); + + if(op == "SET") + { + info.op_type = FDB_OPER_ADD ; + } + else + { + info.op_type = FDB_OPER_DEL ; + } + + SWSS_LOG_INFO("FDBSYNCD STATE FDB updates key=%s, operation=%s\n", key.c_str(), op.c_str()); + + for (auto i : kfvFieldsValues(entry)) + { + SWSS_LOG_INFO(" FDBSYNCD STATE FDB updates : " + "FvFiels %s, FvValues: %s \n", fvField(i).c_str(), fvValue(i).c_str()); + + if(fvField(i) == "port") + { + memcpy(info.port_name, fvValue(i).c_str(), fvValue(i).length()); + } + + if(fvField(i) == "type") + { + if(fvValue(i) == "dynamic") + { + info.type = FDB_TYPE_DYNAMIC; + } + else if (fvValue(i) == "static") + { + info.type = FDB_TYPE_STATIC; + } + } + } + + if (op != "SET" && macCheckSrcDB(&info) == false) + { + continue; + } + updateMclagRemoteMac(&info); + } +} + +void FdbSync::macUpdateCache(struct m_fdb_info *info) +{ + string key = info->vid + ":" + info->mac; + m_fdb_mac[key].port_name = info->port_name; + m_fdb_mac[key].type = info->type; + + return; +} + +void FdbSync::macUpdateMclagRemoteCache(struct m_fdb_info *info) +{ + string key = info->vid + ":" + info->mac; + m_mclag_remote_fdb_mac[key].port_name = info->port_name; + m_mclag_remote_fdb_mac[key].type = info->type; + + return; +} + +bool FdbSync::macCheckSrcDB(struct m_fdb_info *info) +{ + string key = info->vid + ":" + info->mac; + if (m_fdb_mac.find(key) != m_fdb_mac.end()) + { + SWSS_LOG_INFO("DEL_KEY %s ", key.c_str()); + return true; + } + + return false; +} + +void FdbSync::macDelVxlanEntry(string auxkey, struct m_fdb_info *info) +{ + std::string vtep = m_mac[auxkey].vtep; + + const std::string cmds = std::string("") + + " bridge fdb del " + info->mac + " dev " + + m_mac[auxkey].ifname + " dst " + vtep + " vlan " + info->vid.substr(4); + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_INFO("Success cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + + return; +} + +void FdbSync::updateLocalMac (struct m_fdb_info *info) +{ + char *op; + char *type; + string port_name = ""; + string key = info->vid + ":" + info->mac; + short fdb_type; /*dynamic or static*/ + + if (info->op_type == FDB_OPER_ADD) + { + macUpdateCache(info); + op = "replace"; + port_name = info->port_name; + fdb_type = info->type; + /* Check if this vlan+key is also learned by vxlan neighbor then delete learned on */ + if (m_mac.find(key) != m_mac.end()) + { + macDelVxlanEntry(key, info); + SWSS_LOG_INFO("Local learn event deleting from VXLAN table DEL_KEY %s", key.c_str()); + macDelVxlan(key); + } + } + else + { + op = "del"; + port_name = m_fdb_mac[key].port_name; + fdb_type = m_fdb_mac[key].type; + m_fdb_mac.erase(key); + } + + if (!m_isEvpnNvoExist) + { + SWSS_LOG_INFO("Ignore kernel update EVPN NVO is not configured MAC %s", key.c_str()); + return; + } + + if (fdb_type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + op + " " + info->mac + " dev " + + port_name + " master " + type + " vlan " + info->vid.substr(4); + + std::string res; + int ret = swss::exec(cmds, res); + + SWSS_LOG_INFO("cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + + return; +} + +void FdbSync::addLocalMac(string key, string op) +{ + char *type; + string port_name = ""; + string mac = ""; + string vlan = ""; + size_t str_loc = string::npos; + + str_loc = key.find(":"); + if (str_loc == string::npos) + { + SWSS_LOG_ERROR("Local MAC issue with Key:%s", key.c_str()); + return; + } + vlan = key.substr(4, str_loc-4); + mac = key.substr(str_loc+1, std::string::npos); + + SWSS_LOG_INFO("Local route Vlan:%s MAC:%s Key:%s Op:%s", vlan.c_str(), mac.c_str(), key.c_str(), op.c_str()); + + if (m_fdb_mac.find(key)!=m_fdb_mac.end()) + { + port_name = m_fdb_mac[key].port_name; + if (port_name.empty()) + { + SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); + return; + } + + if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + op + " " + mac + " dev " + + port_name + " master " + type + " vlan " + vlan; + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_INFO("Config triggered cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + return; +} + +void FdbSync::updateMclagRemoteMac (struct m_fdb_info *info) +{ + char *op; + char *type; + string port_name = ""; + string key = info->vid + ":" + info->mac; + short fdb_type; /*dynamic or static*/ + + if (info->op_type == FDB_OPER_ADD) + { + macUpdateMclagRemoteCache(info); + op = "replace"; + port_name = info->port_name; + fdb_type = info->type; + } + else + { + op = "del"; + port_name = m_mclag_remote_fdb_mac[key].port_name; + fdb_type = m_mclag_remote_fdb_mac[key].type; + m_mclag_remote_fdb_mac.erase(key); + } + + if (fdb_type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + op + " " + info->mac + " dev " + + port_name + " master " + type + " vlan " + info->vid.substr(4); + + std::string res; + int ret = swss::exec(cmds, res); + + SWSS_LOG_INFO("cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + + return; +} + +/* + * This is a special case handling where mac is learned in the ASIC. + * Then MAC is learned in the Kernel, Since this mac is learned in the Kernel + * This MAC will age out, when MAC delete is received from the Kernel. + * If MAC is still present in the state DB cache then fdbsyncd will be + * re-programmed with MAC in the Kernel + */ +void FdbSync::macRefreshStateDB(int vlan, string kmac) +{ + string key = "Vlan" + to_string(vlan) + ":" + kmac; + char *type; + string port_name = ""; + + SWSS_LOG_INFO("Refreshing Vlan:%d MAC route MAC:%s Key %s", vlan, kmac.c_str(), key.c_str()); + + if (m_fdb_mac.find(key)!=m_fdb_mac.end()) + { + port_name = m_fdb_mac[key].port_name; + if (port_name.empty()) + { + SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); + return; + } + + if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + "replace" + " " + kmac + " dev " + + port_name + " master " + type + " vlan " + to_string(vlan); + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_INFO("Refreshing cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + return; +} + +bool FdbSync::checkImetExist(string key, uint32_t vni) +{ + if (m_imet_route.find(key) != m_imet_route.end()) + { + SWSS_LOG_INFO("IMET exist key:%s Vni:%d", key.c_str(), vni); + return false; + } + m_imet_route[key].vni = vni; + return true; +} + +bool FdbSync::checkDelImet(string key, uint32_t vni) +{ + int ret = false; + + SWSS_LOG_INFO("Del IMET key:%s Vni:%d", key.c_str(), vni); + if (m_imet_route.find(key) != m_imet_route.end()) + { + ret = true; + m_imet_route.erase(key); + } + return ret; +} + +void FdbSync::imetAddRoute(struct in_addr vtep, string vlan_str, uint32_t vni) +{ + string vlan_id = "Vlan" + vlan_str; + string key = vlan_id + ":" + inet_ntoa(vtep); + + if (!checkImetExist(key, vni)) + { + return; + } + + SWSS_LOG_INFO("%sIMET Add route key:%s vtep:%s %s", + m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", + key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); + + std::vector fvVector; + FieldValueTuple f("vni", to_string(vni)); + fvVector.push_back(f); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, false); + return; + } + + m_imetTable.set(key, fvVector); + return; +} + +void FdbSync::imetDelRoute(struct in_addr vtep, string vlan_str, uint32_t vni) +{ + string vlan_id = "Vlan" + vlan_str; + string key = vlan_id + ":" + inet_ntoa(vtep); + + if (!checkDelImet(key, vni)) + { + return; + } + + SWSS_LOG_INFO("%sIMET Del route key:%s vtep:%s %s", + m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", + key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); + + std::vector fvVector; + FieldValueTuple f("vni", to_string(vni)); + fvVector.push_back(f); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, true); + return; + } + + m_imetTable.del(key); + return; +} + +void FdbSync::macDelVxlanDB(string key) +{ + string vtep = m_mac[key].vtep; + string type; + string vni = to_string(m_mac[key].vni); + type = m_mac[key].type; + + std::vector fvVector; + FieldValueTuple rv("remote_vtep", vtep); + FieldValueTuple t("type", type); + FieldValueTuple v("vni", vni); + fvVector.push_back(rv); + fvVector.push_back(t); + fvVector.push_back(v); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, true); + return; + } + + SWSS_LOG_INFO("VXLAN_FDB_TABLE: DEL_KEY %s vtep:%s type:%s", key.c_str(), vtep.c_str(), type.c_str()); + m_fdbTable.del(key); + return; + +} + +void FdbSync::macAddVxlan(string key, struct in_addr vtep, string type, uint32_t vni, string intf_name) +{ + string svtep = inet_ntoa(vtep); + string svni = to_string(vni); + + /* Update the DB with Vxlan MAC */ + m_mac[key] = {svtep, type, vni, intf_name}; + + std::vector fvVector; + FieldValueTuple rv("remote_vtep", svtep); + FieldValueTuple t("type", type); + FieldValueTuple v("vni", svni); + fvVector.push_back(rv); + fvVector.push_back(t); + fvVector.push_back(v); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, false); + return; + } + + SWSS_LOG_INFO("VXLAN_FDB_TABLE: ADD_KEY %s vtep:%s type:%s", key.c_str(), svtep.c_str(), type.c_str()); + m_fdbTable.set(key, fvVector); + + return; +} + +void FdbSync::macDelVxlan(string key) +{ + if (m_mac.find(key) != m_mac.end()) + { + SWSS_LOG_INFO("DEL_KEY %s vtep:%s type:%s", key.c_str(), m_mac[key].vtep.c_str(), m_mac[key].type.c_str()); + macDelVxlanDB(key); + m_mac.erase(key); + } + return; +} + +void FdbSync::onMsgNbr(int nlmsg_type, struct nl_object *obj) +{ + char macStr[MAX_ADDR_SIZE + 1] = {0}; + struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj; + struct in_addr vtep = {0}; + int vlan = 0, ifindex = 0; + uint32_t vni = 0; + nl_addr *vtep_addr; + string ifname; + string key; + bool delete_key = false; + size_t str_loc = string::npos; + string type = ""; + string vlan_id = ""; + bool isVxlanIntf = false; + + if ((nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_GETNEIGH) && + (nlmsg_type != RTM_DELNEIGH)) + { + return; + } + + /* Only MAC route is to be supported */ + if (rtnl_neigh_get_family(neigh) != AF_BRIDGE) + { + return; + } + ifindex = rtnl_neigh_get_ifindex(neigh); + if (m_intf_info.find(ifindex) != m_intf_info.end()) + { + isVxlanIntf = true; + ifname = m_intf_info[ifindex].ifname; + } + + nl_addr2str(rtnl_neigh_get_lladdr(neigh), macStr, MAX_ADDR_SIZE); + + if (isVxlanIntf == false) + { + if (nlmsg_type != RTM_DELNEIGH) + { + return; + } + } + else + { + /* If this is for vnet bridge vxlan interface, then return */ + if (ifname.find(VXLAN_BR_IF_NAME_PREFIX) != string::npos) + { + return; + } + + /* VxLan netdevice should be in - format */ + str_loc = ifname.rfind("-"); + if (str_loc == string::npos) + { + return; + } + + vlan_id = "Vlan" + ifname.substr(str_loc+1, std::string::npos); + vni = m_intf_info[ifindex].vni; + } + + + if (isVxlanIntf == false) + { + vlan = rtnl_neigh_get_vlan(neigh); + if (m_isEvpnNvoExist) + { + macRefreshStateDB(vlan, macStr); + } + return; + } + + vtep_addr = rtnl_neigh_get_dst(neigh); + if (vtep_addr == NULL) + { + return; + } + else + { + /* Currently we only support ipv4 tunnel endpoints */ + vtep.s_addr = *(uint32_t *)nl_addr_get_binary_addr(vtep_addr); + SWSS_LOG_INFO("Tunnel IP %s Int%d", inet_ntoa(vtep), *(uint32_t *)nl_addr_get_binary_addr(vtep_addr)); + } + + int state = rtnl_neigh_get_state(neigh); + if ((nlmsg_type == RTM_DELNEIGH) || (state == NUD_INCOMPLETE) || + (state == NUD_FAILED)) + { + delete_key = true; + } + + if (state & NUD_NOARP) + { + /* This is a static route */ + type = "static"; + } + else + { + type = "dynamic"; + } + + /* Handling IMET routes */ + if (MacAddress(macStr) == MacAddress("00:00:00:00:00:00")) + { + if (vtep.s_addr) + { + string vlan_str = ifname.substr(str_loc+1, string::npos); + + if (!delete_key) + { + imetAddRoute(vtep, vlan_str, vni); + } + else + { + imetDelRoute(vtep, vlan_str, vni); + } + } + return; + } + + key+= vlan_id; + key+= ":"; + key+= macStr; + + if (!delete_key) + { + macAddVxlan(key, vtep, type, vni, ifname); + } + else + { + macDelVxlan(key); + } + return; +} + +void FdbSync::onMsgLink(int nlmsg_type, struct nl_object *obj) +{ + struct rtnl_link *link; + char *ifname = NULL; + char *nil = "NULL"; + int ifindex; + unsigned int vni; + + link = (struct rtnl_link *)obj; + ifname = rtnl_link_get_name(link); + ifindex = rtnl_link_get_ifindex(link); + if (rtnl_link_is_vxlan(link) == 0) + { + return; + } + + if (rtnl_link_vxlan_get_id(link, &vni) != 0) + { + SWSS_LOG_INFO("Op:%d VxLAN dev:%s index:%d vni:%d. Not found", nlmsg_type, ifname? ifname: nil, ifindex, vni); + return; + } + SWSS_LOG_INFO("Op:%d VxLAN dev %s index:%d vni:%d", nlmsg_type, ifname? ifname: nil, ifindex, vni); + if (nlmsg_type == RTM_NEWLINK) + { + m_intf_info[ifindex].vni = vni; + m_intf_info[ifindex].ifname = ifname; + } + return; +} + +void FdbSync::onMsg(int nlmsg_type, struct nl_object *obj) +{ + if ((nlmsg_type != RTM_NEWLINK) && + (nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_DELNEIGH)) + { + SWSS_LOG_DEBUG("netlink: unhandled event: %d", nlmsg_type); + return; + } + if (nlmsg_type == RTM_NEWLINK) + { + onMsgLink(nlmsg_type, obj); + } + else + { + onMsgNbr(nlmsg_type, obj); + } +} + diff --git a/fdbsyncd/fdbsync.h b/fdbsyncd/fdbsync.h index e95421f27b..54815f0c30 100644 --- a/fdbsyncd/fdbsync.h +++ b/fdbsyncd/fdbsync.h @@ -1,149 +1,150 @@ -#ifndef __FDBSYNC__ -#define __FDBSYNC__ - -#include -#include -#include "dbconnector.h" -#include "producerstatetable.h" -#include "subscriberstatetable.h" -#include "netmsg.h" -#include "warmRestartAssist.h" - -// The timeout value (in seconds) for fdbsyncd reconcilation logic -#define DEFAULT_FDBSYNC_WARMSTART_TIMER 30 - -namespace swss { - -enum FDB_OP_TYPE { - FDB_OPER_ADD =1, - FDB_OPER_DEL = 2, -}; - -enum FDB_TYPE { - FDB_TYPE_STATIC = 1, - FDB_TYPE_DYNAMIC = 2, -}; - -struct m_fdb_info -{ - std::string mac; - std::string vid; /*Store as Vlan */ - std::string port_name; - short type; /*dynamic or static*/ - short op_type; /*add or del*/ -}; - -class FdbSync : public NetMsg -{ -public: - enum { MAX_ADDR_SIZE = 64 }; - - FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db); - ~FdbSync(); - - virtual void onMsg(int nlmsg_type, struct nl_object *obj); - - bool isFdbRestoreDone(); - - AppRestartAssist *getRestartAssist() - { - return m_AppRestartAssist; - } - - SubscriberStateTable *getFdbStateTable() - { - return &m_fdbStateTable; - } - - SubscriberStateTable *getMclagRemoteFdbStateTable() - { - return &m_mclagRemoteFdbStateTable; - } - - SubscriberStateTable *getCfgEvpnNvoTable() - { - return &m_cfgEvpnNvoTable; - } - - void processStateFdb(); - - void processStateMclagRemoteFdb(); - - void processCfgEvpnNvo(); - - bool m_reconcileDone = false; - - bool m_isEvpnNvoExist = false; - -private: - ProducerStateTable m_fdbTable; - ProducerStateTable m_imetTable; - SubscriberStateTable m_fdbStateTable; - SubscriberStateTable m_mclagRemoteFdbStateTable; - AppRestartAssist *m_AppRestartAssist; - SubscriberStateTable m_cfgEvpnNvoTable; - - struct m_local_fdb_info - { - std::string port_name; - short type;/*dynamic or static*/ - }; - std::unordered_map m_fdb_mac; - - std::unordered_map m_mclag_remote_fdb_mac; - - void macDelVxlanEntry(std::string auxkey, struct m_fdb_info *info); - - void macUpdateCache(struct m_fdb_info *info); - - bool macCheckSrcDB(struct m_fdb_info *info); - - void updateLocalMac(struct m_fdb_info *info); - - void updateAllLocalMac(); - - void macRefreshStateDB(int vlan, std::string kmac); - - void updateMclagRemoteMac(struct m_fdb_info *info); - - void macUpdateMclagRemoteCache(struct m_fdb_info *info); - - bool checkImetExist(std::string key, uint32_t vni); - - bool checkDelImet(std::string key, uint32_t vni); - - struct m_mac_info - { - std::string vtep; - std::string type; - unsigned int vni; - std::string ifname; - }; - std::unordered_map m_mac; - - struct m_imet_info - { - unsigned int vni; - }; - std::unordered_map m_imet_route; - - struct intf - { - std::string ifname; - unsigned int vni; - }; - std::unordered_map m_intf_info; - - void addLocalMac(std::string key, std::string op); - void macAddVxlan(std::string key, struct in_addr vtep, std::string type, uint32_t vni, std::string intf_name); - void macDelVxlan(std::string auxkey); - void macDelVxlanDB(std::string key); - void imetAddRoute(struct in_addr vtep, std::string ifname, uint32_t vni); - void imetDelRoute(struct in_addr vtep, std::string ifname, uint32_t vni); - void onMsgNbr(int nlmsg_type, struct nl_object *obj); - void onMsgLink(int nlmsg_type, struct nl_object *obj); -}; - -} - -#endif +#ifndef __FDBSYNC__ +#define __FDBSYNC__ + +#include +#include +#include "dbconnector.h" +#include "producerstatetable.h" +#include "subscriberstatetable.h" +#include "netmsg.h" +#include "warmRestartAssist.h" + +// The timeout value (in seconds) for fdbsyncd reconcilation logic +#define DEFAULT_FDBSYNC_WARMSTART_TIMER 30 + +namespace swss { + +enum FDB_OP_TYPE { + FDB_OPER_ADD =1, + FDB_OPER_DEL = 2, +}; + +enum FDB_TYPE { + FDB_TYPE_STATIC = 1, + FDB_TYPE_DYNAMIC = 2, +}; + +struct m_fdb_info +{ + std::string mac; + std::string vid; /*Store as Vlan */ + std::string port_name; + short type; /*dynamic or static*/ + short op_type; /*add or del*/ +}; + +class FdbSync : public NetMsg +{ +public: + enum { MAX_ADDR_SIZE = 64 }; + + FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db); + ~FdbSync(); + + virtual void onMsg(int nlmsg_type, struct nl_object *obj); + + bool isFdbRestoreDone(); + + AppRestartAssist *getRestartAssist() + { + return m_AppRestartAssist; + } + + SubscriberStateTable *getFdbStateTable() + { + return &m_fdbStateTable; + } + + SubscriberStateTable *getMclagRemoteFdbStateTable() + { + return &m_mclagRemoteFdbStateTable; + } + + SubscriberStateTable *getCfgEvpnNvoTable() + { + return &m_cfgEvpnNvoTable; + } + + void processStateFdb(); + + void processStateMclagRemoteFdb(); + + void processCfgEvpnNvo(); + + bool m_reconcileDone = false; + + bool m_isEvpnNvoExist = false; + +private: + ProducerStateTable m_fdbTable; + ProducerStateTable m_imetTable; + SubscriberStateTable m_fdbStateTable; + SubscriberStateTable m_mclagRemoteFdbStateTable; + AppRestartAssist *m_AppRestartAssist; + SubscriberStateTable m_cfgEvpnNvoTable; + + struct m_local_fdb_info + { + std::string port_name; + short type;/*dynamic or static*/ + }; + std::unordered_map m_fdb_mac; + + std::unordered_map m_mclag_remote_fdb_mac; + + void macDelVxlanEntry(std::string auxkey, struct m_fdb_info *info); + + void macUpdateCache(struct m_fdb_info *info); + + bool macCheckSrcDB(struct m_fdb_info *info); + + void updateLocalMac(struct m_fdb_info *info); + + void updateAllLocalMac(); + + void macRefreshStateDB(int vlan, std::string kmac); + + void updateMclagRemoteMac(struct m_fdb_info *info); + + void macUpdateMclagRemoteCache(struct m_fdb_info *info); + + bool checkImetExist(std::string key, uint32_t vni); + + bool checkDelImet(std::string key, uint32_t vni); + + struct m_mac_info + { + std::string vtep; + std::string type; + unsigned int vni; + std::string ifname; + }; + std::unordered_map m_mac; + + struct m_imet_info + { + unsigned int vni; + }; + std::unordered_map m_imet_route; + + struct intf + { + std::string ifname; + unsigned int vni; + }; + std::unordered_map m_intf_info; + + void addLocalMac(std::string key, std::string op); + void macAddVxlan(std::string key, struct in_addr vtep, std::string type, uint32_t vni, std::string intf_name); + void macDelVxlan(std::string auxkey); + void macDelVxlanDB(std::string key); + void imetAddRoute(struct in_addr vtep, std::string ifname, uint32_t vni); + void imetDelRoute(struct in_addr vtep, std::string ifname, uint32_t vni); + void onMsgNbr(int nlmsg_type, struct nl_object *obj); + void onMsgLink(int nlmsg_type, struct nl_object *obj); +}; + +} + +#endif + diff --git a/fdbsyncd/fdbsyncd.cpp b/fdbsyncd/fdbsyncd.cpp index 60e88477d1..f734cf9616 100644 --- a/fdbsyncd/fdbsyncd.cpp +++ b/fdbsyncd/fdbsyncd.cpp @@ -1,111 +1,110 @@ -#include -#include -#include -#include -#include "logger.h" -#include "select.h" -#include "netdispatcher.h" -#include "netlink.h" -#include "fdbsyncd/fdbsync.h" - -using namespace std; -using namespace swss; - -int main(int argc, char **argv) -{ - Logger::linkToDbNative("fdbsyncd"); - - DBConnector appDb(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - RedisPipeline pipelineAppDB(&appDb); - DBConnector stateDb(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - DBConnector log_db(LOGLEVEL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - DBConnector config_db(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - - FdbSync sync(&pipelineAppDB, &stateDb, &config_db); - - NetDispatcher::getInstance().registerMessageHandler(RTM_NEWNEIGH, &sync); - NetDispatcher::getInstance().registerMessageHandler(RTM_DELNEIGH, &sync); - NetDispatcher::getInstance().registerMessageHandler(RTM_NEWLINK, &sync); - - while (1) - { - try - { - NetLink netlink; - Selectable *temps; - int ret; - Select s; - - using namespace std::chrono; - - /* - * If WarmStart is enabled, restore the VXLAN-FDB and VNI - * tables and start a reconcillation timer - */ - if (sync.getRestartAssist()->isWarmStartInProgress()) - { - sync.getRestartAssist()->readTablesToMap(); - SWSS_LOG_NOTICE("Starting ReconcileTimer"); - } - - netlink.registerGroup(RTNLGRP_LINK); - netlink.registerGroup(RTNLGRP_NEIGH); - SWSS_LOG_NOTICE("Listens to link and neigh messages..."); - netlink.dumpRequest(RTM_GETLINK); - s.addSelectable(&netlink); - ret = s.select(&temps, 1); - if (ret == Select::ERROR) - { - SWSS_LOG_ERROR("Error in RTM_GETLINK dump"); - } - - netlink.dumpRequest(RTM_GETNEIGH); - - s.addSelectable(sync.getFdbStateTable()); - s.addSelectable(sync.getMclagRemoteFdbStateTable()); - s.addSelectable(sync.getCfgEvpnNvoTable()); - while (true) - { - s.select(&temps); - - if(temps == (Selectable *)sync.getFdbStateTable()) - { - sync.processStateFdb(); - } - else if(temps == (Selectable *)sync.getMclagRemoteFdbStateTable()) - { - sync.processStateMclagRemoteFdb(); - } - else if (temps == (Selectable *)sync.getCfgEvpnNvoTable()) - { - sync.processCfgEvpnNvo(); - } - else - { - /* - * If warmstart is in progress, we check the reconcile timer, - * if timer expired, we stop the timer and start the reconcile process - */ - if (sync.getRestartAssist()->isWarmStartInProgress()) - { - if (sync.getRestartAssist()->checkReconcileTimer(temps)) - { - sync.m_reconcileDone = true; - sync.getRestartAssist()->stopReconcileTimer(s); - sync.getRestartAssist()->reconcile(); - SWSS_LOG_NOTICE("VXLAN FDB VNI Reconcillation Complete (Timer)"); - } - } - } - } - } - catch (const std::exception& e) - { - cout << "Exception \"" << e.what() << "\" had been thrown in deamon" << endl; - return 0; - } - } - - return 1; -} - +#include +#include +#include +#include +#include "logger.h" +#include "select.h" +#include "netdispatcher.h" +#include "netlink.h" +#include "fdbsyncd/fdbsync.h" + +using namespace std; +using namespace swss; + +int main(int argc, char **argv) +{ + Logger::linkToDbNative("fdbsyncd"); + + DBConnector appDb(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + RedisPipeline pipelineAppDB(&appDb); + DBConnector stateDb(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + DBConnector log_db(LOGLEVEL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + DBConnector config_db(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + + FdbSync sync(&pipelineAppDB, &stateDb, &config_db); + + NetDispatcher::getInstance().registerMessageHandler(RTM_NEWNEIGH, &sync); + NetDispatcher::getInstance().registerMessageHandler(RTM_DELNEIGH, &sync); + NetDispatcher::getInstance().registerMessageHandler(RTM_NEWLINK, &sync); + + while (1) + { + try + { + NetLink netlink; + Selectable *temps; + int ret; + Select s; + + using namespace std::chrono; + + /* + * If WarmStart is enabled, restore the VXLAN-FDB and VNI + * tables and start a reconcillation timer + */ + if (sync.getRestartAssist()->isWarmStartInProgress()) + { + sync.getRestartAssist()->readTablesToMap(); + SWSS_LOG_NOTICE("Starting ReconcileTimer"); + } + + netlink.registerGroup(RTNLGRP_LINK); + netlink.registerGroup(RTNLGRP_NEIGH); + SWSS_LOG_NOTICE("Listens to link and neigh messages..."); + netlink.dumpRequest(RTM_GETLINK); + s.addSelectable(&netlink); + ret = s.select(&temps, 1); + if (ret == Select::ERROR) + { + SWSS_LOG_ERROR("Error in RTM_GETLINK dump"); + } + + netlink.dumpRequest(RTM_GETNEIGH); + + s.addSelectable(sync.getFdbStateTable()); + s.addSelectable(sync.getMclagRemoteFdbStateTable()); + s.addSelectable(sync.getCfgEvpnNvoTable()); + while (true) + { + s.select(&temps); + + if(temps == (Selectable *)sync.getFdbStateTable()) + { + sync.processStateFdb(); + } + else if(temps == (Selectable *)sync.getMclagRemoteFdbStateTable()) + { + sync.processStateMclagRemoteFdb(); + } + else if (temps == (Selectable *)sync.getCfgEvpnNvoTable()) + { + sync.processCfgEvpnNvo(); + } + else + { + /* + * If warmstart is in progress, we check the reconcile timer, + * if timer expired, we stop the timer and start the reconcile process + */ + if (sync.getRestartAssist()->isWarmStartInProgress()) + { + if (sync.getRestartAssist()->checkReconcileTimer(temps)) + { + sync.m_reconcileDone = true; + sync.getRestartAssist()->stopReconcileTimer(s); + sync.getRestartAssist()->reconcile(); + SWSS_LOG_NOTICE("VXLAN FDB VNI Reconcillation Complete (Timer)"); + } + } + } + } + } + catch (const std::exception& e) + { + cout << "Exception \"" << e.what() << "\" had been thrown in deamon" << endl; + return 0; + } + } + + return 1; +} diff --git a/orchagent/notifications.cpp b/orchagent/notifications.cpp index 209c03d83b..4133726bc4 100644 --- a/orchagent/notifications.cpp +++ b/orchagent/notifications.cpp @@ -5,7 +5,7 @@ extern "C" { #include "logger.h" #include "notifications.h" -void on_fdb_event(uint32_t count, sai_fdb_event_notification_data_t *data) +void on_fdb_event(uint32_t count, sai_fdb_event_notification_data_t *fdbevent) { // don't use this event handler, because it runs by libsairedis in a separate thread // which causes concurrency access to the DB diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index 928a779a2e..af2a5e1bbd 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -156,7 +156,7 @@ class PortsOrch : public Orch, public Subject unique_ptr
m_pgIndexTable; unique_ptr m_flexCounterTable; unique_ptr m_flexCounterGroupTable; - NotificationProducer* notifications; + unique_ptr notifications; std::string getQueueWatermarkFlexCounterTableKey(std::string s); std::string getPriorityGroupWatermarkFlexCounterTableKey(std::string s); From 307480cc16a52448ac3cb3dfc71de2bfee311f55 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Mon, 4 Jan 2021 16:45:13 -0800 Subject: [PATCH 09/54] Fixed the mac type. --- fdbsyncd/fdbsync.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbsyncd/fdbsync.cpp b/fdbsyncd/fdbsync.cpp index f2c4b1fb34..05a18f1090 100644 --- a/fdbsyncd/fdbsync.cpp +++ b/fdbsyncd/fdbsync.cpp @@ -170,7 +170,7 @@ void FdbSync::processStateMclagRemoteFdb() auto mac_address = key.substr(delimiter+1); info.vid = vlan_name; - memcpy(info.mac, mac_address.c_str(),mac_address.length()); + info.mac = mac_address; if(op == "SET") { From e159f43b6d895f6af7cb9b3bc73e18e15caf6168 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Mon, 4 Jan 2021 17:30:14 -0800 Subject: [PATCH 10/54] Fix Port_name --- fdbsyncd/fdbsync.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdbsyncd/fdbsync.cpp b/fdbsyncd/fdbsync.cpp index 05a18f1090..6e6e2b0522 100644 --- a/fdbsyncd/fdbsync.cpp +++ b/fdbsyncd/fdbsync.cpp @@ -190,7 +190,7 @@ void FdbSync::processStateMclagRemoteFdb() if(fvField(i) == "port") { - memcpy(info.port_name, fvValue(i).c_str(), fvValue(i).length()); + info.port_name = fvValue(i); } if(fvField(i) == "type") From 2427f063cb7e7281d9022597c4e45616becc23dc Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Mon, 4 Jan 2021 19:24:38 -0800 Subject: [PATCH 11/54] Updated the fix from PR885. --- orchagent/portsorch.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 7e54199dac..fa8384c36f 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -257,7 +257,8 @@ PortsOrch::PortsOrch(DBConnector *db, vector &tableNames) 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)); - notifications = new swss::NotificationProducer(db, "VLANSTATE"); + notifications = unique_ptr(new swss::NotificationProducer(db, "VLANSTATE")); + initGearbox(); string queueWmSha, pgWmSha; @@ -1826,16 +1827,6 @@ sai_status_t PortsOrch::removePort(sai_object_id_t port_id) Port port; - /* - * Make sure to bring down admin state. - * SET would have replaced with DEL - */ - if (getPort(port_id, port)) - { - setPortAdminStatus(port, false); - } - /* else : port is in default state or not yet created */ - sai_status_t status = sai_port_api->remove_port(port_id); if (status != SAI_STATUS_SUCCESS) { From cf19814a38495fad035eef783ea10cb7012f39d6 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Mon, 4 Jan 2021 20:57:34 -0800 Subject: [PATCH 12/54] Adding new orchfiles to mock_tests --- tests/mock_tests/Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/mock_tests/Makefile.am b/tests/mock_tests/Makefile.am index 252b7d9c88..50d12fd94c 100644 --- a/tests/mock_tests/Makefile.am +++ b/tests/mock_tests/Makefile.am @@ -65,7 +65,9 @@ tests_SOURCES = aclorch_ut.cpp \ $(top_srcdir)/orchagent/sfloworch.cpp \ $(top_srcdir)/orchagent/debugcounterorch.cpp \ $(top_srcdir)/orchagent/natorch.cpp \ - $(top_srcdir)/orchagent/muxorch.cpp + $(top_srcdir)/orchagent/muxorch.cpp \ + $(top_srcdir)/orchagent/mlagorch.cpp \ + $(top_srcdir)/orchagent/isolationgrouporch.cpp tests_SOURCES += $(FLEX_CTR_DIR)/flex_counter_manager.cpp $(FLEX_CTR_DIR)/flex_counter_stat_manager.cpp tests_SOURCES += $(DEBUG_CTR_DIR)/debug_counter.cpp $(DEBUG_CTR_DIR)/drop_counter.cpp From 146874ab22529668d80239bd2d9240bce3064b10 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Fri, 5 Feb 2021 10:21:58 -0800 Subject: [PATCH 13/54] Updated the file format to unix. --- fdbsyncd/fdbsync.cpp | 1606 ++++++++++++++++++++--------------------- fdbsyncd/fdbsync.h | 300 ++++---- fdbsyncd/fdbsyncd.cpp | 220 +++--- 3 files changed, 1063 insertions(+), 1063 deletions(-) diff --git a/fdbsyncd/fdbsync.cpp b/fdbsyncd/fdbsync.cpp index 6e6e2b0522..32870210ff 100644 --- a/fdbsyncd/fdbsync.cpp +++ b/fdbsyncd/fdbsync.cpp @@ -1,803 +1,803 @@ -#include -#include -#include -#include -#include -#include - -#include "logger.h" -#include "dbconnector.h" -#include "producerstatetable.h" -#include "ipaddress.h" -#include "netmsg.h" -#include "macaddress.h" -#include "exec.h" -#include "fdbsync.h" -#include "warm_restart.h" -#include "errno.h" - -using namespace std; -using namespace swss; - -#define VXLAN_BR_IF_NAME_PREFIX "Brvxlan" - -FdbSync::FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db) : - m_fdbTable(pipelineAppDB, APP_VXLAN_FDB_TABLE_NAME), - m_imetTable(pipelineAppDB, APP_VXLAN_REMOTE_VNI_TABLE_NAME), - m_fdbStateTable(stateDb, STATE_FDB_TABLE_NAME), - m_mclagRemoteFdbStateTable(stateDb, STATE_MCLAG_REMOTE_FDB_TABLE_NAME), - m_cfgEvpnNvoTable(config_db, CFG_VXLAN_EVPN_NVO_TABLE_NAME) -{ - m_AppRestartAssist = new AppRestartAssist(pipelineAppDB, "fdbsyncd", "swss", DEFAULT_FDBSYNC_WARMSTART_TIMER); - if (m_AppRestartAssist) - { - m_AppRestartAssist->registerAppTable(APP_VXLAN_FDB_TABLE_NAME, &m_fdbTable); - m_AppRestartAssist->registerAppTable(APP_VXLAN_REMOTE_VNI_TABLE_NAME, &m_imetTable); - } -} - -FdbSync::~FdbSync() -{ - if (m_AppRestartAssist) - { - delete m_AppRestartAssist; - } -} - -void FdbSync::processCfgEvpnNvo() -{ - std::deque entries; - m_cfgEvpnNvoTable.pops(entries); - bool lastNvoState = m_isEvpnNvoExist; - - for (auto entry: entries) - { - std::string op = kfvOp(entry); - - if (op == SET_COMMAND) - { - m_isEvpnNvoExist = true; - } - else if (op == DEL_COMMAND) - { - m_isEvpnNvoExist = false; - } - - if (lastNvoState != m_isEvpnNvoExist) - { - updateAllLocalMac(); - } - } - return; -} - -void FdbSync::updateAllLocalMac() -{ - for ( auto it = m_fdb_mac.begin(); it != m_fdb_mac.end(); ++it ) - { - if (m_isEvpnNvoExist) - { - /* Add the Local FDB entry into Kernel */ - addLocalMac(it->first, "replace"); - } - else - { - /* Delete the Local FDB entry from Kernel */ - addLocalMac(it->first, "del"); - } - } -} - -void FdbSync::processStateFdb() -{ - struct m_fdb_info info; - std::deque entries; - - m_fdbStateTable.pops(entries); - - int count =0 ; - for (auto entry: entries) - { - count++; - std::string key = kfvKey(entry); - std::string op = kfvOp(entry); - - std::size_t delimiter = key.find_first_of(":"); - auto vlan_name = key.substr(0, delimiter); - auto mac_address = key.substr(delimiter+1); - - info.vid = vlan_name; - info.mac = mac_address; - - if(op == "SET") - { - info.op_type = FDB_OPER_ADD ; - } - else - { - info.op_type = FDB_OPER_DEL ; - } - - SWSS_LOG_INFO("FDBSYNCD STATE FDB updates key=%s, operation=%s\n", key.c_str(), op.c_str()); - - for (auto i : kfvFieldsValues(entry)) - { - SWSS_LOG_INFO(" FDBSYNCD STATE FDB updates : " - "FvFiels %s, FvValues: %s \n", fvField(i).c_str(), fvValue(i).c_str()); - - if(fvField(i) == "port") - { - info.port_name = fvValue(i); - } - - if(fvField(i) == "type") - { - if(fvValue(i) == "dynamic") - { - info.type = FDB_TYPE_DYNAMIC; - } - else if (fvValue(i) == "static") - { - info.type = FDB_TYPE_STATIC; - } - } - } - - if (op != "SET" && macCheckSrcDB(&info) == false) - { - continue; - } - updateLocalMac(&info); - } -} - -void FdbSync::processStateMclagRemoteFdb() -{ - struct m_fdb_info info; - std::deque entries; - - m_mclagRemoteFdbStateTable.pops(entries); - - int count =0 ; - for (auto entry: entries) - { - count++; - std::string key = kfvKey(entry); - std::string op = kfvOp(entry); - - std::size_t delimiter = key.find_first_of(":"); - auto vlan_name = key.substr(0, delimiter); - auto mac_address = key.substr(delimiter+1); - - info.vid = vlan_name; - info.mac = mac_address; - - if(op == "SET") - { - info.op_type = FDB_OPER_ADD ; - } - else - { - info.op_type = FDB_OPER_DEL ; - } - - SWSS_LOG_INFO("FDBSYNCD STATE FDB updates key=%s, operation=%s\n", key.c_str(), op.c_str()); - - for (auto i : kfvFieldsValues(entry)) - { - SWSS_LOG_INFO(" FDBSYNCD STATE FDB updates : " - "FvFiels %s, FvValues: %s \n", fvField(i).c_str(), fvValue(i).c_str()); - - if(fvField(i) == "port") - { - info.port_name = fvValue(i); - } - - if(fvField(i) == "type") - { - if(fvValue(i) == "dynamic") - { - info.type = FDB_TYPE_DYNAMIC; - } - else if (fvValue(i) == "static") - { - info.type = FDB_TYPE_STATIC; - } - } - } - - if (op != "SET" && macCheckSrcDB(&info) == false) - { - continue; - } - updateMclagRemoteMac(&info); - } -} - -void FdbSync::macUpdateCache(struct m_fdb_info *info) -{ - string key = info->vid + ":" + info->mac; - m_fdb_mac[key].port_name = info->port_name; - m_fdb_mac[key].type = info->type; - - return; -} - -void FdbSync::macUpdateMclagRemoteCache(struct m_fdb_info *info) -{ - string key = info->vid + ":" + info->mac; - m_mclag_remote_fdb_mac[key].port_name = info->port_name; - m_mclag_remote_fdb_mac[key].type = info->type; - - return; -} - -bool FdbSync::macCheckSrcDB(struct m_fdb_info *info) -{ - string key = info->vid + ":" + info->mac; - if (m_fdb_mac.find(key) != m_fdb_mac.end()) - { - SWSS_LOG_INFO("DEL_KEY %s ", key.c_str()); - return true; - } - - return false; -} - -void FdbSync::macDelVxlanEntry(string auxkey, struct m_fdb_info *info) -{ - std::string vtep = m_mac[auxkey].vtep; - - const std::string cmds = std::string("") - + " bridge fdb del " + info->mac + " dev " - + m_mac[auxkey].ifname + " dst " + vtep + " vlan " + info->vid.substr(4); - - std::string res; - int ret = swss::exec(cmds, res); - if (ret != 0) - { - SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - - SWSS_LOG_INFO("Success cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - - return; -} - -void FdbSync::updateLocalMac (struct m_fdb_info *info) -{ - char *op; - char *type; - string port_name = ""; - string key = info->vid + ":" + info->mac; - short fdb_type; /*dynamic or static*/ - - if (info->op_type == FDB_OPER_ADD) - { - macUpdateCache(info); - op = "replace"; - port_name = info->port_name; - fdb_type = info->type; - /* Check if this vlan+key is also learned by vxlan neighbor then delete learned on */ - if (m_mac.find(key) != m_mac.end()) - { - macDelVxlanEntry(key, info); - SWSS_LOG_INFO("Local learn event deleting from VXLAN table DEL_KEY %s", key.c_str()); - macDelVxlan(key); - } - } - else - { - op = "del"; - port_name = m_fdb_mac[key].port_name; - fdb_type = m_fdb_mac[key].type; - m_fdb_mac.erase(key); - } - - if (!m_isEvpnNvoExist) - { - SWSS_LOG_INFO("Ignore kernel update EVPN NVO is not configured MAC %s", key.c_str()); - return; - } - - if (fdb_type == FDB_TYPE_DYNAMIC) - { - type = "dynamic"; - } - else - { - type = "static"; - } - - const std::string cmds = std::string("") - + " bridge fdb " + op + " " + info->mac + " dev " - + port_name + " master " + type + " vlan " + info->vid.substr(4); - - std::string res; - int ret = swss::exec(cmds, res); - - SWSS_LOG_INFO("cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - - return; -} - -void FdbSync::addLocalMac(string key, string op) -{ - char *type; - string port_name = ""; - string mac = ""; - string vlan = ""; - size_t str_loc = string::npos; - - str_loc = key.find(":"); - if (str_loc == string::npos) - { - SWSS_LOG_ERROR("Local MAC issue with Key:%s", key.c_str()); - return; - } - vlan = key.substr(4, str_loc-4); - mac = key.substr(str_loc+1, std::string::npos); - - SWSS_LOG_INFO("Local route Vlan:%s MAC:%s Key:%s Op:%s", vlan.c_str(), mac.c_str(), key.c_str(), op.c_str()); - - if (m_fdb_mac.find(key)!=m_fdb_mac.end()) - { - port_name = m_fdb_mac[key].port_name; - if (port_name.empty()) - { - SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); - return; - } - - if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) - { - type = "dynamic"; - } - else - { - type = "static"; - } - - const std::string cmds = std::string("") - + " bridge fdb " + op + " " + mac + " dev " - + port_name + " master " + type + " vlan " + vlan; - - std::string res; - int ret = swss::exec(cmds, res); - if (ret != 0) - { - SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - - SWSS_LOG_INFO("Config triggered cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - return; -} - -void FdbSync::updateMclagRemoteMac (struct m_fdb_info *info) -{ - char *op; - char *type; - string port_name = ""; - string key = info->vid + ":" + info->mac; - short fdb_type; /*dynamic or static*/ - - if (info->op_type == FDB_OPER_ADD) - { - macUpdateMclagRemoteCache(info); - op = "replace"; - port_name = info->port_name; - fdb_type = info->type; - } - else - { - op = "del"; - port_name = m_mclag_remote_fdb_mac[key].port_name; - fdb_type = m_mclag_remote_fdb_mac[key].type; - m_mclag_remote_fdb_mac.erase(key); - } - - if (fdb_type == FDB_TYPE_DYNAMIC) - { - type = "dynamic"; - } - else - { - type = "static"; - } - - const std::string cmds = std::string("") - + " bridge fdb " + op + " " + info->mac + " dev " - + port_name + " master " + type + " vlan " + info->vid.substr(4); - - std::string res; - int ret = swss::exec(cmds, res); - - SWSS_LOG_INFO("cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - - return; -} - -/* - * This is a special case handling where mac is learned in the ASIC. - * Then MAC is learned in the Kernel, Since this mac is learned in the Kernel - * This MAC will age out, when MAC delete is received from the Kernel. - * If MAC is still present in the state DB cache then fdbsyncd will be - * re-programmed with MAC in the Kernel - */ -void FdbSync::macRefreshStateDB(int vlan, string kmac) -{ - string key = "Vlan" + to_string(vlan) + ":" + kmac; - char *type; - string port_name = ""; - - SWSS_LOG_INFO("Refreshing Vlan:%d MAC route MAC:%s Key %s", vlan, kmac.c_str(), key.c_str()); - - if (m_fdb_mac.find(key)!=m_fdb_mac.end()) - { - port_name = m_fdb_mac[key].port_name; - if (port_name.empty()) - { - SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); - return; - } - - if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) - { - type = "dynamic"; - } - else - { - type = "static"; - } - - const std::string cmds = std::string("") - + " bridge fdb " + "replace" + " " + kmac + " dev " - + port_name + " master " + type + " vlan " + to_string(vlan); - - std::string res; - int ret = swss::exec(cmds, res); - if (ret != 0) - { - SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - - SWSS_LOG_INFO("Refreshing cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); - } - return; -} - -bool FdbSync::checkImetExist(string key, uint32_t vni) -{ - if (m_imet_route.find(key) != m_imet_route.end()) - { - SWSS_LOG_INFO("IMET exist key:%s Vni:%d", key.c_str(), vni); - return false; - } - m_imet_route[key].vni = vni; - return true; -} - -bool FdbSync::checkDelImet(string key, uint32_t vni) -{ - int ret = false; - - SWSS_LOG_INFO("Del IMET key:%s Vni:%d", key.c_str(), vni); - if (m_imet_route.find(key) != m_imet_route.end()) - { - ret = true; - m_imet_route.erase(key); - } - return ret; -} - -void FdbSync::imetAddRoute(struct in_addr vtep, string vlan_str, uint32_t vni) -{ - string vlan_id = "Vlan" + vlan_str; - string key = vlan_id + ":" + inet_ntoa(vtep); - - if (!checkImetExist(key, vni)) - { - return; - } - - SWSS_LOG_INFO("%sIMET Add route key:%s vtep:%s %s", - m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", - key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); - - std::vector fvVector; - FieldValueTuple f("vni", to_string(vni)); - fvVector.push_back(f); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, false); - return; - } - - m_imetTable.set(key, fvVector); - return; -} - -void FdbSync::imetDelRoute(struct in_addr vtep, string vlan_str, uint32_t vni) -{ - string vlan_id = "Vlan" + vlan_str; - string key = vlan_id + ":" + inet_ntoa(vtep); - - if (!checkDelImet(key, vni)) - { - return; - } - - SWSS_LOG_INFO("%sIMET Del route key:%s vtep:%s %s", - m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", - key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); - - std::vector fvVector; - FieldValueTuple f("vni", to_string(vni)); - fvVector.push_back(f); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, true); - return; - } - - m_imetTable.del(key); - return; -} - -void FdbSync::macDelVxlanDB(string key) -{ - string vtep = m_mac[key].vtep; - string type; - string vni = to_string(m_mac[key].vni); - type = m_mac[key].type; - - std::vector fvVector; - FieldValueTuple rv("remote_vtep", vtep); - FieldValueTuple t("type", type); - FieldValueTuple v("vni", vni); - fvVector.push_back(rv); - fvVector.push_back(t); - fvVector.push_back(v); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, true); - return; - } - - SWSS_LOG_INFO("VXLAN_FDB_TABLE: DEL_KEY %s vtep:%s type:%s", key.c_str(), vtep.c_str(), type.c_str()); - m_fdbTable.del(key); - return; - -} - -void FdbSync::macAddVxlan(string key, struct in_addr vtep, string type, uint32_t vni, string intf_name) -{ - string svtep = inet_ntoa(vtep); - string svni = to_string(vni); - - /* Update the DB with Vxlan MAC */ - m_mac[key] = {svtep, type, vni, intf_name}; - - std::vector fvVector; - FieldValueTuple rv("remote_vtep", svtep); - FieldValueTuple t("type", type); - FieldValueTuple v("vni", svni); - fvVector.push_back(rv); - fvVector.push_back(t); - fvVector.push_back(v); - - // If warmstart is in progress, we take all netlink changes into the cache map - if (m_AppRestartAssist->isWarmStartInProgress()) - { - m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, false); - return; - } - - SWSS_LOG_INFO("VXLAN_FDB_TABLE: ADD_KEY %s vtep:%s type:%s", key.c_str(), svtep.c_str(), type.c_str()); - m_fdbTable.set(key, fvVector); - - return; -} - -void FdbSync::macDelVxlan(string key) -{ - if (m_mac.find(key) != m_mac.end()) - { - SWSS_LOG_INFO("DEL_KEY %s vtep:%s type:%s", key.c_str(), m_mac[key].vtep.c_str(), m_mac[key].type.c_str()); - macDelVxlanDB(key); - m_mac.erase(key); - } - return; -} - -void FdbSync::onMsgNbr(int nlmsg_type, struct nl_object *obj) -{ - char macStr[MAX_ADDR_SIZE + 1] = {0}; - struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj; - struct in_addr vtep = {0}; - int vlan = 0, ifindex = 0; - uint32_t vni = 0; - nl_addr *vtep_addr; - string ifname; - string key; - bool delete_key = false; - size_t str_loc = string::npos; - string type = ""; - string vlan_id = ""; - bool isVxlanIntf = false; - - if ((nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_GETNEIGH) && - (nlmsg_type != RTM_DELNEIGH)) - { - return; - } - - /* Only MAC route is to be supported */ - if (rtnl_neigh_get_family(neigh) != AF_BRIDGE) - { - return; - } - ifindex = rtnl_neigh_get_ifindex(neigh); - if (m_intf_info.find(ifindex) != m_intf_info.end()) - { - isVxlanIntf = true; - ifname = m_intf_info[ifindex].ifname; - } - - nl_addr2str(rtnl_neigh_get_lladdr(neigh), macStr, MAX_ADDR_SIZE); - - if (isVxlanIntf == false) - { - if (nlmsg_type != RTM_DELNEIGH) - { - return; - } - } - else - { - /* If this is for vnet bridge vxlan interface, then return */ - if (ifname.find(VXLAN_BR_IF_NAME_PREFIX) != string::npos) - { - return; - } - - /* VxLan netdevice should be in - format */ - str_loc = ifname.rfind("-"); - if (str_loc == string::npos) - { - return; - } - - vlan_id = "Vlan" + ifname.substr(str_loc+1, std::string::npos); - vni = m_intf_info[ifindex].vni; - } - - - if (isVxlanIntf == false) - { - vlan = rtnl_neigh_get_vlan(neigh); - if (m_isEvpnNvoExist) - { - macRefreshStateDB(vlan, macStr); - } - return; - } - - vtep_addr = rtnl_neigh_get_dst(neigh); - if (vtep_addr == NULL) - { - return; - } - else - { - /* Currently we only support ipv4 tunnel endpoints */ - vtep.s_addr = *(uint32_t *)nl_addr_get_binary_addr(vtep_addr); - SWSS_LOG_INFO("Tunnel IP %s Int%d", inet_ntoa(vtep), *(uint32_t *)nl_addr_get_binary_addr(vtep_addr)); - } - - int state = rtnl_neigh_get_state(neigh); - if ((nlmsg_type == RTM_DELNEIGH) || (state == NUD_INCOMPLETE) || - (state == NUD_FAILED)) - { - delete_key = true; - } - - if (state & NUD_NOARP) - { - /* This is a static route */ - type = "static"; - } - else - { - type = "dynamic"; - } - - /* Handling IMET routes */ - if (MacAddress(macStr) == MacAddress("00:00:00:00:00:00")) - { - if (vtep.s_addr) - { - string vlan_str = ifname.substr(str_loc+1, string::npos); - - if (!delete_key) - { - imetAddRoute(vtep, vlan_str, vni); - } - else - { - imetDelRoute(vtep, vlan_str, vni); - } - } - return; - } - - key+= vlan_id; - key+= ":"; - key+= macStr; - - if (!delete_key) - { - macAddVxlan(key, vtep, type, vni, ifname); - } - else - { - macDelVxlan(key); - } - return; -} - -void FdbSync::onMsgLink(int nlmsg_type, struct nl_object *obj) -{ - struct rtnl_link *link; - char *ifname = NULL; - char *nil = "NULL"; - int ifindex; - unsigned int vni; - - link = (struct rtnl_link *)obj; - ifname = rtnl_link_get_name(link); - ifindex = rtnl_link_get_ifindex(link); - if (rtnl_link_is_vxlan(link) == 0) - { - return; - } - - if (rtnl_link_vxlan_get_id(link, &vni) != 0) - { - SWSS_LOG_INFO("Op:%d VxLAN dev:%s index:%d vni:%d. Not found", nlmsg_type, ifname? ifname: nil, ifindex, vni); - return; - } - SWSS_LOG_INFO("Op:%d VxLAN dev %s index:%d vni:%d", nlmsg_type, ifname? ifname: nil, ifindex, vni); - if (nlmsg_type == RTM_NEWLINK) - { - m_intf_info[ifindex].vni = vni; - m_intf_info[ifindex].ifname = ifname; - } - return; -} - -void FdbSync::onMsg(int nlmsg_type, struct nl_object *obj) -{ - if ((nlmsg_type != RTM_NEWLINK) && - (nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_DELNEIGH)) - { - SWSS_LOG_DEBUG("netlink: unhandled event: %d", nlmsg_type); - return; - } - if (nlmsg_type == RTM_NEWLINK) - { - onMsgLink(nlmsg_type, obj); - } - else - { - onMsgNbr(nlmsg_type, obj); - } -} - +#include +#include +#include +#include +#include +#include + +#include "logger.h" +#include "dbconnector.h" +#include "producerstatetable.h" +#include "ipaddress.h" +#include "netmsg.h" +#include "macaddress.h" +#include "exec.h" +#include "fdbsync.h" +#include "warm_restart.h" +#include "errno.h" + +using namespace std; +using namespace swss; + +#define VXLAN_BR_IF_NAME_PREFIX "Brvxlan" + +FdbSync::FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db) : + m_fdbTable(pipelineAppDB, APP_VXLAN_FDB_TABLE_NAME), + m_imetTable(pipelineAppDB, APP_VXLAN_REMOTE_VNI_TABLE_NAME), + m_fdbStateTable(stateDb, STATE_FDB_TABLE_NAME), + m_mclagRemoteFdbStateTable(stateDb, STATE_MCLAG_REMOTE_FDB_TABLE_NAME), + m_cfgEvpnNvoTable(config_db, CFG_VXLAN_EVPN_NVO_TABLE_NAME) +{ + m_AppRestartAssist = new AppRestartAssist(pipelineAppDB, "fdbsyncd", "swss", DEFAULT_FDBSYNC_WARMSTART_TIMER); + if (m_AppRestartAssist) + { + m_AppRestartAssist->registerAppTable(APP_VXLAN_FDB_TABLE_NAME, &m_fdbTable); + m_AppRestartAssist->registerAppTable(APP_VXLAN_REMOTE_VNI_TABLE_NAME, &m_imetTable); + } +} + +FdbSync::~FdbSync() +{ + if (m_AppRestartAssist) + { + delete m_AppRestartAssist; + } +} + +void FdbSync::processCfgEvpnNvo() +{ + std::deque entries; + m_cfgEvpnNvoTable.pops(entries); + bool lastNvoState = m_isEvpnNvoExist; + + for (auto entry: entries) + { + std::string op = kfvOp(entry); + + if (op == SET_COMMAND) + { + m_isEvpnNvoExist = true; + } + else if (op == DEL_COMMAND) + { + m_isEvpnNvoExist = false; + } + + if (lastNvoState != m_isEvpnNvoExist) + { + updateAllLocalMac(); + } + } + return; +} + +void FdbSync::updateAllLocalMac() +{ + for ( auto it = m_fdb_mac.begin(); it != m_fdb_mac.end(); ++it ) + { + if (m_isEvpnNvoExist) + { + /* Add the Local FDB entry into Kernel */ + addLocalMac(it->first, "replace"); + } + else + { + /* Delete the Local FDB entry from Kernel */ + addLocalMac(it->first, "del"); + } + } +} + +void FdbSync::processStateFdb() +{ + struct m_fdb_info info; + std::deque entries; + + m_fdbStateTable.pops(entries); + + int count =0 ; + for (auto entry: entries) + { + count++; + std::string key = kfvKey(entry); + std::string op = kfvOp(entry); + + std::size_t delimiter = key.find_first_of(":"); + auto vlan_name = key.substr(0, delimiter); + auto mac_address = key.substr(delimiter+1); + + info.vid = vlan_name; + info.mac = mac_address; + + if(op == "SET") + { + info.op_type = FDB_OPER_ADD ; + } + else + { + info.op_type = FDB_OPER_DEL ; + } + + SWSS_LOG_INFO("FDBSYNCD STATE FDB updates key=%s, operation=%s\n", key.c_str(), op.c_str()); + + for (auto i : kfvFieldsValues(entry)) + { + SWSS_LOG_INFO(" FDBSYNCD STATE FDB updates : " + "FvFiels %s, FvValues: %s \n", fvField(i).c_str(), fvValue(i).c_str()); + + if(fvField(i) == "port") + { + info.port_name = fvValue(i); + } + + if(fvField(i) == "type") + { + if(fvValue(i) == "dynamic") + { + info.type = FDB_TYPE_DYNAMIC; + } + else if (fvValue(i) == "static") + { + info.type = FDB_TYPE_STATIC; + } + } + } + + if (op != "SET" && macCheckSrcDB(&info) == false) + { + continue; + } + updateLocalMac(&info); + } +} + +void FdbSync::processStateMclagRemoteFdb() +{ + struct m_fdb_info info; + std::deque entries; + + m_mclagRemoteFdbStateTable.pops(entries); + + int count =0 ; + for (auto entry: entries) + { + count++; + std::string key = kfvKey(entry); + std::string op = kfvOp(entry); + + std::size_t delimiter = key.find_first_of(":"); + auto vlan_name = key.substr(0, delimiter); + auto mac_address = key.substr(delimiter+1); + + info.vid = vlan_name; + info.mac = mac_address; + + if(op == "SET") + { + info.op_type = FDB_OPER_ADD ; + } + else + { + info.op_type = FDB_OPER_DEL ; + } + + SWSS_LOG_INFO("FDBSYNCD STATE FDB updates key=%s, operation=%s\n", key.c_str(), op.c_str()); + + for (auto i : kfvFieldsValues(entry)) + { + SWSS_LOG_INFO(" FDBSYNCD STATE FDB updates : " + "FvFiels %s, FvValues: %s \n", fvField(i).c_str(), fvValue(i).c_str()); + + if(fvField(i) == "port") + { + info.port_name = fvValue(i); + } + + if(fvField(i) == "type") + { + if(fvValue(i) == "dynamic") + { + info.type = FDB_TYPE_DYNAMIC; + } + else if (fvValue(i) == "static") + { + info.type = FDB_TYPE_STATIC; + } + } + } + + if (op != "SET" && macCheckSrcDB(&info) == false) + { + continue; + } + updateMclagRemoteMac(&info); + } +} + +void FdbSync::macUpdateCache(struct m_fdb_info *info) +{ + string key = info->vid + ":" + info->mac; + m_fdb_mac[key].port_name = info->port_name; + m_fdb_mac[key].type = info->type; + + return; +} + +void FdbSync::macUpdateMclagRemoteCache(struct m_fdb_info *info) +{ + string key = info->vid + ":" + info->mac; + m_mclag_remote_fdb_mac[key].port_name = info->port_name; + m_mclag_remote_fdb_mac[key].type = info->type; + + return; +} + +bool FdbSync::macCheckSrcDB(struct m_fdb_info *info) +{ + string key = info->vid + ":" + info->mac; + if (m_fdb_mac.find(key) != m_fdb_mac.end()) + { + SWSS_LOG_INFO("DEL_KEY %s ", key.c_str()); + return true; + } + + return false; +} + +void FdbSync::macDelVxlanEntry(string auxkey, struct m_fdb_info *info) +{ + std::string vtep = m_mac[auxkey].vtep; + + const std::string cmds = std::string("") + + " bridge fdb del " + info->mac + " dev " + + m_mac[auxkey].ifname + " dst " + vtep + " vlan " + info->vid.substr(4); + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_INFO("Success cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + + return; +} + +void FdbSync::updateLocalMac (struct m_fdb_info *info) +{ + char *op; + char *type; + string port_name = ""; + string key = info->vid + ":" + info->mac; + short fdb_type; /*dynamic or static*/ + + if (info->op_type == FDB_OPER_ADD) + { + macUpdateCache(info); + op = "replace"; + port_name = info->port_name; + fdb_type = info->type; + /* Check if this vlan+key is also learned by vxlan neighbor then delete learned on */ + if (m_mac.find(key) != m_mac.end()) + { + macDelVxlanEntry(key, info); + SWSS_LOG_INFO("Local learn event deleting from VXLAN table DEL_KEY %s", key.c_str()); + macDelVxlan(key); + } + } + else + { + op = "del"; + port_name = m_fdb_mac[key].port_name; + fdb_type = m_fdb_mac[key].type; + m_fdb_mac.erase(key); + } + + if (!m_isEvpnNvoExist) + { + SWSS_LOG_INFO("Ignore kernel update EVPN NVO is not configured MAC %s", key.c_str()); + return; + } + + if (fdb_type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + op + " " + info->mac + " dev " + + port_name + " master " + type + " vlan " + info->vid.substr(4); + + std::string res; + int ret = swss::exec(cmds, res); + + SWSS_LOG_INFO("cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + + return; +} + +void FdbSync::addLocalMac(string key, string op) +{ + char *type; + string port_name = ""; + string mac = ""; + string vlan = ""; + size_t str_loc = string::npos; + + str_loc = key.find(":"); + if (str_loc == string::npos) + { + SWSS_LOG_ERROR("Local MAC issue with Key:%s", key.c_str()); + return; + } + vlan = key.substr(4, str_loc-4); + mac = key.substr(str_loc+1, std::string::npos); + + SWSS_LOG_INFO("Local route Vlan:%s MAC:%s Key:%s Op:%s", vlan.c_str(), mac.c_str(), key.c_str(), op.c_str()); + + if (m_fdb_mac.find(key)!=m_fdb_mac.end()) + { + port_name = m_fdb_mac[key].port_name; + if (port_name.empty()) + { + SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); + return; + } + + if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + op + " " + mac + " dev " + + port_name + " master " + type + " vlan " + vlan; + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_INFO("Config triggered cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + return; +} + +void FdbSync::updateMclagRemoteMac (struct m_fdb_info *info) +{ + char *op; + char *type; + string port_name = ""; + string key = info->vid + ":" + info->mac; + short fdb_type; /*dynamic or static*/ + + if (info->op_type == FDB_OPER_ADD) + { + macUpdateMclagRemoteCache(info); + op = "replace"; + port_name = info->port_name; + fdb_type = info->type; + } + else + { + op = "del"; + port_name = m_mclag_remote_fdb_mac[key].port_name; + fdb_type = m_mclag_remote_fdb_mac[key].type; + m_mclag_remote_fdb_mac.erase(key); + } + + if (fdb_type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + op + " " + info->mac + " dev " + + port_name + " master " + type + " vlan " + info->vid.substr(4); + + std::string res; + int ret = swss::exec(cmds, res); + + SWSS_LOG_INFO("cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + + return; +} + +/* + * This is a special case handling where mac is learned in the ASIC. + * Then MAC is learned in the Kernel, Since this mac is learned in the Kernel + * This MAC will age out, when MAC delete is received from the Kernel. + * If MAC is still present in the state DB cache then fdbsyncd will be + * re-programmed with MAC in the Kernel + */ +void FdbSync::macRefreshStateDB(int vlan, string kmac) +{ + string key = "Vlan" + to_string(vlan) + ":" + kmac; + char *type; + string port_name = ""; + + SWSS_LOG_INFO("Refreshing Vlan:%d MAC route MAC:%s Key %s", vlan, kmac.c_str(), key.c_str()); + + if (m_fdb_mac.find(key)!=m_fdb_mac.end()) + { + port_name = m_fdb_mac[key].port_name; + if (port_name.empty()) + { + SWSS_LOG_INFO("Port name not present MAC route Key:%s", key.c_str()); + return; + } + + if (m_fdb_mac[key].type == FDB_TYPE_DYNAMIC) + { + type = "dynamic"; + } + else + { + type = "static"; + } + + const std::string cmds = std::string("") + + " bridge fdb " + "replace" + " " + kmac + " dev " + + port_name + " master " + type + " vlan " + to_string(vlan); + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_INFO("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_INFO("Refreshing cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + return; +} + +bool FdbSync::checkImetExist(string key, uint32_t vni) +{ + if (m_imet_route.find(key) != m_imet_route.end()) + { + SWSS_LOG_INFO("IMET exist key:%s Vni:%d", key.c_str(), vni); + return false; + } + m_imet_route[key].vni = vni; + return true; +} + +bool FdbSync::checkDelImet(string key, uint32_t vni) +{ + int ret = false; + + SWSS_LOG_INFO("Del IMET key:%s Vni:%d", key.c_str(), vni); + if (m_imet_route.find(key) != m_imet_route.end()) + { + ret = true; + m_imet_route.erase(key); + } + return ret; +} + +void FdbSync::imetAddRoute(struct in_addr vtep, string vlan_str, uint32_t vni) +{ + string vlan_id = "Vlan" + vlan_str; + string key = vlan_id + ":" + inet_ntoa(vtep); + + if (!checkImetExist(key, vni)) + { + return; + } + + SWSS_LOG_INFO("%sIMET Add route key:%s vtep:%s %s", + m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", + key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); + + std::vector fvVector; + FieldValueTuple f("vni", to_string(vni)); + fvVector.push_back(f); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, false); + return; + } + + m_imetTable.set(key, fvVector); + return; +} + +void FdbSync::imetDelRoute(struct in_addr vtep, string vlan_str, uint32_t vni) +{ + string vlan_id = "Vlan" + vlan_str; + string key = vlan_id + ":" + inet_ntoa(vtep); + + if (!checkDelImet(key, vni)) + { + return; + } + + SWSS_LOG_INFO("%sIMET Del route key:%s vtep:%s %s", + m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "", + key.c_str(), inet_ntoa(vtep), vlan_id.c_str()); + + std::vector fvVector; + FieldValueTuple f("vni", to_string(vni)); + fvVector.push_back(f); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_REMOTE_VNI_TABLE_NAME, key, fvVector, true); + return; + } + + m_imetTable.del(key); + return; +} + +void FdbSync::macDelVxlanDB(string key) +{ + string vtep = m_mac[key].vtep; + string type; + string vni = to_string(m_mac[key].vni); + type = m_mac[key].type; + + std::vector fvVector; + FieldValueTuple rv("remote_vtep", vtep); + FieldValueTuple t("type", type); + FieldValueTuple v("vni", vni); + fvVector.push_back(rv); + fvVector.push_back(t); + fvVector.push_back(v); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, true); + return; + } + + SWSS_LOG_INFO("VXLAN_FDB_TABLE: DEL_KEY %s vtep:%s type:%s", key.c_str(), vtep.c_str(), type.c_str()); + m_fdbTable.del(key); + return; + +} + +void FdbSync::macAddVxlan(string key, struct in_addr vtep, string type, uint32_t vni, string intf_name) +{ + string svtep = inet_ntoa(vtep); + string svni = to_string(vni); + + /* Update the DB with Vxlan MAC */ + m_mac[key] = {svtep, type, vni, intf_name}; + + std::vector fvVector; + FieldValueTuple rv("remote_vtep", svtep); + FieldValueTuple t("type", type); + FieldValueTuple v("vni", svni); + fvVector.push_back(rv); + fvVector.push_back(t); + fvVector.push_back(v); + + // If warmstart is in progress, we take all netlink changes into the cache map + if (m_AppRestartAssist->isWarmStartInProgress()) + { + m_AppRestartAssist->insertToMap(APP_VXLAN_FDB_TABLE_NAME, key, fvVector, false); + return; + } + + SWSS_LOG_INFO("VXLAN_FDB_TABLE: ADD_KEY %s vtep:%s type:%s", key.c_str(), svtep.c_str(), type.c_str()); + m_fdbTable.set(key, fvVector); + + return; +} + +void FdbSync::macDelVxlan(string key) +{ + if (m_mac.find(key) != m_mac.end()) + { + SWSS_LOG_INFO("DEL_KEY %s vtep:%s type:%s", key.c_str(), m_mac[key].vtep.c_str(), m_mac[key].type.c_str()); + macDelVxlanDB(key); + m_mac.erase(key); + } + return; +} + +void FdbSync::onMsgNbr(int nlmsg_type, struct nl_object *obj) +{ + char macStr[MAX_ADDR_SIZE + 1] = {0}; + struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj; + struct in_addr vtep = {0}; + int vlan = 0, ifindex = 0; + uint32_t vni = 0; + nl_addr *vtep_addr; + string ifname; + string key; + bool delete_key = false; + size_t str_loc = string::npos; + string type = ""; + string vlan_id = ""; + bool isVxlanIntf = false; + + if ((nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_GETNEIGH) && + (nlmsg_type != RTM_DELNEIGH)) + { + return; + } + + /* Only MAC route is to be supported */ + if (rtnl_neigh_get_family(neigh) != AF_BRIDGE) + { + return; + } + ifindex = rtnl_neigh_get_ifindex(neigh); + if (m_intf_info.find(ifindex) != m_intf_info.end()) + { + isVxlanIntf = true; + ifname = m_intf_info[ifindex].ifname; + } + + nl_addr2str(rtnl_neigh_get_lladdr(neigh), macStr, MAX_ADDR_SIZE); + + if (isVxlanIntf == false) + { + if (nlmsg_type != RTM_DELNEIGH) + { + return; + } + } + else + { + /* If this is for vnet bridge vxlan interface, then return */ + if (ifname.find(VXLAN_BR_IF_NAME_PREFIX) != string::npos) + { + return; + } + + /* VxLan netdevice should be in - format */ + str_loc = ifname.rfind("-"); + if (str_loc == string::npos) + { + return; + } + + vlan_id = "Vlan" + ifname.substr(str_loc+1, std::string::npos); + vni = m_intf_info[ifindex].vni; + } + + + if (isVxlanIntf == false) + { + vlan = rtnl_neigh_get_vlan(neigh); + if (m_isEvpnNvoExist) + { + macRefreshStateDB(vlan, macStr); + } + return; + } + + vtep_addr = rtnl_neigh_get_dst(neigh); + if (vtep_addr == NULL) + { + return; + } + else + { + /* Currently we only support ipv4 tunnel endpoints */ + vtep.s_addr = *(uint32_t *)nl_addr_get_binary_addr(vtep_addr); + SWSS_LOG_INFO("Tunnel IP %s Int%d", inet_ntoa(vtep), *(uint32_t *)nl_addr_get_binary_addr(vtep_addr)); + } + + int state = rtnl_neigh_get_state(neigh); + if ((nlmsg_type == RTM_DELNEIGH) || (state == NUD_INCOMPLETE) || + (state == NUD_FAILED)) + { + delete_key = true; + } + + if (state & NUD_NOARP) + { + /* This is a static route */ + type = "static"; + } + else + { + type = "dynamic"; + } + + /* Handling IMET routes */ + if (MacAddress(macStr) == MacAddress("00:00:00:00:00:00")) + { + if (vtep.s_addr) + { + string vlan_str = ifname.substr(str_loc+1, string::npos); + + if (!delete_key) + { + imetAddRoute(vtep, vlan_str, vni); + } + else + { + imetDelRoute(vtep, vlan_str, vni); + } + } + return; + } + + key+= vlan_id; + key+= ":"; + key+= macStr; + + if (!delete_key) + { + macAddVxlan(key, vtep, type, vni, ifname); + } + else + { + macDelVxlan(key); + } + return; +} + +void FdbSync::onMsgLink(int nlmsg_type, struct nl_object *obj) +{ + struct rtnl_link *link; + char *ifname = NULL; + char *nil = "NULL"; + int ifindex; + unsigned int vni; + + link = (struct rtnl_link *)obj; + ifname = rtnl_link_get_name(link); + ifindex = rtnl_link_get_ifindex(link); + if (rtnl_link_is_vxlan(link) == 0) + { + return; + } + + if (rtnl_link_vxlan_get_id(link, &vni) != 0) + { + SWSS_LOG_INFO("Op:%d VxLAN dev:%s index:%d vni:%d. Not found", nlmsg_type, ifname? ifname: nil, ifindex, vni); + return; + } + SWSS_LOG_INFO("Op:%d VxLAN dev %s index:%d vni:%d", nlmsg_type, ifname? ifname: nil, ifindex, vni); + if (nlmsg_type == RTM_NEWLINK) + { + m_intf_info[ifindex].vni = vni; + m_intf_info[ifindex].ifname = ifname; + } + return; +} + +void FdbSync::onMsg(int nlmsg_type, struct nl_object *obj) +{ + if ((nlmsg_type != RTM_NEWLINK) && + (nlmsg_type != RTM_NEWNEIGH) && (nlmsg_type != RTM_DELNEIGH)) + { + SWSS_LOG_DEBUG("netlink: unhandled event: %d", nlmsg_type); + return; + } + if (nlmsg_type == RTM_NEWLINK) + { + onMsgLink(nlmsg_type, obj); + } + else + { + onMsgNbr(nlmsg_type, obj); + } +} + diff --git a/fdbsyncd/fdbsync.h b/fdbsyncd/fdbsync.h index 54815f0c30..a5547b745b 100644 --- a/fdbsyncd/fdbsync.h +++ b/fdbsyncd/fdbsync.h @@ -1,150 +1,150 @@ -#ifndef __FDBSYNC__ -#define __FDBSYNC__ - -#include -#include -#include "dbconnector.h" -#include "producerstatetable.h" -#include "subscriberstatetable.h" -#include "netmsg.h" -#include "warmRestartAssist.h" - -// The timeout value (in seconds) for fdbsyncd reconcilation logic -#define DEFAULT_FDBSYNC_WARMSTART_TIMER 30 - -namespace swss { - -enum FDB_OP_TYPE { - FDB_OPER_ADD =1, - FDB_OPER_DEL = 2, -}; - -enum FDB_TYPE { - FDB_TYPE_STATIC = 1, - FDB_TYPE_DYNAMIC = 2, -}; - -struct m_fdb_info -{ - std::string mac; - std::string vid; /*Store as Vlan */ - std::string port_name; - short type; /*dynamic or static*/ - short op_type; /*add or del*/ -}; - -class FdbSync : public NetMsg -{ -public: - enum { MAX_ADDR_SIZE = 64 }; - - FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db); - ~FdbSync(); - - virtual void onMsg(int nlmsg_type, struct nl_object *obj); - - bool isFdbRestoreDone(); - - AppRestartAssist *getRestartAssist() - { - return m_AppRestartAssist; - } - - SubscriberStateTable *getFdbStateTable() - { - return &m_fdbStateTable; - } - - SubscriberStateTable *getMclagRemoteFdbStateTable() - { - return &m_mclagRemoteFdbStateTable; - } - - SubscriberStateTable *getCfgEvpnNvoTable() - { - return &m_cfgEvpnNvoTable; - } - - void processStateFdb(); - - void processStateMclagRemoteFdb(); - - void processCfgEvpnNvo(); - - bool m_reconcileDone = false; - - bool m_isEvpnNvoExist = false; - -private: - ProducerStateTable m_fdbTable; - ProducerStateTable m_imetTable; - SubscriberStateTable m_fdbStateTable; - SubscriberStateTable m_mclagRemoteFdbStateTable; - AppRestartAssist *m_AppRestartAssist; - SubscriberStateTable m_cfgEvpnNvoTable; - - struct m_local_fdb_info - { - std::string port_name; - short type;/*dynamic or static*/ - }; - std::unordered_map m_fdb_mac; - - std::unordered_map m_mclag_remote_fdb_mac; - - void macDelVxlanEntry(std::string auxkey, struct m_fdb_info *info); - - void macUpdateCache(struct m_fdb_info *info); - - bool macCheckSrcDB(struct m_fdb_info *info); - - void updateLocalMac(struct m_fdb_info *info); - - void updateAllLocalMac(); - - void macRefreshStateDB(int vlan, std::string kmac); - - void updateMclagRemoteMac(struct m_fdb_info *info); - - void macUpdateMclagRemoteCache(struct m_fdb_info *info); - - bool checkImetExist(std::string key, uint32_t vni); - - bool checkDelImet(std::string key, uint32_t vni); - - struct m_mac_info - { - std::string vtep; - std::string type; - unsigned int vni; - std::string ifname; - }; - std::unordered_map m_mac; - - struct m_imet_info - { - unsigned int vni; - }; - std::unordered_map m_imet_route; - - struct intf - { - std::string ifname; - unsigned int vni; - }; - std::unordered_map m_intf_info; - - void addLocalMac(std::string key, std::string op); - void macAddVxlan(std::string key, struct in_addr vtep, std::string type, uint32_t vni, std::string intf_name); - void macDelVxlan(std::string auxkey); - void macDelVxlanDB(std::string key); - void imetAddRoute(struct in_addr vtep, std::string ifname, uint32_t vni); - void imetDelRoute(struct in_addr vtep, std::string ifname, uint32_t vni); - void onMsgNbr(int nlmsg_type, struct nl_object *obj); - void onMsgLink(int nlmsg_type, struct nl_object *obj); -}; - -} - -#endif - +#ifndef __FDBSYNC__ +#define __FDBSYNC__ + +#include +#include +#include "dbconnector.h" +#include "producerstatetable.h" +#include "subscriberstatetable.h" +#include "netmsg.h" +#include "warmRestartAssist.h" + +// The timeout value (in seconds) for fdbsyncd reconcilation logic +#define DEFAULT_FDBSYNC_WARMSTART_TIMER 30 + +namespace swss { + +enum FDB_OP_TYPE { + FDB_OPER_ADD =1, + FDB_OPER_DEL = 2, +}; + +enum FDB_TYPE { + FDB_TYPE_STATIC = 1, + FDB_TYPE_DYNAMIC = 2, +}; + +struct m_fdb_info +{ + std::string mac; + std::string vid; /*Store as Vlan */ + std::string port_name; + short type; /*dynamic or static*/ + short op_type; /*add or del*/ +}; + +class FdbSync : public NetMsg +{ +public: + enum { MAX_ADDR_SIZE = 64 }; + + FdbSync(RedisPipeline *pipelineAppDB, DBConnector *stateDb, DBConnector *config_db); + ~FdbSync(); + + virtual void onMsg(int nlmsg_type, struct nl_object *obj); + + bool isFdbRestoreDone(); + + AppRestartAssist *getRestartAssist() + { + return m_AppRestartAssist; + } + + SubscriberStateTable *getFdbStateTable() + { + return &m_fdbStateTable; + } + + SubscriberStateTable *getMclagRemoteFdbStateTable() + { + return &m_mclagRemoteFdbStateTable; + } + + SubscriberStateTable *getCfgEvpnNvoTable() + { + return &m_cfgEvpnNvoTable; + } + + void processStateFdb(); + + void processStateMclagRemoteFdb(); + + void processCfgEvpnNvo(); + + bool m_reconcileDone = false; + + bool m_isEvpnNvoExist = false; + +private: + ProducerStateTable m_fdbTable; + ProducerStateTable m_imetTable; + SubscriberStateTable m_fdbStateTable; + SubscriberStateTable m_mclagRemoteFdbStateTable; + AppRestartAssist *m_AppRestartAssist; + SubscriberStateTable m_cfgEvpnNvoTable; + + struct m_local_fdb_info + { + std::string port_name; + short type;/*dynamic or static*/ + }; + std::unordered_map m_fdb_mac; + + std::unordered_map m_mclag_remote_fdb_mac; + + void macDelVxlanEntry(std::string auxkey, struct m_fdb_info *info); + + void macUpdateCache(struct m_fdb_info *info); + + bool macCheckSrcDB(struct m_fdb_info *info); + + void updateLocalMac(struct m_fdb_info *info); + + void updateAllLocalMac(); + + void macRefreshStateDB(int vlan, std::string kmac); + + void updateMclagRemoteMac(struct m_fdb_info *info); + + void macUpdateMclagRemoteCache(struct m_fdb_info *info); + + bool checkImetExist(std::string key, uint32_t vni); + + bool checkDelImet(std::string key, uint32_t vni); + + struct m_mac_info + { + std::string vtep; + std::string type; + unsigned int vni; + std::string ifname; + }; + std::unordered_map m_mac; + + struct m_imet_info + { + unsigned int vni; + }; + std::unordered_map m_imet_route; + + struct intf + { + std::string ifname; + unsigned int vni; + }; + std::unordered_map m_intf_info; + + void addLocalMac(std::string key, std::string op); + void macAddVxlan(std::string key, struct in_addr vtep, std::string type, uint32_t vni, std::string intf_name); + void macDelVxlan(std::string auxkey); + void macDelVxlanDB(std::string key); + void imetAddRoute(struct in_addr vtep, std::string ifname, uint32_t vni); + void imetDelRoute(struct in_addr vtep, std::string ifname, uint32_t vni); + void onMsgNbr(int nlmsg_type, struct nl_object *obj); + void onMsgLink(int nlmsg_type, struct nl_object *obj); +}; + +} + +#endif + diff --git a/fdbsyncd/fdbsyncd.cpp b/fdbsyncd/fdbsyncd.cpp index f734cf9616..99492df184 100644 --- a/fdbsyncd/fdbsyncd.cpp +++ b/fdbsyncd/fdbsyncd.cpp @@ -1,110 +1,110 @@ -#include -#include -#include -#include -#include "logger.h" -#include "select.h" -#include "netdispatcher.h" -#include "netlink.h" -#include "fdbsyncd/fdbsync.h" - -using namespace std; -using namespace swss; - -int main(int argc, char **argv) -{ - Logger::linkToDbNative("fdbsyncd"); - - DBConnector appDb(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - RedisPipeline pipelineAppDB(&appDb); - DBConnector stateDb(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - DBConnector log_db(LOGLEVEL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - DBConnector config_db(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - - FdbSync sync(&pipelineAppDB, &stateDb, &config_db); - - NetDispatcher::getInstance().registerMessageHandler(RTM_NEWNEIGH, &sync); - NetDispatcher::getInstance().registerMessageHandler(RTM_DELNEIGH, &sync); - NetDispatcher::getInstance().registerMessageHandler(RTM_NEWLINK, &sync); - - while (1) - { - try - { - NetLink netlink; - Selectable *temps; - int ret; - Select s; - - using namespace std::chrono; - - /* - * If WarmStart is enabled, restore the VXLAN-FDB and VNI - * tables and start a reconcillation timer - */ - if (sync.getRestartAssist()->isWarmStartInProgress()) - { - sync.getRestartAssist()->readTablesToMap(); - SWSS_LOG_NOTICE("Starting ReconcileTimer"); - } - - netlink.registerGroup(RTNLGRP_LINK); - netlink.registerGroup(RTNLGRP_NEIGH); - SWSS_LOG_NOTICE("Listens to link and neigh messages..."); - netlink.dumpRequest(RTM_GETLINK); - s.addSelectable(&netlink); - ret = s.select(&temps, 1); - if (ret == Select::ERROR) - { - SWSS_LOG_ERROR("Error in RTM_GETLINK dump"); - } - - netlink.dumpRequest(RTM_GETNEIGH); - - s.addSelectable(sync.getFdbStateTable()); - s.addSelectable(sync.getMclagRemoteFdbStateTable()); - s.addSelectable(sync.getCfgEvpnNvoTable()); - while (true) - { - s.select(&temps); - - if(temps == (Selectable *)sync.getFdbStateTable()) - { - sync.processStateFdb(); - } - else if(temps == (Selectable *)sync.getMclagRemoteFdbStateTable()) - { - sync.processStateMclagRemoteFdb(); - } - else if (temps == (Selectable *)sync.getCfgEvpnNvoTable()) - { - sync.processCfgEvpnNvo(); - } - else - { - /* - * If warmstart is in progress, we check the reconcile timer, - * if timer expired, we stop the timer and start the reconcile process - */ - if (sync.getRestartAssist()->isWarmStartInProgress()) - { - if (sync.getRestartAssist()->checkReconcileTimer(temps)) - { - sync.m_reconcileDone = true; - sync.getRestartAssist()->stopReconcileTimer(s); - sync.getRestartAssist()->reconcile(); - SWSS_LOG_NOTICE("VXLAN FDB VNI Reconcillation Complete (Timer)"); - } - } - } - } - } - catch (const std::exception& e) - { - cout << "Exception \"" << e.what() << "\" had been thrown in deamon" << endl; - return 0; - } - } - - return 1; -} +#include +#include +#include +#include +#include "logger.h" +#include "select.h" +#include "netdispatcher.h" +#include "netlink.h" +#include "fdbsyncd/fdbsync.h" + +using namespace std; +using namespace swss; + +int main(int argc, char **argv) +{ + Logger::linkToDbNative("fdbsyncd"); + + DBConnector appDb(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + RedisPipeline pipelineAppDB(&appDb); + DBConnector stateDb(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + DBConnector log_db(LOGLEVEL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + DBConnector config_db(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + + FdbSync sync(&pipelineAppDB, &stateDb, &config_db); + + NetDispatcher::getInstance().registerMessageHandler(RTM_NEWNEIGH, &sync); + NetDispatcher::getInstance().registerMessageHandler(RTM_DELNEIGH, &sync); + NetDispatcher::getInstance().registerMessageHandler(RTM_NEWLINK, &sync); + + while (1) + { + try + { + NetLink netlink; + Selectable *temps; + int ret; + Select s; + + using namespace std::chrono; + + /* + * If WarmStart is enabled, restore the VXLAN-FDB and VNI + * tables and start a reconcillation timer + */ + if (sync.getRestartAssist()->isWarmStartInProgress()) + { + sync.getRestartAssist()->readTablesToMap(); + SWSS_LOG_NOTICE("Starting ReconcileTimer"); + } + + netlink.registerGroup(RTNLGRP_LINK); + netlink.registerGroup(RTNLGRP_NEIGH); + SWSS_LOG_NOTICE("Listens to link and neigh messages..."); + netlink.dumpRequest(RTM_GETLINK); + s.addSelectable(&netlink); + ret = s.select(&temps, 1); + if (ret == Select::ERROR) + { + SWSS_LOG_ERROR("Error in RTM_GETLINK dump"); + } + + netlink.dumpRequest(RTM_GETNEIGH); + + s.addSelectable(sync.getFdbStateTable()); + s.addSelectable(sync.getMclagRemoteFdbStateTable()); + s.addSelectable(sync.getCfgEvpnNvoTable()); + while (true) + { + s.select(&temps); + + if(temps == (Selectable *)sync.getFdbStateTable()) + { + sync.processStateFdb(); + } + else if(temps == (Selectable *)sync.getMclagRemoteFdbStateTable()) + { + sync.processStateMclagRemoteFdb(); + } + else if (temps == (Selectable *)sync.getCfgEvpnNvoTable()) + { + sync.processCfgEvpnNvo(); + } + else + { + /* + * If warmstart is in progress, we check the reconcile timer, + * if timer expired, we stop the timer and start the reconcile process + */ + if (sync.getRestartAssist()->isWarmStartInProgress()) + { + if (sync.getRestartAssist()->checkReconcileTimer(temps)) + { + sync.m_reconcileDone = true; + sync.getRestartAssist()->stopReconcileTimer(s); + sync.getRestartAssist()->reconcile(); + SWSS_LOG_NOTICE("VXLAN FDB VNI Reconcillation Complete (Timer)"); + } + } + } + } + } + catch (const std::exception& e) + { + cout << "Exception \"" << e.what() << "\" had been thrown in deamon" << endl; + return 0; + } + } + + return 1; +} From 923d1beffea43ea36fbcfd49bd083cab6b46b727 Mon Sep 17 00:00:00 2001 From: Tapash Das Date: Fri, 5 Feb 2021 23:40:08 -0800 Subject: [PATCH 14/54] MCLAG Unique IP support changes. --- fdbsyncd/fdbsync.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ fdbsyncd/fdbsync.h | 2 ++ 2 files changed, 45 insertions(+) diff --git a/fdbsyncd/fdbsync.cpp b/fdbsyncd/fdbsync.cpp index 32870210ff..c80b171192 100644 --- a/fdbsyncd/fdbsync.cpp +++ b/fdbsyncd/fdbsync.cpp @@ -418,6 +418,39 @@ void FdbSync::updateMclagRemoteMac (struct m_fdb_info *info) return; } +void FdbSync::updateMclagRemoteMacPort(int ifindex, int vlan, std::string mac) +{ + string key = "Vlan" + to_string(vlan) + ":" + mac; + int type = 0; + string port_name = ""; + + SWSS_LOG_INFO("Updating Intf %d, Vlan:%d MAC:%s Key %s", ifindex, vlan, mac.c_str(), key.c_str()); + + if (m_mclag_remote_fdb_mac.find(key) != m_mclag_remote_fdb_mac.end()) + { + type = m_mclag_remote_fdb_mac[key].type; + port_name = m_mclag_remote_fdb_mac[key].port_name; + SWSS_LOG_INFO(" port %s, type %d\n", port_name.c_str(), type); + + if (type == FDB_TYPE_STATIC) + { + const std::string cmds = std::string("") + + " bridge fdb " + "replace" + " " + mac + " dev " + + port_name + " master " + "static" + " vlan " + to_string(vlan); + + std::string res; + int ret = swss::exec(cmds, res); + if (ret != 0) + { + SWSS_LOG_NOTICE("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + + SWSS_LOG_NOTICE("Update cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + } + } + return; +} + /* * This is a special case handling where mac is learned in the ASIC. * Then MAC is learned in the Kernel, Since this mac is learned in the Kernel @@ -655,6 +688,16 @@ void FdbSync::onMsgNbr(int nlmsg_type, struct nl_object *obj) if (isVxlanIntf == false) { + if (nlmsg_type == RTM_NEWNEIGH) + { + int vid = rtnl_neigh_get_vlan(neigh); + int state = rtnl_neigh_get_state(neigh); + if (state & NUD_PERMANENT) + { + updateMclagRemoteMacPort(ifindex, vid, macStr); + } + } + if (nlmsg_type != RTM_DELNEIGH) { return; diff --git a/fdbsyncd/fdbsync.h b/fdbsyncd/fdbsync.h index a5547b745b..ecd4182926 100644 --- a/fdbsyncd/fdbsync.h +++ b/fdbsyncd/fdbsync.h @@ -106,6 +106,8 @@ class FdbSync : public NetMsg void updateMclagRemoteMac(struct m_fdb_info *info); + void updateMclagRemoteMacPort(int ifindex, int vlan, std::string mac); + void macUpdateMclagRemoteCache(struct m_fdb_info *info); bool checkImetExist(std::string key, uint32_t vni); From b395b18aa32806b173d4246849bf5f0898fe0010 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Mon, 19 Apr 2021 16:50:41 -0700 Subject: [PATCH 15/54] Removed dependency with PR 885. --- orchagent/fdborch.cpp | 908 ++++++++++--------- orchagent/fdborch.h | 34 +- orchagent/notifications.cpp | 2 +- orchagent/port.h | 34 +- orchagent/portsorch.cpp | 1629 +++++++++++++++++++++++++---------- orchagent/portsorch.h | 61 +- 6 files changed, 1795 insertions(+), 873 deletions(-) diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index 7411dcbb54..2280c46edb 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -70,9 +70,8 @@ bool FdbOrch::bake() bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) { const FdbEntry& entry = update.entry; - const FdbData fdbdata = {update.port.m_bridge_port_id, update.type, FDB_ORIGIN_LEARN}; + FdbData fdbdata; FdbData oldFdbData; - const Port& port = update.port; const MacAddress& mac = entry.mac; string portName = port.m_alias; @@ -94,13 +93,16 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) auto it = m_entries.find(entry); if (it != m_entries.end()) { + /* This block is specifically added for MAC_MOVE event + and not expected to be executed for LEARN event + */ if (port.m_bridge_port_id == it->second.bridge_port_id) { - if (it->second.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + if (it->second.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) { mac_move=true; oldFdbData = it->second; - } + } else { SWSS_LOG_INFO("FdbOrch notification: mac %s is duplicate", entry.mac.to_string().c_str()); @@ -108,13 +110,20 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) } } mac_move = true; - oldFdbData = it->second; + oldFdbData = it->second; } + fdbdata.bridge_port_id = update.port.m_bridge_port_id; + fdbdata.type = update.type; + fdbdata.origin = FDB_ORIGIN_LEARN; + fdbdata.remote_ip = ""; + fdbdata.esi = ""; + fdbdata.vni = 0; + m_entries[entry] = fdbdata; - SWSS_LOG_DEBUG("FdbOrch notification: mac %s was inserted into bv_id 0x%" PRIx64, - entry.mac.to_string().c_str(), entry.bv_id); - SWSS_LOG_DEBUG("m_entries size=%lu mac=%s port=0x%" PRIx64, + SWSS_LOG_INFO("FdbOrch notification: mac %s was inserted in port %s into bv_id 0x%" PRIx64, + entry.mac.to_string().c_str(), portName.c_str(), entry.bv_id); + SWSS_LOG_INFO("m_entries size=%zu mac=%s port=0x%" PRIx64, m_entries.size(), entry.mac.to_string().c_str(), m_entries[entry].bridge_port_id); if (mac_move && (oldFdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED)) @@ -128,7 +137,6 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) std::vector fvs; fvs.push_back(FieldValueTuple("port", portName)); fvs.push_back(FieldValueTuple("type", update.type)); - m_fdbStateTable.set(key, fvs); if (!mac_move) @@ -144,6 +152,7 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) { oldFdbData = it->second; } + size_t erased = m_entries.erase(entry); SWSS_LOG_DEBUG("FdbOrch notification: mac %s was removed from bv_id 0x%" PRIx64, entry.mac.to_string().c_str(), entry.bv_id); @@ -159,8 +168,12 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) m_mclagFdbStateTable.del(key); } - // Remove in StateDb - m_fdbStateTable.del(key); + if ((oldFdbData.origin != FDB_ORIGIN_VXLAN_ADVERTIZED) && + (oldFdbData.origin != FDB_ORIGIN_MCLAG_ADVERTIZED)) + { + // Remove in StateDb for non advertised mac addresses + m_fdbStateTable.del(key); + } gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); return true; @@ -184,11 +197,24 @@ void FdbOrch::update(sai_fdb_event_t type, type, update.entry.mac.to_string().c_str(), entry->bv_id, bridge_port_id); + if (bridge_port_id && !m_portsOrch->getPortByBridgePortId(bridge_port_id, update.port)) { - SWSS_LOG_ERROR("Failed to get port by bridge port ID 0x%" PRIx64 ".", + if (type == SAI_FDB_EVENT_FLUSHED) + { + /* In case of flush - can be ignored due to a race. + There are notifications about FDB FLUSH (syncd/sai_redis) on port, + which was already removed by orchagent as a result of + removeVlanMember action (removeBridgePort) */ + SWSS_LOG_INFO("Flush event: Failed to get port by bridge port ID 0x%" PRIx64 ".", + bridge_port_id); + + } else { + SWSS_LOG_ERROR("Failed to get port by bridge port ID 0x%" PRIx64 ".", bridge_port_id); + + } return; } @@ -204,21 +230,11 @@ void FdbOrch::update(sai_fdb_event_t type, return; } - if (!m_portsOrch->getPortByBridgePortId(bridge_port_id, update.port)) - { - SWSS_LOG_ERROR("FdbOrch LEARN notification: Failed to get port by bridge port ID 0x%" PRIx64, bridge_port_id); - return; - } - // we already have such entries auto existing_entry = m_entries.find(update.entry); if (existing_entry != m_entries.end()) { - SWSS_LOG_INFO("FdbOrch LEARN notification: mac %s is already in bv_id 0x%" - PRIx64 "existing-bp 0x%" PRIx64 "new-bp:0x%" PRIx64, - update.entry.mac.to_string().c_str(), entry->bv_id, existing_entry->second.bridge_port_id, bridge_port_id); - - if (existing_entry->second.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + if (existing_entry->second.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) { // If the bp is different MOVE the MAC entry. if (existing_entry->second.bridge_port_id != bridge_port_id) @@ -284,58 +300,53 @@ void FdbOrch::update(sai_fdb_event_t type, } else { - SWSS_LOG_NOTICE("FdbOrch LEARN notification: mac %s is already in bv_id 0x%lx existing-bp 0x%lx new-bp:0x%lx ", - update.entry.mac.to_string().c_str(), entry->bv_id, existing_entry->second.bridge_port_id, bridge_port_id); - break; + SWSS_LOG_INFO("FdbOrch LEARN notification: mac %s is already in bv_id 0x%" + PRIx64 "existing-bp 0x%" PRIx64 "new-bp:0x%" PRIx64, + update.entry.mac.to_string().c_str(), entry->bv_id, existing_entry->second.bridge_port_id, bridge_port_id); } - + break; } update.add = true; - update.type = "dynamic"; update.entry.port_name = update.port.m_alias; - storeFdbEntryState(update); + update.type = "dynamic"; update.port.m_fdb_count++; m_portsOrch->setPort(update.port.m_alias, update.port); vlan.m_fdb_count++; m_portsOrch->setPort(vlan.m_alias, vlan); - SWSS_LOG_INFO("Notifying observers of FDB entry LEARN"); - + storeFdbEntryState(update); notify(SUBJECT_TYPE_FDB_CHANGE, &update); break; } case SAI_FDB_EVENT_AGED: { - SWSS_LOG_INFO("Received AGE event for bvid=%lx mac=%s port=%lx", entry->bv_id, update.entry.mac.to_string().c_str(), bridge_port_id); + SWSS_LOG_INFO("Received AGE event for bvid=0x%" PRIx64 " mac=%s port=0x%" PRIx64, + entry->bv_id, update.entry.mac.to_string().c_str(), bridge_port_id); if (!m_portsOrch->getPort(entry->bv_id, vlan)) { - SWSS_LOG_NOTICE("FdbOrch AGE notification: Failed to locate vlan port from bv_id 0x%lx", entry->bv_id); + SWSS_LOG_NOTICE("FdbOrch AGE notification: Failed to locate vlan port from bv_id 0x%" PRIx64, entry->bv_id); } auto existing_entry = m_entries.find(update.entry); // we don't have such entries if (existing_entry == m_entries.end()) { - SWSS_LOG_INFO("FdbOrch AGE notification: mac %s is not present in bv_id 0x%lx bp 0x%lx", + SWSS_LOG_INFO("FdbOrch AGE notification: mac %s is not present in bv_id 0x%" PRIx64 " bp 0x%" PRIx64, update.entry.mac.to_string().c_str(), entry->bv_id, bridge_port_id); break; } - if (!m_portsOrch->getPortByBridgePortId(bridge_port_id, update.port)) - { - SWSS_LOG_NOTICE("FdbOrch AGE notification: Failed to get port by bridge port ID 0x%lx", bridge_port_id); - } - if (existing_entry->second.bridge_port_id != bridge_port_id) { - SWSS_LOG_NOTICE("FdbOrch AGE notification: Stale aging event received for mac-bv_id %s-0x%lx with bp=0x%lx existing bp=0x%lx", update.entry.mac.to_string().c_str(), entry->bv_id, bridge_port_id, existing_entry->second.bridge_port_id); + SWSS_LOG_INFO("FdbOrch AGE notification: Stale aging event received for mac-bv_id %s-0x%" PRIx64 " with bp=0x%" PRIx64 " existing bp=0x%" PRIx64, + update.entry.mac.to_string().c_str(), entry->bv_id, bridge_port_id, existing_entry->second.bridge_port_id); // We need to get the port for bridge-port in existing fdb if (!m_portsOrch->getPortByBridgePortId(existing_entry->second.bridge_port_id, update.port)) { - SWSS_LOG_NOTICE("FdbOrch AGE notification: Failed to get port by bridge port ID 0x%lx", existing_entry->second.bridge_port_id); + SWSS_LOG_INFO("FdbOrch AGE notification: Failed to get port by bridge port ID 0x%" PRIx64, existing_entry->second.bridge_port_id); } // dont return, let it delete just to bring SONiC and SAI in sync // return; @@ -343,16 +354,25 @@ void FdbOrch::update(sai_fdb_event_t type, if (existing_entry->second.type == "static") { + update.type = "static"; + if (vlan.m_members.find(update.port.m_alias) == vlan.m_members.end()) { - update.type = "static"; - saved_fdb_entries[update.port.m_alias].push_back({existing_entry->first.mac, vlan.m_vlan_info.vlan_id, "static", FDB_ORIGIN_PROVISIONED }); + FdbData fdbData; + fdbData.bridge_port_id = SAI_NULL_OBJECT_ID; + fdbData.type = update.type; + fdbData.origin = existing_entry->second.origin; + fdbData.remote_ip = existing_entry->second.remote_ip; + fdbData.esi = existing_entry->second.esi; + fdbData.vni = existing_entry->second.vni; + saved_fdb_entries[update.port.m_alias].push_back( + {existing_entry->first.mac, vlan.m_vlan_info.vlan_id, fdbData}); } else { /*port added back to vlan before we receive delete notification for flush from SAI. Re-add entry to SAI - */ + */ sai_attribute_t attr; vector attrs; @@ -367,7 +387,10 @@ void FdbOrch::update(sai_fdb_event_t type, { SWSS_LOG_ERROR("Failed to create FDB %s on %s, rv:%d", existing_entry->first.mac.to_string().c_str(), update.port.m_alias.c_str(), status); - return; + if (handleSaiCreateStatus(SAI_API_FDB, status) != task_success) + { + return; + } } return; } @@ -413,10 +436,10 @@ void FdbOrch::update(sai_fdb_event_t type, } return; } + update.add = false; - storeFdbEntryState(update); if (!update.port.m_alias.empty()) - { + { update.port.m_fdb_count--; m_portsOrch->setPort(update.port.m_alias, update.port); } @@ -425,9 +448,11 @@ void FdbOrch::update(sai_fdb_event_t type, vlan.m_fdb_count--; m_portsOrch->setPort(vlan.m_alias, vlan); } + storeFdbEntryState(update); - SWSS_LOG_INFO("Notifying observers of FDB entry removal on AGED/MOVED"); notify(SUBJECT_TYPE_FDB_CHANGE, &update); + + notifyTunnelOrch(update.port); break; } case SAI_FDB_EVENT_MOVE: @@ -435,32 +460,28 @@ void FdbOrch::update(sai_fdb_event_t type, Port port_old; auto existing_entry = m_entries.find(update.entry); - SWSS_LOG_INFO("Received MOVE event for bvid=%lx mac=%s port=%lx", entry->bv_id, update.entry.mac.to_string().c_str(), bridge_port_id); - update.add = true; + SWSS_LOG_INFO("Received MOVE event for bvid=0x%" PRIx64 " mac=%s port=0x%" PRIx64, + entry->bv_id, update.entry.mac.to_string().c_str(), bridge_port_id); if (!m_portsOrch->getPort(entry->bv_id, vlan)) { - SWSS_LOG_ERROR("FdbOrch MOVE notification: Failed to locate vlan port from bv_id 0x%lx", entry->bv_id); - return; - } - - if (!m_portsOrch->getPortByBridgePortId(bridge_port_id, update.port)) - { - SWSS_LOG_ERROR("FdbOrch MOVE notification: Failed to get port by bridge port ID 0x%lx", bridge_port_id); + SWSS_LOG_ERROR("FdbOrch MOVE notification: Failed to locate vlan port from bv_id 0x%" PRIx64, entry->bv_id); return; } // We should already have such entry if (existing_entry == m_entries.end()) { - SWSS_LOG_WARN("FdbOrch MOVE notification: mac %s is not found in bv_id 0x%lx", + SWSS_LOG_WARN("FdbOrch MOVE notification: mac %s is not found in bv_id 0x%" PRIx64, update.entry.mac.to_string().c_str(), entry->bv_id); } else if (!m_portsOrch->getPortByBridgePortId(existing_entry->second.bridge_port_id, port_old)) { - SWSS_LOG_ERROR("FdbOrch MOVE notification: Failed to get port by bridge port ID 0x%lx", existing_entry->second.bridge_port_id); + SWSS_LOG_ERROR("FdbOrch MOVE notification: Failed to get port by bridge port ID 0x%" PRIx64, existing_entry->second.bridge_port_id); return; } + + update.add = true; if (!port_old.m_alias.empty()) { port_old.m_fdb_count--; @@ -468,67 +489,102 @@ void FdbOrch::update(sai_fdb_event_t type, } update.port.m_fdb_count++; m_portsOrch->setPort(update.port.m_alias, update.port); - storeFdbEntryState(update); notify(SUBJECT_TYPE_FDB_CHANGE, &update); + notifyTunnelOrch(port_old); + break; } - case SAI_FDB_EVENT_FLUSHED: - SWSS_LOG_INFO("Received FLUSH event for bvid=%lx mac=%s port=%lx", entry->bv_id, update.entry.mac.to_string().c_str(), bridge_port_id); - for (auto itr = m_entries.begin(); itr != m_entries.end();) - { - if (itr->second.type == "static") - { - itr++; - continue; - } - if (((bridge_port_id == SAI_NULL_OBJECT_ID) && (entry->bv_id == SAI_NULL_OBJECT_ID)) // Flush all DYNAMIC - || ((bridge_port_id == itr->second.bridge_port_id) && (entry->bv_id == SAI_NULL_OBJECT_ID)) // flush all DYN on a port - || ((bridge_port_id == SAI_NULL_OBJECT_ID) && (entry->bv_id == itr->first.bv_id))) // flush all DYN on a vlan - { + SWSS_LOG_INFO("FDB Flush event received: [ %s , 0x%" PRIx64 " ], \ + bridge port ID: 0x%" PRIx64 ".", + update.entry.mac.to_string().c_str(), entry->bv_id, + bridge_port_id); - if (!m_portsOrch->getPortByBridgePortId(itr->second.bridge_port_id, update.port)) - { - SWSS_LOG_ERROR("FdbOrch FLUSH notification: Failed to get port by bridge port ID 0x%lx", itr->second.bridge_port_id); - itr++; - continue; - } + string vlanName = "-"; + if (entry->bv_id) { + Port vlan; - if (!m_portsOrch->getPort(itr->first.bv_id, vlan)) - { - SWSS_LOG_NOTICE("FdbOrch FLUSH notification: Failed to locate vlan port from bv_id 0x%lx", itr->first.bv_id); - itr++; - continue; - } + if (!m_portsOrch->getPort(entry->bv_id, vlan)) + { + SWSS_LOG_NOTICE("FdbOrch notification: Failed to locate vlan\ + port from bv_id 0x%" PRIx64, entry->bv_id); + return; + } + vlanName = "Vlan" + to_string(vlan.m_vlan_info.vlan_id); + } + + if (bridge_port_id == SAI_NULL_OBJECT_ID && + entry->bv_id == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_INFO("FDB Flush: [ %s , %s ] = { port: - }", + update.entry.mac.to_string().c_str(), vlanName.c_str()); + for (auto itr = m_entries.begin(); itr != m_entries.end();) + { + /* + TODO: here should only delete the dynamic fdb entries, + but unfortunately in structure FdbEntry currently have + no member to indicate the fdb entry type, + if there is static mac added, here will have issue. + */ update.entry.mac = itr->first.mac; update.entry.bv_id = itr->first.bv_id; update.add = false; - update.vlan_id = vlan.m_vlan_info.vlan_id; itr++; - - update.port.m_fdb_count--; - m_portsOrch->setPort(update.port.m_alias, update.port); - vlan.m_fdb_count--; - m_portsOrch->setPort(vlan.m_alias, vlan); - - /* This will invalidate the current iterator hence itr++ is done before */ storeFdbEntryState(update); - SWSS_LOG_DEBUG("FdbOrch FLUSH notification: mac %s was removed", update.entry.mac.to_string().c_str()); - - notify(SUBJECT_TYPE_FDB_CHANGE, &update); + for (auto observer: m_observers) + { + observer->update(SUBJECT_TYPE_FDB_CHANGE, &update); + } } - else + } + else if (entry->bv_id == SAI_NULL_OBJECT_ID) + { + /* FLUSH based on port */ + SWSS_LOG_INFO("FDB Flush: [ %s , %s ] = { port: %s }", + update.entry.mac.to_string().c_str(), + vlanName.c_str(), update.port.m_alias.c_str()); + + for (auto itr = m_entries.begin(); itr != m_entries.end();) { - itr++; + auto next_item = std::next(itr); + if (itr->first.port_name == update.port.m_alias) + { + update.entry.mac = itr->first.mac; + update.entry.bv_id = itr->first.bv_id; + update.add = false; + + storeFdbEntryState(update); + + for (auto observer: m_observers) + { + observer->update(SUBJECT_TYPE_FDB_CHANGE, &update); + } + } + itr = next_item; } } + else if (bridge_port_id == SAI_NULL_OBJECT_ID) + { + /* FLUSH based on VLAN - unsupported */ + SWSS_LOG_ERROR("Unsupported FDB Flush: [ %s , %s ] = { port: - }", + update.entry.mac.to_string().c_str(), + vlanName.c_str()); + + } + else + { + /* FLUSH based on port and VLAN - unsupported */ + SWSS_LOG_ERROR("Unsupported FDB Flush: [ %s , %s ] = { port: %s }", + update.entry.mac.to_string().c_str(), + vlanName.c_str(), update.port.m_alias.c_str()); + } break; } @@ -561,6 +617,32 @@ void FdbOrch::update(SubjectType type, void *cntx) return; } +void FdbOrch::update(SubjectType type, void *cntx) +{ + SWSS_LOG_ENTER(); + + assert(cntx); + + switch(type) { + case SUBJECT_TYPE_VLAN_MEMBER_CHANGE: + { + VlanMemberUpdate *update = reinterpret_cast(cntx); + updateVlanMember(*update); + break; + } + case SUBJECT_TYPE_PORT_OPER_STATE_CHANGE: + { + PortOperStateUpdate *update = reinterpret_cast(cntx); + updatePortOperState(*update); + break; + } + default: + break; + } + + return; +} + bool FdbOrch::getPort(const MacAddress& mac, uint16_t vlan, Port& port) { SWSS_LOG_ENTER(); @@ -608,11 +690,16 @@ void FdbOrch::doTask(Consumer& consumer) FdbOrigin origin = FDB_ORIGIN_PROVISIONED; string table_name = consumer.getTableName(); + if(table_name == APP_VXLAN_FDB_TABLE_NAME) + { + origin = FDB_ORIGIN_VXLAN_ADVERTIZED; + } if (table_name == APP_MCLAG_FDB_TABLE_NAME) { origin = FDB_ORIGIN_MCLAG_ADVERTIZED; } + auto it = consumer.m_toSync.begin(); while (it != consumer.m_toSync.end()) { @@ -636,7 +723,7 @@ void FdbOrch::doTask(Consumer& consumer) it = consumer.m_toSync.erase(it); continue; } - deleteFdbEntryFromSavedFDB(MacAddress(keys[1]), vlan_id, origin, ""); + deleteFdbEntryFromSavedFDB(MacAddress(keys[1]), vlan_id, origin); it = consumer.m_toSync.erase(it); } @@ -650,13 +737,15 @@ void FdbOrch::doTask(Consumer& consumer) FdbEntry entry; entry.mac = MacAddress(keys[1]); entry.bv_id = vlan.m_vlan_info.vlan_oid; - string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string(); - if (op == SET_COMMAND) { - string port; - string type; + string port = ""; + string type = "dynamic"; + string remote_ip = ""; + string esi = ""; + unsigned int vni = 0; + string sticky = ""; for (auto i : kfvFieldsValues(t)) { @@ -669,16 +758,70 @@ void FdbOrch::doTask(Consumer& consumer) { type = fvValue(i); } + + if(origin == FDB_ORIGIN_VXLAN_ADVERTIZED) + { + if (fvField(i) == "remote_vtep") + { + remote_ip = fvValue(i); + // Creating an IpAddress object to validate if remote_ip is valid + // if invalid it will throw the exception and we will ignore the + // event + try { + IpAddress valid_ip = IpAddress(remote_ip); + (void)valid_ip; // To avoid g++ warning + } catch(exception &e) { + SWSS_LOG_NOTICE("Invalid IP address in remote MAC %s", remote_ip.c_str()); + remote_ip = ""; + break; + } + } + + if (fvField(i) == "esi") + { + esi = fvValue(i); + } + + if (fvField(i) == "vni") + { + try { + vni = (unsigned int) stoi(fvValue(i)); + } catch(exception &e) { + SWSS_LOG_INFO("Invalid VNI in remote MAC %s", fvValue(i).c_str()); + vni = 0; + break; + } + } + } } - entry.port_name = port; /* FDB type is either dynamic or static */ - if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED) assert(type == "dynamic" || type == "dynamic_local" || type == "static" ); else assert(type == "dynamic" || type == "static"); - if (addFdbEntry(entry, port, type, origin)) + if(origin == FDB_ORIGIN_VXLAN_ADVERTIZED) + { + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); + + if(!remote_ip.length()) + { + it = consumer.m_toSync.erase(it); + continue; + } + port = tunnel_orch->getTunnelPortName(remote_ip); + } + + + FdbData fdbData; + fdbData.bridge_port_id = SAI_NULL_OBJECT_ID; + fdbData.type = type; + fdbData.origin = origin; + fdbData.remote_ip = remote_ip; + fdbData.esi = esi; + fdbData.vni = vni; + if (addFdbEntry(entry, port, fdbData)) { if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED) { @@ -692,19 +835,11 @@ void FdbOrch::doTask(Consumer& consumer) } else it++; - - /* Remove corresponding APP_DB entry if type is 'dynamic' */ - // FIXME: The modification of table is not thread safe. - // Uncomment this after this issue is fixed. - // if (type == "dynamic") - // { - // m_table.del(kfvKey(t)); - // } } else if (op == DEL_COMMAND) { - if (removeFdbEntry(entry)) - { + if (removeFdbEntry(entry, origin)) + { if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED) { m_mclagFdbStateTable.del(key); @@ -715,7 +850,7 @@ void FdbOrch::doTask(Consumer& consumer) it = consumer.m_toSync.erase(it); } else - it++; + it++; } else @@ -735,6 +870,7 @@ void FdbOrch::doTask(NotificationConsumer& consumer) return; } + sai_status_t status; std::string op; std::string data; std::vector values; @@ -745,17 +881,28 @@ void FdbOrch::doTask(NotificationConsumer& consumer) { if (op == "ALL") { - flushFdbAll(0); + /* + * so far only support flush all the FDB entries + * flush per port and flush per vlan will be added later. + */ + status = sai_fdb_api->flush_fdb_entries(gSwitchId, 0, NULL); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Flush fdb failed, return code %x", status); + } + return; } else if (op == "PORT") { - flushFdbByPort(data, 0); + /*place holder for flush port fdb*/ + SWSS_LOG_ERROR("Received unsupported flush port fdb request"); return; } else if (op == "VLAN") { - flushFdbByVlan(data, 0); + /*place holder for flush vlan fdb*/ + SWSS_LOG_ERROR("Received unsupported flush vlan fdb request"); return; } else @@ -799,7 +946,7 @@ void FdbOrch::doTask(NotificationConsumer& consumer) * Description: * Flushes FDB entries based on bridge_port_oid, or vlan_oid or both. * This function is called in three cases. - * 1. Port is reoved from VLAN (via SUBJECT_TYPE_VLAN_MEMBER_CHANGE) + * 1. Port is removed from VLAN (via SUBJECT_TYPE_VLAN_MEMBER_CHANGE) * 2. Bridge port OID is removed (Direct call) * 3. Port is shut down (via SUBJECT_TYPE_ */ @@ -850,7 +997,7 @@ void FdbOrch::notifyObserversFDBFlush(Port &port, sai_object_id_t& bvid) for (auto itr = m_entries.begin(); itr != m_entries.end(); ++itr) { - if ((itr->second.bridge_port_id == port.m_bridge_port_id) && + if ((itr->first.port_name == port.m_alias) && (itr->first.bv_id == bvid)) { SWSS_LOG_INFO("Adding MAC learnt on [ port:%s , bvid:0x%" PRIx64 "]\ @@ -862,15 +1009,15 @@ void FdbOrch::notifyObserversFDBFlush(Port &port, sai_object_id_t& bvid) } } -#if 0 //tbd_build if (!flushUpdate.entries.empty()) { - notify(SUBJECT_TYPE_FDB_FLUSH_CHANGE, &update); + for (auto observer: m_observers) + { + observer->update(SUBJECT_TYPE_FDB_FLUSH_CHANGE, &flushUpdate); + } } -#endif } - void FdbOrch::updatePortOperState(const PortOperStateUpdate& update) { SWSS_LOG_ENTER(); @@ -899,17 +1046,20 @@ void FdbOrch::updatePortOperState(const PortOperStateUpdate& update) void FdbOrch::updateVlanMember(const VlanMemberUpdate& update) { - string port_name = update.member.m_alias; - string vlan_name = update.vlan.m_alias; - SWSS_LOG_ENTER(); if (!update.add) { - flushFdbByPortVlan(port_name, vlan_name, 1); + swss::Port vlan = update.vlan; + swss::Port port = update.member; + flushFDBEntries(port.m_bridge_port_id, vlan.m_vlan_info.vlan_oid); + notifyObserversFDBFlush(port, vlan.m_vlan_info.vlan_oid); return; } + + string port_name = update.member.m_alias; auto fdb_list = std::move(saved_fdb_entries[port_name]); + saved_fdb_entries[port_name].clear(); if(!fdb_list.empty()) { for (const auto& fdb: fdb_list) @@ -921,7 +1071,7 @@ void FdbOrch::updateVlanMember(const VlanMemberUpdate& update) FdbEntry entry; entry.mac = fdb.mac; entry.bv_id = update.vlan.m_vlan_info.vlan_oid; - (void)addFdbEntry(entry, port_name, fdb.type, fdb.origin); + (void)addFdbEntry(entry, port_name, fdb.fdbData); } else { @@ -931,26 +1081,29 @@ void FdbOrch::updateVlanMember(const VlanMemberUpdate& update) } } -bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const string& type, FdbOrigin origin) +bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, + FdbData fdbData) { Port vlan; Port port; SWSS_LOG_ENTER(); - SWSS_LOG_INFO("mac=%s bv_id=0x%lx port_name %s type %s", entry.mac.to_string().c_str(), entry.bv_id, port_name.c_str(), type.c_str()); + SWSS_LOG_INFO("mac=%s bv_id=0x%" PRIx64 " port_name=%s type=%s origin=%d", + entry.mac.to_string().c_str(), entry.bv_id, port_name.c_str(), + fdbData.type.c_str(), fdbData.origin); if (!m_portsOrch->getPort(entry.bv_id, vlan)) { - SWSS_LOG_NOTICE("addFdbEntry: Failed to locate vlan port from bv_id 0x%lx", entry.bv_id); + SWSS_LOG_NOTICE("addFdbEntry: Failed to locate vlan port from bv_id 0x%" PRIx64, entry.bv_id); return false; } /* Retry until port is created */ if (!m_portsOrch->getPort(port_name, port) || (port.m_bridge_port_id == SAI_NULL_OBJECT_ID)) { - SWSS_LOG_INFO("Saving a fdb entry until port %s becomes active origin %d", port_name.c_str(), origin); - saved_fdb_entries[port_name].push_back({entry.mac, vlan.m_vlan_info.vlan_id, type, origin}); - + SWSS_LOG_INFO("Saving a fdb entry until port %s becomes active", port_name.c_str()); + saved_fdb_entries[port_name].push_back({entry.mac, + vlan.m_vlan_info.vlan_id, fdbData}); return true; } @@ -958,10 +1111,8 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const if (vlan.m_members.find(port_name) == vlan.m_members.end()) { SWSS_LOG_INFO("Saving a fdb entry until port %s becomes vlan %s member", port_name.c_str(), vlan.m_alias.c_str()); - - if (type != "dynamic_local") - saved_fdb_entries[port_name].push_back({entry.mac, vlan.m_vlan_info.vlan_id, type, origin}); - + saved_fdb_entries[port_name].push_back({entry.mac, + vlan.m_vlan_info.vlan_id, fdbData}); return true; } @@ -976,38 +1127,64 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const FdbOrigin oldOrigin = FDB_ORIGIN_INVALID ; bool macUpdate = false; auto it = m_entries.find(entry); - if(it != m_entries.end()) + if (it != m_entries.end()) { + /* get existing port and type */ oldType = it->second.type; oldOrigin = it->second.origin; - /* get existing port and type */ if (!m_portsOrch->getPortByBridgePortId(it->second.bridge_port_id, oldPort)) { - SWSS_LOG_ERROR("Existing port 0x%lx details not found", it->second.bridge_port_id); + SWSS_LOG_ERROR("Existing port 0x%" PRIx64 " details not found", it->second.bridge_port_id); return false; } - if((oldOrigin == origin) && (oldType == type) && (port.m_bridge_port_id == it->second.bridge_port_id)) + if ((oldOrigin == fdbData.origin) && (oldType == fdbData.type) && (port.m_bridge_port_id == it->second.bridge_port_id)) { /* Duplicate Mac */ - SWSS_LOG_INFO("FdbOrch: mac=%s %s port=%s type=%s origin=%d is duplicate", entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str(), type.c_str(), origin); + SWSS_LOG_INFO("FdbOrch: mac=%s %s port=%s type=%s origin=%d is duplicate", entry.mac.to_string().c_str(), + vlan.m_alias.c_str(), port_name.c_str(), + fdbData.type.c_str(), fdbData.origin); return true; } - else if(origin != oldOrigin) + else if (fdbData.origin != oldOrigin) { /* Mac origin has changed */ - if((oldType == "static") && (oldOrigin == FDB_ORIGIN_PROVISIONED)) + if ((oldType == "static") && (oldOrigin == FDB_ORIGIN_PROVISIONED)) { /* old mac was static and provisioned, it can not be changed by Remote Mac */ - SWSS_LOG_INFO("Already existing static MAC:%s in Vlan:%d. " - "Received same MAC from peer " + SWSS_LOG_NOTICE("Already existing static MAC:%s in Vlan:%d. " + "Received same MAC from peer:%s; " "Peer mac ignored", - entry.mac.to_string().c_str(), vlan.m_vlan_info.vlan_id); + entry.mac.to_string().c_str(), vlan.m_vlan_info.vlan_id, + fdbData.remote_ip.c_str()); return true; } - else if ((oldOrigin == FDB_ORIGIN_LEARN) && (origin == FDB_ORIGIN_MCLAG_ADVERTIZED)) + else if ((oldType == "static") && (oldOrigin == + FDB_ORIGIN_VXLAN_ADVERTIZED) && (fdbData.type == "dynamic")) + { + /* old mac was static and received from remote, it can not be changed by dynamic locally provisioned Mac */ + SWSS_LOG_INFO("Already existing static MAC:%s in Vlan:%d " + "from Peer:%s. Now same is provisioned as dynamic; " + "Provisioned dynamic mac is ignored", + entry.mac.to_string().c_str(), vlan.m_vlan_info.vlan_id, + it->second.remote_ip.c_str()); + return true; + } + else if (oldOrigin == FDB_ORIGIN_VXLAN_ADVERTIZED) + { + if ((oldType == "static") && (fdbData.type == "static")) + { + SWSS_LOG_WARN("You have just overwritten existing static MAC:%s " + "in Vlan:%d from Peer:%s, " + "If it is a mistake, it will result in inconsistent Traffic Forwarding", + entry.mac.to_string().c_str(), + vlan.m_vlan_info.vlan_id, + it->second.remote_ip.c_str()); + } + } + else if ((oldOrigin == FDB_ORIGIN_LEARN) && (fdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED)) { if ((port.m_bridge_port_id == it->second.bridge_port_id) && (oldType == "dynamic") && (type == "dynamic_local")) { @@ -1015,12 +1192,21 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const " old_type=%s local mac exists," " received dynamic_local from iccpd, ignore update", entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str(), - type.c_str(), origin, oldOrigin, oldType.c_str()); + type.c_str(), fdbData.origin, oldOrigin, oldType.c_str()); return true; } } } + else /* (fdbData.origin == oldOrigin) */ + { + /* Mac origin is same, all changes are allowed */ + /* Allowed + * Bridge-port is changed or/and + * Sticky bit from remote is modified or + * provisioned mac is converted from static<-->dynamic + */ + } macUpdate = true; } @@ -1029,114 +1215,162 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const vector attrs; attr.id = SAI_FDB_ENTRY_ATTR_TYPE; - if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + if (fdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED || fdbData.origin == FDB_ORIGIN_VXLAN_ADVERTIZED) { - if (type == "dynamic_local") + if (fdbData.type == "dynamic_local") attr.value.s32 = SAI_FDB_ENTRY_TYPE_DYNAMIC; else attr.value.s32 = SAI_FDB_ENTRY_TYPE_STATIC; } else { - attr.value.s32 = (type == "dynamic") ? SAI_FDB_ENTRY_TYPE_DYNAMIC : SAI_FDB_ENTRY_TYPE_STATIC; + attr.value.s32 = (fdbData.type == "dynamic") ? SAI_FDB_ENTRY_TYPE_DYNAMIC : SAI_FDB_ENTRY_TYPE_STATIC; } + attrs.push_back(attr); - if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + if ((fdbData.origin == FDB_ORIGIN_VXLAN_ADVERTIZED || fdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + && (fdbData.type == "dynamic")) { - if (type != "dynamic_local") - { - attr.id = SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE; - attr.value.booldata = true; - attrs.push_back(attr); - } + attr.id = SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE; + attr.value.booldata = true; + attrs.push_back(attr); } attr.id = SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID; attr.value.oid = port.m_bridge_port_id; attrs.push_back(attr); - attr.id = SAI_FDB_ENTRY_ATTR_PACKET_ACTION; - attr.value.s32 = SAI_PACKET_ACTION_FORWARD; - attrs.push_back(attr); - - string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string(); - - if(macUpdate) + if (fdbData.origin == FDB_ORIGIN_VXLAN_ADVERTIZED) { - /* delete and re-add fdb entry instead of update, - * as entry may age out in HW/ASIC_DB before - * update, causing the update request to fail. - */ - SWSS_LOG_INFO("MAC-Update FDB %s in %s on from-%s:to-%s from-%s:to-%s", entry.mac.to_string().c_str(), vlan.m_alias.c_str(), oldPort.m_alias.c_str(), port_name.c_str(), oldType.c_str(), type.c_str()); - status = sai_fdb_api->remove_fdb_entry(&fdb_entry); - if (status != SAI_STATUS_SUCCESS) + IpAddress remote = IpAddress(fdbData.remote_ip); + sai_ip_address_t ipaddr; + if (remote.isV4()) { - SWSS_LOG_WARN("FdbOrch RemoveFDBEntry: Failed to remove FDB entry. mac=%s, bv_id=0x%lx", - entry.mac.to_string().c_str(), entry.bv_id); + ipaddr.addr_family = SAI_IP_ADDR_FAMILY_IPV4; + ipaddr.addr.ip4 = remote.getV4Addr(); } else { - oldPort.m_fdb_count--; - m_portsOrch->setPort(oldPort.m_alias, oldPort); - if (oldPort.m_bridge_port_id == port.m_bridge_port_id) - { - port.m_fdb_count--; - m_portsOrch->setPort(port.m_alias, port); - } - vlan.m_fdb_count--; - m_portsOrch->setPort(vlan.m_alias, vlan); - (void)m_entries.erase(entry); - // Remove in StateDb - m_fdbStateTable.del(key); + ipaddr.addr_family = SAI_IP_ADDR_FAMILY_IPV6; + memcpy(ipaddr.addr.ip6, remote.getV6Addr(), sizeof(ipaddr.addr.ip6)); + } + attr.id = SAI_FDB_ENTRY_ATTR_ENDPOINT_IP; + attr.value.ipaddr = ipaddr; + attrs.push_back(attr); + } + else if (macUpdate + && (oldOrigin == FDB_ORIGIN_VXLAN_ADVERTIZED) + && (fdbData.origin != oldOrigin)) + { + /* origin is changed from Remote-advertized to Local-provisioned + * Remove the end-point ip attribute from fdb entry + */ + sai_ip_address_t ipaddr; + ipaddr.addr_family = SAI_IP_ADDR_FAMILY_IPV4; + ipaddr.addr.ip4 = 0; + attr.id = SAI_FDB_ENTRY_ATTR_ENDPOINT_IP; + attr.value.ipaddr = ipaddr; + attrs.push_back(attr); + } - gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); - FdbUpdate update = {entry, port, vlan.m_vlan_info.vlan_id, type, true}; - notify(SUBJECT_TYPE_FDB_CHANGE, &update); + if (macUpdate && (oldOrigin == FDB_ORIGIN_VXLAN_ADVERTIZED)) + { + if ((fdbData.origin != oldOrigin) + || ((oldType == "dynamic") && (oldType != fdbData.type))) + { + attr.id = SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE; + attr.value.booldata = false; + attrs.push_back(attr); } } - SWSS_LOG_INFO("MAC-Create %s FDB %s in %s on %s", type.c_str(), entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str()); - status = sai_fdb_api->create_fdb_entry(&fdb_entry, (uint32_t)attrs.size(), attrs.data()); - if (status != SAI_STATUS_SUCCESS) + + if (macUpdate) { - SWSS_LOG_ERROR("Failed to create %s FDB %s on %s, rv:%d", - type.c_str(), entry.mac.to_string().c_str(), - entry.port_name.c_str(), status); - return false; //FIXME: it should be based on status. Some could be retried, some not + SWSS_LOG_INFO("MAC-Update FDB %s in %s on from-%s:to-%s from-%s:to-%s origin-%d-to-%d", + entry.mac.to_string().c_str(), vlan.m_alias.c_str(), oldPort.m_alias.c_str(), + port_name.c_str(), oldType.c_str(), fdbData.type.c_str(), + oldOrigin, fdbData.origin); + for (auto itr : attrs) + { + status = sai_fdb_api->set_fdb_entry_attribute(&fdb_entry, &itr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("macUpdate-Failed for attr.id=0x%x for FDB %s in %s on %s, rv:%d", + itr.id, entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str(), status); + task_process_status handle_status = handleSaiSetStatus(SAI_API_FDB, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } + } + } + if (oldPort.m_bridge_port_id != port.m_bridge_port_id) + { + oldPort.m_fdb_count--; + m_portsOrch->setPort(oldPort.m_alias, oldPort); + port.m_fdb_count++; + m_portsOrch->setPort(port.m_alias, port); + } } - port.m_fdb_count++; - m_portsOrch->setPort(port.m_alias, port); - vlan.m_fdb_count++; - m_portsOrch->setPort(vlan.m_alias, vlan); + else + { + SWSS_LOG_INFO("MAC-Create %s FDB %s in %s on %s", fdbData.type.c_str(), entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str()); - FdbData fdbdata = {port.m_bridge_port_id, type, origin}; + status = sai_fdb_api->create_fdb_entry(&fdb_entry, (uint32_t)attrs.size(), attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create %s FDB %s in %s on %s, rv:%d", + fdbData.type.c_str(), entry.mac.to_string().c_str(), + vlan.m_alias.c_str(), port_name.c_str(), status); + task_process_status handle_status = handleSaiCreateStatus(SAI_API_FDB, status); //FIXME: it should be based on status. Some could be retried, some not + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } + } + port.m_fdb_count++; + m_portsOrch->setPort(port.m_alias, port); + vlan.m_fdb_count++; + m_portsOrch->setPort(vlan.m_alias, vlan); + } + FdbData storeFdbData = fdbData; + storeFdbData.bridge_port_id = port.m_bridge_port_id; // overwrite the type and origin if ((origin == FDB_ORIGIN_MCLAG_ADVERTIZED) && (type == "dynamic_local")) { //If the MAC is dynamic_local change the origin accordingly //MAC is added/updated as dynamic to allow aging. - fdbdata.origin = FDB_ORIGIN_LEARN; - fdbdata.type = "dynamic"; + storeFdbData.origin = FDB_ORIGIN_LEARN; + storeFdbData.type = "dynamic"; } + + m_entries[entry] = storeFdbData; + + string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string(); + SWSS_LOG_NOTICE("Storing FDB entry: [%s, 0x%" PRIx64 "] [ port: %s , type: %s]", entry.mac.to_string().c_str(), entry.bv_id, entry.port_name.c_str(), type.c_str()); - m_entries[entry] = fdbdata; - if ( (type == "dynamic_local") || (origin != FDB_ORIGIN_MCLAG_ADVERTIZED)) + + if ( (fdbData.type == "dynamic_local") || + (fdbData.origin != FDB_ORIGIN_MCLAG_ADVERTIZED) || + (fdbData.origin != FDB_ORIGIN_VXLAN_ADVERTIZED)) { /* State-DB is updated only for Local Mac addresses */ // Write to StateDb std::vector fvs; fvs.push_back(FieldValueTuple("port", port_name)); - if (type == "dynamic_local") + if (fdbData.type == "dynamic_local") fvs.push_back(FieldValueTuple("type", "dynamic")); else - fvs.push_back(FieldValueTuple("type", type)); + fvs.push_back(FieldValueTuple("type", fdbData.type)); m_fdbStateTable.set(key, fvs); } - else if (macUpdate && (oldOrigin != FDB_ORIGIN_MCLAG_ADVERTIZED)) + else if (macUpdate && (oldOrigin != FDB_ORIGIN_MCLAG_ADVERTIZED) && + (oldOrigin != FDB_ORIGIN_VXLAN_ADVERTIZED)) { /* origin is FDB_ORIGIN_ADVERTIZED and it is mac-update * so delete from StateDb since we only keep local fdbs @@ -1146,11 +1380,11 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const } //register with NeighborOrch for ICCP learned MAC addresses - if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED && (type != "dynamic_local")) + if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED && (fdbData.type != "dynamic_local")) { std::vector fvs; fvs.push_back(FieldValueTuple("port", port_name)); - fvs.push_back(FieldValueTuple("type", type)); + fvs.push_back(FieldValueTuple("type", fdbData.type)); m_mclagFdbStateTable.set(key, fvs); SWSS_LOG_NOTICE("fdbEvent: AddFdbEntry: Add MCLAG MAC with state mclag remote fdb table " @@ -1158,7 +1392,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const vlan.m_vlan_info.vlan_id, port_name.c_str(), type.c_str()); } else if (macUpdate && (oldOrigin == FDB_ORIGIN_MCLAG_ADVERTIZED) && - (origin != FDB_ORIGIN_MCLAG_ADVERTIZED)) + (fdbData.origin != FDB_ORIGIN_MCLAG_ADVERTIZED)) { SWSS_LOG_NOTICE("fdbEvent: AddFdbEntry: del MCLAG MAC from state MCLAG remote fdb table " "Mac: %s Vlan: %d port:%s type:%s", entry.mac.to_string().c_str(), @@ -1166,15 +1400,16 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const m_mclagFdbStateTable.del(key); } - if(!macUpdate) + if (!macUpdate) { gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); } - FdbUpdate update = {entry, port, vlan.m_vlan_info.vlan_id, type, true}; - // overwrite the type to dynamic. - if (type == "dynamic_local") - update.type = "dynamic"; + FdbUpdate update; + update.entry = entry; + update.port = port; + update.type = fdbData.type; + update.add = true; notify(SUBJECT_TYPE_FDB_CHANGE, &update); @@ -1188,36 +1423,35 @@ bool FdbOrch::removeFdbEntry(const FdbEntry& entry, FdbOrigin origin) SWSS_LOG_ENTER(); + SWSS_LOG_INFO("FdbOrch RemoveFDBEntry: mac=%s bv_id=0x%" PRIx64 "origin %d", entry.mac.to_string().c_str(), entry.bv_id, origin); + if (!m_portsOrch->getPort(entry.bv_id, vlan)) { - SWSS_LOG_NOTICE("FdbOrch notification: Failed to locate vlan port from bv_id 0x%lx", entry.bv_id); + SWSS_LOG_NOTICE("FdbOrch notification: Failed to locate vlan port from bv_id 0x%" PRIx64, entry.bv_id); return false; } auto it= m_entries.find(entry); - if(it == m_entries.end()) + if (it == m_entries.end()) { - SWSS_LOG_INFO("FdbOrch RemoveFDBEntry: FDB entry isn't found. mac=%s bv_id=0x%lx", entry.mac.to_string().c_str(), entry.bv_id); + SWSS_LOG_INFO("FdbOrch RemoveFDBEntry: FDB entry isn't found. mac=%s bv_id=0x%" PRIx64, entry.mac.to_string().c_str(), entry.bv_id); /* check whether the entry is in the saved fdb, if so delete it from there. */ - deleteFdbEntryFromSavedFDB(entry.mac, vlan.m_vlan_info.vlan_id, origin, ""); + deleteFdbEntryFromSavedFDB(entry.mac, vlan.m_vlan_info.vlan_id, origin); return true; } FdbData fdbData = it->second; if (!m_portsOrch->getPortByBridgePortId(fdbData.bridge_port_id, port)) { - SWSS_LOG_NOTICE("FdbOrch RemoveFDBEntry: Failed to locate port from bridge_port_id 0x%lx", fdbData.bridge_port_id); + SWSS_LOG_NOTICE("FdbOrch RemoveFDBEntry: Failed to locate port from bridge_port_id 0x%" PRIx64, fdbData.bridge_port_id); return false; } - SWSS_LOG_INFO("FdbOrch RemoveFDBEntry: mac=%s bv_id=0x%lx existing origin %d, port oper_status: %s , is malg interface: %s", - entry.mac.to_string().c_str(), entry.bv_id, fdbData.origin, (port.m_oper_status == SAI_PORT_OPER_STATUS_DOWN) ? "DOWN":"UP", - gMlagOrch->isMlagInterface(port.m_alias) ? "true":"false"); - if(fdbData.origin != origin) + if (fdbData.origin != origin) { if ((origin == FDB_ORIGIN_MCLAG_ADVERTIZED) && (fdbData.origin == FDB_ORIGIN_LEARN) && - (port.m_oper_status == SAI_PORT_OPER_STATUS_DOWN) && (gMlagOrch->isMlagInterface(port.m_alias))) + (port.m_oper_status == SAI_PORT_OPER_STATUS_DOWN) && (gMlagOrch->isMlagInterface(port.m_alias))) { //check if the local MCLAG port is down, if yes then continue delete the local MAC origin = FDB_ORIGIN_LEARN; @@ -1226,14 +1460,19 @@ bool FdbOrch::removeFdbEntry(const FdbEntry& entry, FdbOrigin origin) } else { - m_entries[entry] = fdbData; - SWSS_LOG_NOTICE("FdbOrch RemoveFDBEntry: mac=%s fdb origin is different; found_origin:%d delete_origin:%d", + + /* When mac is moved from remote to local + * BGP will delete the mac from vxlan_fdb_table + * but we should not delete this mac here since now + * mac in orchagent represents locally learnt + */ + SWSS_LOG_INFO("FdbOrch RemoveFDBEntry: mac=%s fdb origin is different; found_origin:%d delete_origin:%d", entry.mac.to_string().c_str(), fdbData.origin, origin); /* We may still have the mac in saved-fdb probably due to unavailability * of bridge-port. check whether the entry is in the saved fdb, * if so delete it from there. */ - deleteFdbEntryFromSavedFDB(entry.mac, vlan.m_vlan_info.vlan_id, origin, ""); + deleteFdbEntryFromSavedFDB(entry.mac, vlan.m_vlan_info.vlan_id, origin); return true; } @@ -1250,10 +1489,18 @@ bool FdbOrch::removeFdbEntry(const FdbEntry& entry, FdbOrigin origin) status = sai_fdb_api->remove_fdb_entry(&fdb_entry); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("FdbOrch RemoveFDBEntry: Failed to remove FDB entry. mac=%s, bv_id=0x%lx", + SWSS_LOG_ERROR("FdbOrch RemoveFDBEntry: Failed to remove FDB entry. mac=%s, bv_id=0x%" PRIx64, entry.mac.to_string().c_str(), entry.bv_id); - return true; //FIXME: it should be based on status. Some could be retried. some not + task_process_status handle_status = handleSaiRemoveStatus(SAI_API_FDB, status); //FIXME: it should be based on status. Some could be retried. some not + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } + + SWSS_LOG_INFO("Removed mac=%s bv_id=0x%" PRIx64 " port:%s", + entry.mac.to_string().c_str(), entry.bv_id, port.m_alias.c_str()); + port.m_fdb_count--; m_portsOrch->setPort(port.m_alias, port); vlan.m_fdb_count--; @@ -1261,187 +1508,50 @@ bool FdbOrch::removeFdbEntry(const FdbEntry& entry, FdbOrigin origin) (void)m_entries.erase(entry); // Remove in StateDb - if (fdbData.origin != FDB_ORIGIN_MCLAG_ADVERTIZED) + if ((fdbData.origin != FDB_ORIGIN_VXLAN_ADVERTIZED) && (fdbData.origin != FDB_ORIGIN_MCLAG_ADVERTIZED)) { m_fdbStateTable.del(key); } gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); - FdbUpdate update = {entry, port, vlan.m_vlan_info.vlan_id, fdbData.type, false}; + FdbUpdate update; + update.entry = entry; + update.port = port; + update.type = fdbData.type; + update.add = false; notify(SUBJECT_TYPE_FDB_CHANGE, &update); - return true; -} + notifyTunnelOrch(update.port); -bool FdbOrch::flushFdbAll(bool flush_static) -{ - sai_status_t status; - sai_attribute_t port_attr; - - if (!flush_static) - { - port_attr.id = SAI_FDB_FLUSH_ATTR_ENTRY_TYPE; - port_attr.value.s32 = SAI_FDB_FLUSH_ENTRY_TYPE_DYNAMIC; - status = sai_fdb_api->flush_fdb_entries(gSwitchId, 1, &port_attr); - } - else - { - status = sai_fdb_api->flush_fdb_entries(gSwitchId, 0, NULL); - } - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Flush fdb failed, return code %x", status); - return false; - } return true; } -bool FdbOrch::flushFdbByPort(const string &alias, bool flush_static) -{ - sai_status_t status; - Port port; - sai_attribute_t port_attr[2]; - - if (!m_portsOrch->getPort(alias, port)) - { - SWSS_LOG_ERROR("could not locate port from alias %s", alias.c_str()); - return false; - } - - if ((port.m_bridge_port_id == SAI_NULL_OBJECT_ID) || !port.m_fdb_count) - { - /* port is not an L2 port or no macs to flush */ - return true; - } - - SWSS_LOG_NOTICE("m_bridge_port_id 0x%lx flush_static %d m_fdb_count %u", port.m_bridge_port_id, flush_static, port.m_fdb_count); - - port_attr[0].id = SAI_FDB_FLUSH_ATTR_BRIDGE_PORT_ID; - port_attr[0].value.oid = port.m_bridge_port_id; - if (!flush_static) - { - port_attr[1].id = SAI_FDB_FLUSH_ATTR_ENTRY_TYPE; - port_attr[1].value.s32 = SAI_FDB_FLUSH_ENTRY_TYPE_DYNAMIC; - status = sai_fdb_api->flush_fdb_entries(gSwitchId, 2, port_attr); - } - else - { - status = sai_fdb_api->flush_fdb_entries(gSwitchId, 1, port_attr); - } - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Flush fdb failed, return code %x", status); - return false; - } - return true; -} - -bool FdbOrch::flushFdbByVlan(const string &alias, bool flush_static) -{ - sai_status_t status; - Port vlan; - sai_attribute_t vlan_attr[2]; - - if (!m_portsOrch->getPort(alias, vlan)) - { - SWSS_LOG_ERROR("could not locate vlan from alias %s", alias.c_str()); - return false; - } - SWSS_LOG_NOTICE("vlan_oid 0x%lx flush_static %d", vlan.m_vlan_info.vlan_oid, flush_static); - - vlan_attr[0].id = SAI_FDB_FLUSH_ATTR_BV_ID; - vlan_attr[0].value.oid = vlan.m_vlan_info.vlan_oid; - if (!flush_static) - { - vlan_attr[1].id = SAI_FDB_FLUSH_ATTR_ENTRY_TYPE; - vlan_attr[1].value.s32 = SAI_FDB_FLUSH_ENTRY_TYPE_DYNAMIC; - status = sai_fdb_api->flush_fdb_entries(gSwitchId, 2, vlan_attr); - } - else - { - status = sai_fdb_api->flush_fdb_entries(gSwitchId, 1, vlan_attr); - } - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Flush fdb failed, return code %x", status); - return false; - } - - return true; -} - -bool FdbOrch::flushFdbByPortVlan(const string &port_alias, const string &vlan_alias, bool flush_static) -{ - - sai_status_t status; - Port vlan; - Port port; - sai_attribute_t port_vlan_attr[3]; - - SWSS_LOG_NOTICE("port %s vlan %s", port_alias.c_str(), vlan_alias.c_str()); - - if (!m_portsOrch->getPort(port_alias, port)) - { - SWSS_LOG_ERROR("could not locate port from alias %s", port_alias.c_str()); - return false; - } - if (!m_portsOrch->getPort(vlan_alias, vlan)) - { - SWSS_LOG_NOTICE("FdbOrch notification: Failed to locate vlan %s", vlan_alias.c_str()); - return false; - } - - if ((port.m_bridge_port_id == SAI_NULL_OBJECT_ID) || !port.m_fdb_count) - { - /* port is not an L2 port or no macs to flush */ - return true; - } - - SWSS_LOG_NOTICE("vlan_oid 0x%lx m_bridge_port_id 0x%lx flush_static %d m_fdb_count %u", vlan.m_vlan_info.vlan_oid, port.m_bridge_port_id, flush_static, port.m_fdb_count); - - port_vlan_attr[0].id = SAI_FDB_FLUSH_ATTR_BV_ID; - port_vlan_attr[0].value.oid = vlan.m_vlan_info.vlan_oid; - port_vlan_attr[1].id = SAI_FDB_FLUSH_ATTR_BRIDGE_PORT_ID; - port_vlan_attr[1].value.oid = port.m_bridge_port_id; - if (!flush_static) - { - port_vlan_attr[2].id = SAI_FDB_FLUSH_ATTR_ENTRY_TYPE; - port_vlan_attr[2].value.s32 = SAI_FDB_FLUSH_ENTRY_TYPE_DYNAMIC; - status = sai_fdb_api->flush_fdb_entries(gSwitchId, 3, port_vlan_attr); - } - else - { - status = sai_fdb_api->flush_fdb_entries(gSwitchId, 2, port_vlan_attr); - } - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Flush fdb failed, return code %x", status); - return false; - } - - return true; -} -void FdbOrch::deleteFdbEntryFromSavedFDB(const MacAddress &mac, +void FdbOrch::deleteFdbEntryFromSavedFDB(const MacAddress &mac, const unsigned short &vlanId, FdbOrigin origin, const string portName) { bool found=false; - SavedFdbEntry entry = {mac, vlanId, "static", origin}; + SavedFdbEntry entry; + entry.mac = mac; + entry.vlanId = vlanId; + entry.fdbData.type = "static"; + /* Below members are unused during delete compare */ + entry.fdbData.origin = origin; for (auto& itr: saved_fdb_entries) { - if(portName.empty() || (portName == itr.first)) + if (portName.empty() || (portName == itr.first)) { auto iter = saved_fdb_entries[itr.first].begin(); while(iter != saved_fdb_entries[itr.first].end()) { if (*iter == entry) { - if(iter->origin == origin) + if (iter->fdbData.origin == origin) { SWSS_LOG_INFO("FDB entry found in saved fdb. deleting..." - "mac=%s vlan_id=0x%x origin:%d port:%s", + "mac=%s vlan_id=0x%x origin:%d port:%s", mac.to_string().c_str(), vlanId, origin, itr.first.c_str()); saved_fdb_entries[itr.first].erase(iter); @@ -1453,15 +1563,27 @@ void FdbOrch::deleteFdbEntryFromSavedFDB(const MacAddress &mac, { SWSS_LOG_INFO("FDB entry found in saved fdb, but Origin is " "different mac=%s vlan_id=0x%x reqOrigin:%d " - "foundOrigin:%d port:%s, IGNORED", + "foundOrigin:%d port:%s, IGNORED", mac.to_string().c_str(), vlanId, origin, - iter->origin, itr.first.c_str()); + iter->fdbData.origin, itr.first.c_str()); } } iter++; } } - if(found) + if (found) break; } } + +// Notify Tunnel Orch when the number of MAC entries +void FdbOrch::notifyTunnelOrch(Port& port) +{ + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); + + if((port.m_type != Port::TUNNEL) || + (port.m_fdb_count != 0)) + return; + + tunnel_orch->deleteTunnelPort(port); +} diff --git a/orchagent/fdborch.h b/orchagent/fdborch.h index 7db4ac3971..c51feb3e46 100644 --- a/orchagent/fdborch.h +++ b/orchagent/fdborch.h @@ -10,6 +10,7 @@ enum FdbOrigin FDB_ORIGIN_INVALID = 0, FDB_ORIGIN_LEARN = 1, FDB_ORIGIN_PROVISIONED = 2, + FDB_ORIGIN_VXLAN_ADVERTIZED = 4, FDB_ORIGIN_MCLAG_ADVERTIZED = 8 }; @@ -33,7 +34,6 @@ struct FdbUpdate { FdbEntry entry; Port port; - uint16_t vlan_id; string type; bool add; }; @@ -43,6 +43,19 @@ struct FdbData sai_object_id_t bridge_port_id; string type; FdbOrigin origin; + /** + {"dynamic", FDB_ORIGIN_LEARN} => dynamically learnt + {"dynamic", FDB_ORIGIN_PROVISIONED} => provisioned dynamic with swssconfig in APPDB + {"dynamic", FDB_ORIGIN_ADVERTIZED} => synced from remote device e.g. BGP MAC route + {"static", FDB_ORIGIN_LEARN} => Invalid + {"static", FDB_ORIGIN_PROVISIONED} => statically provisioned + {"static", FDB_ORIGIN_ADVERTIZED} => sticky synced from remote device + */ + + /* Remote FDB related info */ + string remote_ip; + string esi; + unsigned int vni; }; struct FdbFlushUpdate @@ -55,8 +68,7 @@ struct SavedFdbEntry { MacAddress mac; unsigned short vlanId; - string type; - FdbOrigin origin; + FdbData fdbData; bool operator==(const SavedFdbEntry& other) const { return tie(mac, vlanId) == tie(other.mac, other.vlanId); @@ -81,11 +93,10 @@ class FdbOrch: public Orch, public Subject, public Observer void update(sai_fdb_event_t, const sai_fdb_entry_t *, sai_object_id_t); void update(SubjectType type, void *cntx); bool getPort(const MacAddress&, uint16_t, Port&); - bool flushFdbByPortVlan(const string &, const string &, bool flush_static); - bool flushFdbByVlan(const string &, bool flush_static); - bool flushFdbByPort(const string &, bool flush_static); - bool flushFdbAll(bool flush_static); + bool removeFdbEntry(const FdbEntry& entry, FdbOrigin origin=FDB_ORIGIN_PROVISIONED); + + static const int fdborch_pri; void flushFDBEntries(sai_object_id_t bridge_port_oid, sai_object_id_t vlan_oid); void notifyObserversFDBFlush(Port &p, sai_object_id_t&); @@ -96,7 +107,6 @@ class FdbOrch: public Orch, public Subject, public Observer fdb_entries_by_port_t saved_fdb_entries; vector m_appTables; Table m_fdbStateTable; - Table m_mclagFdbStateTable; NotificationConsumer* m_flushNotificationsConsumer; NotificationConsumer* m_fdbNotificationConsumer; @@ -104,11 +114,13 @@ class FdbOrch: public Orch, public Subject, public Observer void doTask(NotificationConsumer& consumer); void updateVlanMember(const VlanMemberUpdate&); - bool addFdbEntry(const FdbEntry&, const string&, const string&, FdbOrigin origin); - void deleteFdbEntryFromSavedFDB(const MacAddress &mac, const unsigned short &vlanId, - FdbOrigin origin=FDB_ORIGIN_PROVISIONED, const string portName=""); void updatePortOperState(const PortOperStateUpdate&); + + bool addFdbEntry(const FdbEntry&, const string&, FdbData fdbData); + void deleteFdbEntryFromSavedFDB(const MacAddress &mac, const unsigned short &vlanId, FdbOrigin origin, const string portName=""); + bool storeFdbEntryState(const FdbUpdate& update); + void notifyTunnelOrch(Port& port); }; #endif /* SWSS_FDBORCH_H */ diff --git a/orchagent/notifications.cpp b/orchagent/notifications.cpp index 4133726bc4..209c03d83b 100644 --- a/orchagent/notifications.cpp +++ b/orchagent/notifications.cpp @@ -5,7 +5,7 @@ extern "C" { #include "logger.h" #include "notifications.h" -void on_fdb_event(uint32_t count, sai_fdb_event_notification_data_t *fdbevent) +void on_fdb_event(uint32_t count, sai_fdb_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 diff --git a/orchagent/port.h b/orchagent/port.h index 804972d490..f6abce87b0 100644 --- a/orchagent/port.h +++ b/orchagent/port.h @@ -26,7 +26,6 @@ namespace swss { struct VlanMemberEntry { - std::string alias; sai_object_id_t vlan_member_id; sai_vlan_tagging_mode_t vlan_mode; }; @@ -37,6 +36,27 @@ struct VlanInfo { sai_object_id_t vlan_oid = 0; sai_vlan_id_t vlan_id = 0; + sai_object_id_t host_intf_id = SAI_NULL_OBJECT_ID; +}; + +struct SystemPortInfo +{ + std::string alias = ""; + sai_system_port_type_t type = SAI_SYSTEM_PORT_TYPE_LOCAL; + sai_object_id_t local_port_oid = 0; + uint32_t port_id = 0; + uint32_t switch_id = 0; + uint32_t core_index = 0; + uint32_t core_port_index = 0; + uint32_t speed = 400000; + uint32_t num_voq = 8; +}; + +struct SystemLagInfo +{ + std::string alias = ""; + int32_t switch_id = -1; + int32_t spa_id = 0; }; class Port @@ -51,6 +71,7 @@ class Port LAG, TUNNEL, SUBPORT, + SYSTEM, UNKNOWN } ; @@ -88,7 +109,6 @@ class Port VlanInfo m_vlan_info; MacAddress m_mac; sai_object_id_t m_bridge_port_id = 0; // TODO: port could have multiple bridge port IDs - sai_object_id_t m_bridge_port_admin_state = 0; // TODO: port could have multiple bridge port IDs sai_vlan_id_t m_port_vlan_id = DEFAULT_PORT_VLAN_ID; // Port VLAN ID sai_object_id_t m_rif_id = 0; sai_object_id_t m_vr_id = 0; @@ -98,8 +118,8 @@ class Port sai_object_id_t m_tunnel_id = 0; sai_object_id_t m_ingress_acl_table_group_id = 0; sai_object_id_t m_egress_acl_table_group_id = 0; - sai_object_id_t m_parent_port_id = 0; vlan_members_t m_vlan_members; + sai_object_id_t m_parent_port_id = 0; uint32_t m_dependency_bitmap = 0; sai_port_oper_status_t m_oper_status = SAI_PORT_OPER_STATUS_UNKNOWN; std::set m_members; @@ -112,6 +132,7 @@ class Port uint32_t m_vnid = VNID_NONE; uint32_t m_fdb_count = 0; uint32_t m_up_member_count = 0; + uint32_t m_maximum_headroom = 0; /* * Following two bit vectors are used to lock @@ -126,6 +147,13 @@ class Port std::unordered_set m_ingress_acl_tables_uset; std::unordered_set m_egress_acl_tables_uset; + + sai_object_id_t m_system_port_oid = 0; + SystemPortInfo m_system_port_info; + SystemLagInfo m_system_lag_info; + + bool m_fec_cfg = false; + bool m_an_cfg = false; }; } diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index fa8384c36f..a02a4564c4 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -28,6 +28,7 @@ #include "countercheckorch.h" #include "notifier.h" #include "fdborch.h" +#include "subscriberstatetable.h" extern sai_switch_api_t *sai_switch_api; extern sai_bridge_api_t *sai_bridge_api; @@ -45,6 +46,11 @@ extern CrmOrch *gCrmOrch; extern BufferOrch *gBufferOrch; extern FdbOrch *gFdbOrch; extern Directory gDirectory; +extern sai_system_port_api_t *sai_system_port_api; +extern string gMySwitchType; +extern int32_t gVoqMySwitchId; +extern string gMyHostName; +extern string gMyAsicName; #define VLAN_PREFIX "Vlan" #define DEFAULT_VLAN_ID 1 @@ -55,6 +61,7 @@ extern Directory gDirectory; #define QUEUE_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS 10000 #define QUEUE_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS "10000" #define PG_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS "10000" +#define PG_DROP_FLEX_STAT_COUNTER_POLL_MSECS "10000" #define PORT_RATE_FLEX_COUNTER_POLLING_INTERVAL_MS "1000" @@ -198,6 +205,11 @@ static const vector ingressPriorityGroupWater SAI_INGRESS_PRIORITY_GROUP_STAT_SHARED_WATERMARK_BYTES, }; +static const vector ingressPriorityGroupDropStatIds = +{ + SAI_INGRESS_PRIORITY_GROUP_STAT_DROPPED_PACKETS +}; + static char* hostif_vlan_tag[] = { [SAI_HOSTIF_VLAN_TAG_STRIP] = "SAI_HOSTIF_VLAN_TAG_STRIP", [SAI_HOSTIF_VLAN_TAG_KEEP] = "SAI_HOSTIF_VLAN_TAG_KEEP", @@ -218,7 +230,7 @@ static char* hostif_vlan_tag[] = { * bridge. By design, SONiC switch starts with all bridge ports removed from * default VLAN and all ports removed from .1Q bridge. */ -PortsOrch::PortsOrch(DBConnector *db, vector &tableNames) : +PortsOrch::PortsOrch(DBConnector *db, vector &tableNames, DBConnector *chassisAppDb) : Orch(db, tableNames), port_stat_manager(PORT_STAT_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, PORT_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS, true), port_buffer_drop_stat_manager(PORT_BUFFER_DROP_STAT_FLEX_COUNTER_GROUP, StatsMode::READ, PORT_BUFFER_DROP_STAT_POLLING_INTERVAL_MS, true), @@ -237,7 +249,6 @@ PortsOrch::PortsOrch(DBConnector *db, vector &tableNames) /* Initialize port and vlan table */ m_portTable = unique_ptr
(new Table(db, APP_PORT_TABLE_NAME)); - m_vlanTable = unique_ptr
(new Table(db, APP_VLAN_TABLE_NAME)); /* Initialize gearbox */ m_gearboxTable = unique_ptr
(new Table(db, "_GEARBOX_TABLE")); @@ -257,7 +268,8 @@ PortsOrch::PortsOrch(DBConnector *db, vector &tableNames) 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)); - notifications = unique_ptr(new swss::NotificationProducer(db, "VLANSTATE")); + 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(); @@ -294,6 +306,11 @@ PortsOrch::PortsOrch(DBConnector *db, vector &tableNames) 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); } catch (const runtime_error &e) { @@ -394,19 +411,10 @@ PortsOrch::PortsOrch(DBConnector *db, vector &tableNames) } m_default1QBridge = attrs[0].value.oid; - m_defaultVlan_ObjId = attrs[1].value.oid; - - memset(&attr, 0x00, sizeof(attr)); - attr.id = SAI_VLAN_ATTR_VLAN_ID; - - status = sai_vlan_api->get_vlan_attribute(m_defaultVlan_ObjId, 1, &attr); - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to get default VLAN ID, rv:%d", status); - throw runtime_error("PortsOrch initialization failure"); - } + m_defaultVlan = attrs[1].value.oid; - m_defaultVlan_Id = attr.value.u16; + /* Get System ports */ + getSystemPorts(); removeDefaultVlanMembers(); removeDefaultBridgePorts(); @@ -416,19 +424,35 @@ PortsOrch::PortsOrch(DBConnector *db, vector &tableNames) m_portStatusNotificationConsumer = new swss::NotificationConsumer(notificationsDb, "NOTIFICATIONS"); auto portStatusNotificatier = new Notifier(m_portStatusNotificationConsumer, this, "PORT_STATUS_NOTIFICATIONS"); Orch::addExecutor(portStatusNotificatier); + + if (gMySwitchType == "voq") + { + string tableName; + //Add subscriber to process system LAG (System PortChannel) table + tableName = CHASSIS_APP_LAG_TABLE_NAME; + Orch::addExecutor(new Consumer(new SubscriberStateTable(chassisAppDb, tableName, TableConsumable::DEFAULT_POP_BATCH_SIZE, 0), this, tableName)); + m_tableVoqSystemLagTable = unique_ptr
(new Table(chassisAppDb, CHASSIS_APP_LAG_TABLE_NAME)); + + //Add subscriber to process system LAG member (System PortChannelMember) table + tableName = CHASSIS_APP_LAG_MEMBER_TABLE_NAME; + Orch::addExecutor(new Consumer(new SubscriberStateTable(chassisAppDb, tableName, TableConsumable::DEFAULT_POP_BATCH_SIZE, 0), this, tableName)); + m_tableVoqSystemLagMemberTable = unique_ptr
(new Table(chassisAppDb, CHASSIS_APP_LAG_MEMBER_TABLE_NAME)); + + m_lagIdAllocator = unique_ptr (new LagIdAllocator(chassisAppDb)); + } } void PortsOrch::removeDefaultVlanMembers() { /* Get VLAN members in default VLAN */ - vector vlan_member_list(m_portCount); + vector vlan_member_list(m_portCount + m_systemPortCount); sai_attribute_t attr; attr.id = SAI_VLAN_ATTR_MEMBER_LIST; attr.value.objlist.count = (uint32_t)vlan_member_list.size(); attr.value.objlist.list = vlan_member_list.data(); - sai_status_t status = sai_vlan_api->get_vlan_attribute(m_defaultVlan_ObjId, 1, &attr); + sai_status_t status = sai_vlan_api->get_vlan_attribute(m_defaultVlan, 1, &attr); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to get VLAN member list in default VLAN, rv:%d", status); @@ -452,10 +476,10 @@ void PortsOrch::removeDefaultVlanMembers() void PortsOrch::removeDefaultBridgePorts() { /* Get bridge ports in default 1Q bridge - * By default, there will be m_portCount number of SAI_BRIDGE_PORT_TYPE_PORT + * By default, there will be (m_portCount + m_systemPortCount) number of SAI_BRIDGE_PORT_TYPE_PORT * ports and one SAI_BRIDGE_PORT_TYPE_1Q_ROUTER port. The former type of * ports will be removed. */ - vector bridge_port_list(m_portCount + 1); + vector bridge_port_list(m_portCount + m_systemPortCount + 1); sai_attribute_t attr; attr.id = SAI_BRIDGE_ATTR_PORT_LIST; @@ -587,12 +611,35 @@ bool PortsOrch::getPort(sai_object_id_t id, Port &port) { SWSS_LOG_ENTER(); - auto itr = portOidToName.find(id); - if (itr == portOidToName.end()) - return false; - else { - getPort(itr->second, port); - return true; + for (const auto& portIter: m_portList) + { + switch (portIter.second.m_type) + { + case Port::PHY: + case Port::SYSTEM: + if(portIter.second.m_port_id == id) + { + port = portIter.second; + return true; + } + break; + case Port::LAG: + if(portIter.second.m_lag_id == id) + { + port = portIter.second; + return true; + } + break; + case Port::VLAN: + if (portIter.second.m_vlan_info.vlan_oid == id) + { + port = portIter.second; + return true; + } + break; + default: + continue; + } } return false; @@ -614,12 +661,13 @@ bool PortsOrch::getPortByBridgePortId(sai_object_id_t bridge_port_id, Port &port { SWSS_LOG_ENTER(); - auto itr = portOidToName.find(bridge_port_id); - if (itr == portOidToName.end()) - return false; - else { - getPort(itr->second, port); - return true; + for (auto &it: m_portList) + { + if (it.second.m_bridge_port_id == bridge_port_id) + { + port = it.second; + return true; + } } return false; @@ -693,6 +741,17 @@ bool PortsOrch::addSubPort(Port &port, const string &alias, const bool &adminUp, } p.m_vlan_info.vlan_id = vlan_id; + // Change hostif vlan tag for the parent port only when a first subport is created + if (parentPort.m_child_ports.empty()) + { + if (!setHostIntfsStripTag(parentPort, SAI_HOSTIF_VLAN_TAG_KEEP)) + { + SWSS_LOG_ERROR("Failed to set %s for hostif of port %s", + hostif_vlan_tag[SAI_HOSTIF_VLAN_TAG_KEEP], parentPort.m_alias.c_str()); + return false; + } + } + parentPort.m_child_ports.insert(p.m_alias); m_portList[alias] = p; @@ -729,6 +788,21 @@ bool PortsOrch::removeSubPort(const string &alias) m_portList[parentPort.m_alias] = parentPort; m_portList.erase(it); + + // Restore hostif vlan tag for the parent port when the last subport is removed + if (parentPort.m_child_ports.empty()) + { + if (parentPort.m_bridge_port_id == SAI_NULL_OBJECT_ID) + { + if (!setHostIntfsStripTag(parentPort, SAI_HOSTIF_VLAN_TAG_STRIP)) + { + SWSS_LOG_ERROR("Failed to set %s for hostif of port %s", + hostif_vlan_tag[SAI_HOSTIF_VLAN_TAG_STRIP], parentPort.m_alias.c_str()); + return false; + } + } + } + return true; } @@ -777,11 +851,16 @@ bool PortsOrch::setPortAdminStatus(Port &port, bool state) attr.id = SAI_PORT_ATTR_ADMIN_STATE; attr.value.booldata = state; - if (sai_port_api->set_port_attribute(port.m_port_id, &attr) != SAI_STATUS_SUCCESS) + sai_status_t status = sai_port_api->set_port_attribute(port.m_port_id, &attr); + if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to set admin status %s to port pid:%" PRIx64, state ? "UP" : "DOWN", port.m_port_id); - return false; + task_process_status handle_status = handleSaiSetStatus(SAI_API_PORT, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } SWSS_LOG_INFO("Set admin status %s to port pid:%" PRIx64, @@ -827,7 +906,11 @@ bool PortsOrch::setPortMtu(sai_object_id_t id, sai_uint32_t mtu) { SWSS_LOG_ERROR("Failed to set MTU %u to port pid:%" PRIx64 ", rv:%d", attr.value.u32, id, status); - return false; + task_process_status handle_status = handleSaiSetStatus(SAI_API_PORT, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } SWSS_LOG_INFO("Set MTU %u to port pid:%" PRIx64, attr.value.u32, id); return true; @@ -841,10 +924,15 @@ bool PortsOrch::setPortFec(Port &port, sai_port_fec_mode_t mode) attr.id = SAI_PORT_ATTR_FEC_MODE; attr.value.s32 = mode; - if (sai_port_api->set_port_attribute(port.m_port_id, &attr) != SAI_STATUS_SUCCESS) + sai_status_t status = sai_port_api->set_port_attribute(port.m_port_id, &attr); + if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to set fec mode %d to port pid:%" PRIx64, mode, port.m_port_id); - return false; + task_process_status handle_status = handleSaiSetStatus(SAI_API_PORT, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } SWSS_LOG_INFO("Set fec mode %d to port pid:%" PRIx64, mode, port.m_port_id); @@ -904,7 +992,11 @@ bool PortsOrch::setPortPfc(sai_object_id_t portId, uint8_t pfc_bitmask) if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to set PFC 0x%x to port id 0x%" PRIx64 " (rc:%d)", attr.value.u8, portId, status); - return false; + task_process_status handle_status = handleSaiSetStatus(SAI_API_PORT, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } if (p.m_pfc_bitmask != pfc_bitmask) @@ -952,7 +1044,11 @@ bool PortsOrch::setPortPfcAsym(Port &port, string pfc_asym) if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to set PFC mode %d to port id 0x%" PRIx64 " (rc:%d)", port.m_pfc_asym, port.m_port_id, status); - return false; + task_process_status handle_status = handleSaiSetStatus(SAI_API_PORT, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } if (!setPortPfc(port.m_port_id, pfc)) @@ -969,7 +1065,11 @@ bool PortsOrch::setPortPfcAsym(Port &port, string pfc_asym) if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to set RX PFC 0x%x to port id 0x%" PRIx64 " (rc:%d)", attr.value.u8, port.m_port_id, status); - return false; + task_process_status handle_status = handleSaiSetStatus(SAI_API_PORT, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } } @@ -1015,6 +1115,16 @@ bool PortsOrch::bindUnbindAclTableGroup(Port &port, attr.id = ingress ? SAI_PORT_ATTR_INGRESS_ACL : SAI_PORT_ATTR_EGRESS_ACL; status = sai_port_api->set_port_attribute(port.m_port_id, &attr); + if (SAI_STATUS_SUCCESS != status) + { + SWSS_LOG_ERROR("Failed to %s %s to ACL table group %" PRIx64 ", rv:%d", + bind_str.c_str(), port.m_alias.c_str(), attr.value.oid, status); + task_process_status handle_status = handleSaiSetStatus(SAI_API_PORT, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } + } break; } case Port::LAG: @@ -1022,6 +1132,16 @@ bool PortsOrch::bindUnbindAclTableGroup(Port &port, attr.id = ingress ? SAI_LAG_ATTR_INGRESS_ACL : SAI_LAG_ATTR_EGRESS_ACL; status = sai_lag_api->set_lag_attribute(port.m_lag_id, &attr); + if (SAI_STATUS_SUCCESS != status) + { + SWSS_LOG_ERROR("Failed to %s %s to ACL table group %" PRIx64 ", rv:%d", + bind_str.c_str(), port.m_alias.c_str(), attr.value.oid, status); + task_process_status handle_status = handleSaiSetStatus(SAI_API_LAG, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } + } break; } case Port::VLAN: @@ -1031,6 +1151,16 @@ bool PortsOrch::bindUnbindAclTableGroup(Port &port, status = sai_vlan_api->set_vlan_attribute(port.m_vlan_info.vlan_oid, &attr); + if (SAI_STATUS_SUCCESS != status) + { + SWSS_LOG_ERROR("Failed to %s %s to ACL table group %" PRIx64 ", rv:%d", + bind_str.c_str(), port.m_alias.c_str(), attr.value.oid, status); + task_process_status handle_status = handleSaiSetStatus(SAI_API_VLAN, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } + } break; } default: @@ -1041,13 +1171,6 @@ bool PortsOrch::bindUnbindAclTableGroup(Port &port, } } - if (SAI_STATUS_SUCCESS != status) - { - SWSS_LOG_ERROR("Failed to %s %s to ACL table group %" PRIx64 ", rv:%d", - bind_str.c_str(), port.m_alias.c_str(), attr.value.oid, status); - return false; - } - return true; } @@ -1105,7 +1228,11 @@ bool PortsOrch::unbindRemoveAclTableGroup(sai_object_id_t port_oid, if (SAI_STATUS_SUCCESS != status) { SWSS_LOG_ERROR("Failed to remove ACL table group, rv:%d", status); - return false; + task_process_status handle_status = handleSaiRemoveStatus(SAI_API_ACL, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } sai_acl_bind_point_type_t bind_type; if (!getSaiAclBindPointType(port.m_type, bind_type)) @@ -1188,7 +1315,11 @@ bool PortsOrch::createBindAclTableGroup(sai_object_id_t port_oid, if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to create ACL table group, rv:%d", status); - return false; + task_process_status handle_status = handleSaiCreateStatus(SAI_API_ACL, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } assert(group_oid_ref != SAI_NULL_OBJECT_ID); @@ -1231,7 +1362,18 @@ bool PortsOrch::unbindAclTable(sai_object_id_t port_oid, if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to remove ACL group member: %" PRIu64 " ", acl_group_member_oid); - return false; + task_process_status handle_status = handleSaiRemoveStatus(SAI_API_ACL, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } + } + + + Port port; + if (getPort(port_oid, port)) + { + decreasePortRefCount(port.m_alias); } if (!unbindRemoveAclTableGroup(port_oid, acl_table_oid, acl_stage)) { @@ -1291,7 +1433,17 @@ bool PortsOrch::bindAclTable(sai_object_id_t port_oid, { SWSS_LOG_ERROR("Failed to create member in ACL table group %" PRIx64 " for ACL table %" PRIx64 ", rv:%d", group_oid, table_oid, status); - return false; + task_process_status handle_status = handleSaiCreateStatus(SAI_API_ACL, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } + } + + Port port; + if (getPort(port_oid, port)) + { + increasePortRefCount(port.m_alias); } return true; @@ -1307,6 +1459,12 @@ bool PortsOrch::setPortPvid(Port &port, sai_uint32_t pvid) return true; } + if(port.m_type == Port::SYSTEM) + { + SWSS_LOG_INFO("pvid setting for system port %s is not applicable", port.m_alias.c_str()); + return true; + } + if (port.m_rif_id) { SWSS_LOG_ERROR("pvid setting for router interface %s is not allowed", port.m_alias.c_str()); @@ -1324,7 +1482,11 @@ bool PortsOrch::setPortPvid(Port &port, sai_uint32_t pvid) if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to set pvid %u to port: %s", attr.value.u32, port.m_alias.c_str()); - return false; + task_process_status handle_status = handleSaiSetStatus(SAI_API_PORT, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } SWSS_LOG_NOTICE("Set pvid %u to port: %s", attr.value.u32, port.m_alias.c_str()); } @@ -1338,7 +1500,11 @@ bool PortsOrch::setPortPvid(Port &port, sai_uint32_t pvid) if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to set pvid %u to lag: %s", attr.value.u32, port.m_alias.c_str()); - return false; + task_process_status handle_status = handleSaiSetStatus(SAI_API_LAG, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } SWSS_LOG_NOTICE("Set pvid %u to lag: %s", attr.value.u32, port.m_alias.c_str()); } @@ -1406,7 +1572,11 @@ bool PortsOrch::setHostIntfsStripTag(Port &port, sai_hostif_vlan_tag_t strip) { SWSS_LOG_ERROR("Failed to set %s to host interface %s", hostif_vlan_tag[strip], p.m_alias.c_str()); - return false; + task_process_status handle_status = handleSaiSetStatus(SAI_API_HOSTIF, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } SWSS_LOG_NOTICE("Set %s to host interface: %s", hostif_vlan_tag[strip], p.m_alias.c_str()); @@ -1594,11 +1764,16 @@ bool PortsOrch::setGearboxPortAttr(Port &port, dest_port_type_t port_type, sai_p else { SWSS_LOG_ERROR("BOX: Failed to set %s port attribute %d", port.m_alias.c_str(), id); + task_process_status handle_status = handleSaiSetStatus(SAI_API_PORT, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } } } - return status == SAI_STATUS_SUCCESS; + return true; } bool PortsOrch::setPortSpeed(Port &port, sai_uint32_t speed) @@ -1612,13 +1787,17 @@ bool PortsOrch::setPortSpeed(Port &port, sai_uint32_t speed) attr.value.u32 = speed; status = sai_port_api->set_port_attribute(port.m_port_id, &attr); - - if (status == SAI_STATUS_SUCCESS) + if (status != SAI_STATUS_SUCCESS) { - setGearboxPortsAttr(port, SAI_PORT_ATTR_SPEED, &speed); + task_process_status handle_status = handleSaiSetStatus(SAI_API_PORT, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } - return status == SAI_STATUS_SUCCESS; + setGearboxPortsAttr(port, SAI_PORT_ATTR_SPEED, &speed); + return true; } bool PortsOrch::getPortSpeed(sai_object_id_t id, sai_uint32_t &speed) @@ -1654,8 +1833,16 @@ bool PortsOrch::setPortAdvSpeed(sai_object_id_t port_id, sai_uint32_t speed) attr.value.u32list.count = static_cast(speeds.size()); status = sai_port_api->set_port_attribute(port_id, &attr); + if (status != SAI_STATUS_SUCCESS) + { + task_process_status handle_status = handleSaiSetStatus(SAI_API_PORT, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } + } - return status == SAI_STATUS_SUCCESS; + return true; } bool PortsOrch::getQueueTypeAndIndex(sai_object_id_t queue_id, string &type, uint8_t &index) @@ -1713,7 +1900,11 @@ bool PortsOrch::setPortAutoNeg(sai_object_id_t id, int an) if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to set AutoNeg %u to port pid:%" PRIx64, attr.value.booldata, id); - return false; + task_process_status handle_status = handleSaiSetStatus(SAI_API_PORT, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } SWSS_LOG_INFO("Set AutoNeg %u to port pid:%" PRIx64, attr.value.booldata, id); return true; @@ -1741,6 +1932,55 @@ bool PortsOrch::setHostIntfsOperStatus(const Port& port, bool isUp) const return true; } +bool PortsOrch::createVlanHostIntf(Port& vl, string hostif_name) +{ + SWSS_LOG_ENTER(); + + if (vl.m_vlan_info.host_intf_id != SAI_NULL_OBJECT_ID) + { + SWSS_LOG_ERROR("Host interface already assigned to VLAN %d", vl.m_vlan_info.vlan_id); + return false; + } + + vector attrs; + sai_attribute_t attr; + + attr.id = SAI_HOSTIF_ATTR_TYPE; + attr.value.s32 = SAI_HOSTIF_TYPE_NETDEV; + attrs.push_back(attr); + + attr.id = SAI_HOSTIF_ATTR_OBJ_ID; + attr.value.oid = vl.m_vlan_info.vlan_oid; + attrs.push_back(attr); + + attr.id = SAI_HOSTIF_ATTR_NAME; + strncpy(attr.value.chardata, hostif_name.c_str(), sizeof(attr.value.chardata)); + attrs.push_back(attr); + + sai_status_t status = sai_hostif_api->create_hostif(&vl.m_vlan_info.host_intf_id, gSwitchId, (uint32_t)attrs.size(), attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create host interface %s for VLAN %d", hostif_name.c_str(), vl.m_vlan_info.vlan_id); + return false; + } + + m_portList[vl.m_alias] = vl; + + return true; +} + +bool PortsOrch::removeVlanHostIntf(Port vl) +{ + sai_status_t status = sai_hostif_api->remove_hostif(vl.m_vlan_info.host_intf_id); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to remove VLAN %d host interface", vl.m_vlan_info.vlan_id); + return false; + } + + return true; +} + void PortsOrch::updateDbPortOperStatus(const Port& port, sai_port_oper_status_t status) const { SWSS_LOG_ENTER(); @@ -1758,21 +1998,6 @@ void PortsOrch::updateDbPortOperStatus(const Port& port, sai_port_oper_status_t m_portTable->set(port.m_alias, tuples); } -void PortsOrch::updateDbVlanOperStatus(const Port& vlan, string status) const -{ - SWSS_LOG_NOTICE("vlan %s status %s", vlan.m_alias.c_str(), status.c_str()); - - vector tuples; - FieldValueTuple tuple("oper_status", status); - tuples.push_back(tuple); - - std::vector entry; - - SWSS_LOG_NOTICE("sending oper state notification to VlanMgr"); - - notifications->send(status, vlan.m_alias, entry); -} - bool PortsOrch::addPort(const set &lane_set, uint32_t speed, int an, string fec_mode) { SWSS_LOG_ENTER(); @@ -1810,7 +2035,11 @@ bool PortsOrch::addPort(const set &lane_set, uint32_t speed, int an, string if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to create port with the speed %u, rv:%d", speed, status); - return false; + task_process_status handle_status = handleSaiCreateStatus(SAI_API_PORT, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } m_portListLaneMap[lane_set] = port_id; @@ -1827,6 +2056,16 @@ sai_status_t PortsOrch::removePort(sai_object_id_t port_id) Port port; + /* + * Make sure to bring down admin state. + * SET would have replaced with DEL + */ + if (getPort(port_id, port)) + { + setPortAdminStatus(port, false); + } + /* else : port is in default state or not yet created */ + sai_status_t status = sai_port_api->remove_port(port_id); if (status != SAI_STATUS_SUCCESS) { @@ -1849,6 +2088,11 @@ string PortsOrch::getPriorityGroupWatermarkFlexCounterTableKey(string key) return string(PG_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP) + ":" + key; } +string PortsOrch::getPriorityGroupDropPacketsFlexCounterTableKey(string key) +{ + return string(PG_DROP_STAT_COUNTER_FLEX_COUNTER_GROUP) + ":" + key; +} + bool PortsOrch::initPort(const string &alias, const int index, const set &lane_set) { SWSS_LOG_ENTER(); @@ -1878,7 +2122,6 @@ bool PortsOrch::initPort(const string &alias, const int index, const set &l /* Add port to port list */ m_portList[alias] = p; - portOidToName[id] = alias; m_port_ref_count[alias] = 0; m_portOidToIndex[id] = index; @@ -1937,6 +2180,9 @@ void PortsOrch::deInitPort(string alias, sai_object_id_t port_id) /* remove port name map from counter table */ m_counter_db->hdel(COUNTERS_PORT_NAME_MAP, alias); + /* Remove the associated port serdes attribute */ + removePortSerdesAttribute(p.m_port_id); + m_portList[alias].m_init = false; SWSS_LOG_NOTICE("De-Initialized port %s", alias.c_str()); } @@ -2082,6 +2328,7 @@ void PortsOrch::doPortTask(Consumer &consumer) */ if (!m_initDone) { + addSystemPorts(); m_initDone = true; SWSS_LOG_INFO("Get PortInitDone notification from portsyncd."); } @@ -2094,9 +2341,9 @@ void PortsOrch::doPortTask(Consumer &consumer) if (op == SET_COMMAND) { set lane_set; - vector pre_emphasis; - vector idriver; - vector ipredriver; + vector attr_val; + map> serdes_attr; + typedef pair> serdes_attr_pair; string admin_status; string fec_mode; string pfc_asym; @@ -2108,14 +2355,14 @@ void PortsOrch::doPortTask(Consumer &consumer) for (auto i : kfvFieldsValues(t)) { + attr_val.clear(); /* Set interface index */ if (fvField(i) == "index") { index = (int)stoul(fvValue(i)); } - /* Get lane information of a physical port and initialize the port */ - if (fvField(i) == "lanes") + else if (fvField(i) == "lanes") { string lane_str; istringstream iss(fvValue(i)); @@ -2125,65 +2372,107 @@ void PortsOrch::doPortTask(Consumer &consumer) int lane = stoi(lane_str); lane_set.insert(lane); } - } - /* Set port admin status */ - if (fvField(i) == "admin_status") + else if (fvField(i) == "admin_status") { admin_status = fvValue(i); } - /* Set port MTU */ - if (fvField(i) == "mtu") + else if (fvField(i) == "mtu") { mtu = (uint32_t)stoul(fvValue(i)); } - /* Set port speed */ - if (fvField(i) == "speed") + else if (fvField(i) == "speed") { speed = (uint32_t)stoul(fvValue(i)); } - /* Set port fec */ - if (fvField(i) == "fec") + else if (fvField(i) == "fec") { fec_mode = fvValue(i); } - /* Get port fdb learn mode*/ - if (fvField(i) == "learn_mode") + else if (fvField(i) == "learn_mode") { learn_mode = fvValue(i); } - /* Set port asymmetric PFC */ - if (fvField(i) == "pfc_asym") + else if (fvField(i) == "pfc_asym") + { pfc_asym = fvValue(i); - + } /* Set autoneg and ignore the port speed setting */ - if (fvField(i) == "autoneg") + else if (fvField(i) == "autoneg") { - an = (int)stoul(fvValue(i)); + an = (fvValue(i) == "on"); } - /* Set port serdes Pre-emphasis */ - if (fvField(i) == "preemphasis") + else if (fvField(i) == "preemphasis") { - getPortSerdesVal(fvValue(i), pre_emphasis); + getPortSerdesVal(fvValue(i), attr_val); + serdes_attr.insert(serdes_attr_pair(SAI_PORT_SERDES_ATTR_PREEMPHASIS, attr_val)); } - /* Set port serdes idriver */ - if (fvField(i) == "idriver") + else if (fvField(i) == "idriver") { - getPortSerdesVal(fvValue(i), idriver); + getPortSerdesVal(fvValue(i), attr_val); + serdes_attr.insert(serdes_attr_pair(SAI_PORT_SERDES_ATTR_IDRIVER, attr_val)); } - /* Set port serdes ipredriver */ - if (fvField(i) == "ipredriver") + else if (fvField(i) == "ipredriver") + { + getPortSerdesVal(fvValue(i), attr_val); + serdes_attr.insert(serdes_attr_pair(SAI_PORT_SERDES_ATTR_IPREDRIVER, attr_val)); + } + /* Set port serdes pre1 */ + else if (fvField(i) == "pre1") + { + getPortSerdesVal(fvValue(i), attr_val); + serdes_attr.insert(serdes_attr_pair(SAI_PORT_SERDES_ATTR_TX_FIR_PRE1, attr_val)); + } + /* Set port serdes pre2 */ + else if (fvField(i) == "pre2") + { + getPortSerdesVal(fvValue(i), attr_val); + serdes_attr.insert(serdes_attr_pair(SAI_PORT_SERDES_ATTR_TX_FIR_PRE2, attr_val)); + } + /* Set port serdes pre3 */ + else if (fvField(i) == "pre3") + { + getPortSerdesVal(fvValue(i), attr_val); + serdes_attr.insert(serdes_attr_pair(SAI_PORT_SERDES_ATTR_TX_FIR_PRE3, attr_val)); + } + /* Set port serdes main */ + else if (fvField(i) == "main") { - getPortSerdesVal(fvValue(i), ipredriver); + getPortSerdesVal(fvValue(i), attr_val); + serdes_attr.insert(serdes_attr_pair(SAI_PORT_SERDES_ATTR_TX_FIR_MAIN, attr_val)); + } + /* Set port serdes post1 */ + else if (fvField(i) == "post1") + { + getPortSerdesVal(fvValue(i), attr_val); + serdes_attr.insert(serdes_attr_pair(SAI_PORT_SERDES_ATTR_TX_FIR_POST1, attr_val)); + } + /* Set port serdes post2 */ + else if (fvField(i) == "post2") + { + getPortSerdesVal(fvValue(i), attr_val); + serdes_attr.insert(serdes_attr_pair(SAI_PORT_SERDES_ATTR_TX_FIR_POST2, attr_val)); + } + /* Set port serdes post3 */ + else if (fvField(i) == "post3") + { + getPortSerdesVal(fvValue(i), attr_val); + serdes_attr.insert(serdes_attr_pair(SAI_PORT_SERDES_ATTR_TX_FIR_POST3, attr_val)); + } + /* Set port serdes attn */ + else if (fvField(i) == "attn") + { + getPortSerdesVal(fvValue(i), attr_val); + serdes_attr.insert(serdes_attr_pair(SAI_PORT_SERDES_ATTR_TX_FIR_ATTN, attr_val)); } } @@ -2275,12 +2564,13 @@ void PortsOrch::doPortTask(Consumer &consumer) } else { - if (an != -1 && an != p.m_autoneg) + if (an != -1 && (!p.m_an_cfg || an != p.m_autoneg)) { if (setPortAutoNeg(p.m_port_id, an)) { SWSS_LOG_NOTICE("Set port %s AutoNeg to %u", alias.c_str(), an); p.m_autoneg = an; + p.m_an_cfg = true; m_portList[alias] = p; // Once AN is changed @@ -2413,7 +2703,7 @@ void PortsOrch::doPortTask(Consumer &consumer) if (fec_mode_map.find(fec_mode) != fec_mode_map.end()) { /* reset fec mode upon mode change */ - if (p.m_fec_mode != fec_mode_map[fec_mode]) + if (!p.m_fec_cfg || p.m_fec_mode != fec_mode_map[fec_mode]) { if (p.m_admin_state_up) { @@ -2427,6 +2717,7 @@ void PortsOrch::doPortTask(Consumer &consumer) p.m_admin_state_up = false; p.m_fec_mode = fec_mode_map[fec_mode]; + p.m_fec_cfg = true; if (setPortFec(p, p.m_fec_mode)) { @@ -2444,6 +2735,7 @@ void PortsOrch::doPortTask(Consumer &consumer) { /* Port is already down, setting fec mode*/ p.m_fec_mode = fec_mode_map[fec_mode]; + p.m_fec_cfg = true; if (setPortFec(p, p.m_fec_mode)) { m_portList[alias] = p; @@ -2504,9 +2796,9 @@ void PortsOrch::doPortTask(Consumer &consumer) } } - if (pre_emphasis.size() != 0) + if (serdes_attr.size() != 0) { - if (setPortSerdesAttribute(p.m_port_id, SAI_PORT_ATTR_SERDES_PREEMPHASIS, pre_emphasis)) + if (setPortSerdesAttribute(p.m_port_id, serdes_attr)) { SWSS_LOG_NOTICE("Set port %s preemphasis is success", alias.c_str()); } @@ -2519,48 +2811,18 @@ void PortsOrch::doPortTask(Consumer &consumer) } - if (idriver.size() != 0) + /* Last step set port admin status */ + if (!admin_status.empty() && (p.m_admin_state_up != (admin_status == "up"))) { - if (setPortSerdesAttribute(p.m_port_id, SAI_PORT_ATTR_SERDES_IDRIVER, idriver)) + if (setPortAdminStatus(p, admin_status == "up")) { - SWSS_LOG_NOTICE("Set port %s idriver is success", alias.c_str()); + p.m_admin_state_up = (admin_status == "up"); + m_portList[alias] = p; + SWSS_LOG_NOTICE("Set port %s admin status to %s", alias.c_str(), admin_status.c_str()); } else { - SWSS_LOG_ERROR("Failed to set port %s idriver", alias.c_str()); - it++; - continue; - } - - } - - if (ipredriver.size() != 0) - { - if (setPortSerdesAttribute(p.m_port_id, SAI_PORT_ATTR_SERDES_IPREDRIVER, ipredriver)) - { - SWSS_LOG_NOTICE("Set port %s ipredriver is success", alias.c_str()); - } - else - { - SWSS_LOG_ERROR("Failed to set port %s ipredriver", alias.c_str()); - it++; - continue; - } - - } - - /* Last step set port admin status */ - if (!admin_status.empty() && (p.m_admin_state_up != (admin_status == "up"))) - { - if (setPortAdminStatus(p, admin_status == "up")) - { - p.m_admin_state_up = (admin_status == "up"); - m_portList[alias] = p; - SWSS_LOG_NOTICE("Set port %s admin status to %s", alias.c_str(), admin_status.c_str()); - } - else - { - SWSS_LOG_ERROR("Failed to set port %s admin status to %s", alias.c_str(), admin_status.c_str()); + SWSS_LOG_ERROR("Failed to set port %s admin status to %s", alias.c_str(), admin_status.c_str()); it++; continue; } @@ -2660,6 +2922,7 @@ void PortsOrch::doVlanTask(Consumer &consumer) // Retrieve attributes uint32_t mtu = 0; MacAddress mac; + string hostif_name = ""; for (auto i : kfvFieldsValues(t)) { if (fvField(i) == "mtu") @@ -2670,6 +2933,10 @@ void PortsOrch::doVlanTask(Consumer &consumer) { mac = MacAddress(fvValue(i)); } + if (fvField(i) == "hostif_name") + { + hostif_name = fvValue(i); + } } /* @@ -2712,6 +2979,16 @@ void PortsOrch::doVlanTask(Consumer &consumer) gIntfsOrch->setRouterIntfsMac(vl); } } + if (!hostif_name.empty()) + { + if (!createVlanHostIntf(vl, hostif_name)) + { + // No need to fail in case of error as this is for monitoring VLAN. + // Error message is printed by "createVlanHostIntf" so just handle failure gracefully. + it = consumer.m_toSync.erase(it); + continue; + } + } } it = consumer.m_toSync.erase(it); @@ -2824,23 +3101,24 @@ void PortsOrch::doVlanMemberTask(Consumer &consumer) } else if (op == DEL_COMMAND) { - int ret = true; if (vlan.m_members.find(port_alias) != vlan.m_members.end()) { - ret = removeVlanMember(vlan, port); - } - if ((ret) && m_portVlanMember[port.m_alias].empty()) - { - ret = removeBridgePort(port); - } - if (ret) - { - it = consumer.m_toSync.erase(it); + if (removeVlanMember(vlan, port)) + { + if (port.m_vlan_members.empty()) + { + removeBridgePort(port); + } + it = consumer.m_toSync.erase(it); + } + else + { + it++; + } } else - { - it++; - } + /* Cannot locate the VLAN */ + it = consumer.m_toSync.erase(it); } else { @@ -2854,6 +3132,8 @@ void PortsOrch::doLagTask(Consumer &consumer) { SWSS_LOG_ENTER(); + string table_name = consumer.getTableName(); + auto it = consumer.m_toSync.begin(); while (it != consumer.m_toSync.end()) { @@ -2866,11 +3146,10 @@ void PortsOrch::doLagTask(Consumer &consumer) { // Retrieve attributes uint32_t mtu = 0; - - string oper_status; string learn_mode; string operation_status; - bool operation_status_changed = false; + uint32_t lag_id = 0; + int32_t switch_id = -1; for (auto i : kfvFieldsValues(t)) { @@ -2891,21 +3170,43 @@ void PortsOrch::doLagTask(Consumer &consumer) it++; continue; } + } + else if (fvField(i) == "lag_id") + { + lag_id = (uint32_t)stoul(fvValue(i)); + } + else if (fvField(i) == "switch_id") + { + switch_id = stoi(fvValue(i)); + } + } - gNeighOrch->ifChangeInformNextHop(alias, - (operation_status == "up")); - Port lag; - if (getPort(alias, lag)) - { - operation_status_changed = - (string_oper_status.at(operation_status) != - lag.m_oper_status); - } - oper_status = fvValue(i); + if (table_name == CHASSIS_APP_LAG_TABLE_NAME) + { + if (switch_id == gVoqMySwitchId) + { + //Already created, syncd local lag from CHASSIS_APP_DB. Skip + it = consumer.m_toSync.erase(it); + continue; } } + else + { + // For local portchannel + + lag_id = 0; + switch_id = -1; + } - auto status = addLag(alias); + // Create a new LAG when the new alias comes + if (m_portList.find(alias) == m_portList.end()) + { + if (!addLag(alias, lag_id, switch_id)) + { + it++; + continue; + } + } // Process attributes Port l; @@ -2922,14 +3223,7 @@ void PortsOrch::doLagTask(Consumer &consumer) m_portList[alias] = l; } - if (operation_status_changed) - { - PortOperStateUpdate update; - update.port = l; - update.operStatus = string_oper_status.at(operation_status); - notify(SUBJECT_TYPE_PORT_OPER_STATE_CHANGE, static_cast(&update)); - } - if ((mtu != 0) && (mtu != l.m_mtu)) + if (mtu != 0) { l.m_mtu = mtu; m_portList[alias] = l; @@ -2941,16 +3235,6 @@ void PortsOrch::doLagTask(Consumer &consumer) updateChildPortsMtu(l, mtu); } - if (!oper_status.empty()) - { - if (oper_status != "up") - gFdbOrch->flushFdbByPort(alias, 0); - - /* Trigger status updated only if it is set */ - sai_port_oper_status_t status = (oper_status == "up") ? SAI_PORT_OPER_STATUS_UP : SAI_PORT_OPER_STATUS_DOWN; - updateLagOperStatus(l, status); - } - if (!learn_mode.empty() && (l.m_learn_mode != learn_mode)) { if (l.m_bridge_port_id != SAI_NULL_OBJECT_ID) @@ -2977,15 +3261,8 @@ void PortsOrch::doLagTask(Consumer &consumer) } } } - if (!status) - { - it++; - continue; - } - else - { - it = consumer.m_toSync.erase(it); - } + + it = consumer.m_toSync.erase(it); } else if (op == DEL_COMMAND) { @@ -3014,6 +3291,8 @@ void PortsOrch::doLagMemberTask(Consumer &consumer) { SWSS_LOG_ENTER(); + string table_name = consumer.getTableName(); + auto it = consumer.m_toSync.begin(); while (it != consumer.m_toSync.end()) { @@ -3048,6 +3327,27 @@ void PortsOrch::doLagMemberTask(Consumer &consumer) continue; } + if (table_name == CHASSIS_APP_LAG_MEMBER_TABLE_NAME) + { + int32_t lag_switch_id = lag.m_system_lag_info.switch_id; + if (lag_switch_id == gVoqMySwitchId) + { + //Synced local member addition to local lag. Skip + it = consumer.m_toSync.erase(it); + continue; + } + + //Sanity check: The switch id-s of lag and member must match + int32_t port_switch_id = port.m_system_port_info.switch_id; + if (port_switch_id != lag_switch_id) + { + SWSS_LOG_ERROR("System lag switch id mismatch. Lag %s switch id: %d, Member %s switch id: %d", + lag_alias.c_str(), lag_switch_id, port_alias.c_str(), port_switch_id); + it = consumer.m_toSync.erase(it); + continue; + } + } + /* Update a LAG member */ if (op == SET_COMMAND) { @@ -3190,11 +3490,11 @@ void PortsOrch::doTask(Consumer &consumer) { doVlanMemberTask(consumer); } - else if (table_name == APP_LAG_TABLE_NAME) + else if (table_name == APP_LAG_TABLE_NAME || table_name == CHASSIS_APP_LAG_TABLE_NAME) { doLagTask(consumer); } - else if (table_name == APP_LAG_MEMBER_TABLE_NAME) + else if (table_name == APP_LAG_MEMBER_TABLE_NAME || table_name == CHASSIS_APP_LAG_MEMBER_TABLE_NAME) { doLagMemberTask(consumer); } @@ -3273,6 +3573,25 @@ void PortsOrch::initializePriorityGroups(Port &port) SWSS_LOG_INFO("Get priority groups for port %s", port.m_alias.c_str()); } +void PortsOrch::initializePortMaximumHeadroom(Port &port) +{ + sai_attribute_t attr; + + attr.id = SAI_PORT_ATTR_QOS_MAXIMUM_HEADROOM_SIZE; + + sai_status_t status = sai_port_api->get_port_attribute(port.m_port_id, 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_NOTICE("Unable to get the maximum headroom for port %s rv:%d, ignored", port.m_alias.c_str(), status); + return; + } + + vector fvVector; + port.m_maximum_headroom = attr.value.u32; + fvVector.emplace_back("max_headroom_size", to_string(port.m_maximum_headroom)); + m_stateBufferMaximumValueTable->set(port.m_alias, fvVector); +} + bool PortsOrch::initializePort(Port &port) { SWSS_LOG_ENTER(); @@ -3281,6 +3600,7 @@ bool PortsOrch::initializePort(Port &port) initializePriorityGroups(port); initializeQueues(port); + initializePortMaximumHeadroom(port); /* Create host interface */ if (!addHostIntfs(port, port.m_alias, port.m_hif_id)) @@ -3375,7 +3695,11 @@ bool PortsOrch::addHostIntfs(Port &port, string alias, sai_object_id_t &host_int if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to create host interface for port %s", alias.c_str()); - return false; + task_process_status handle_status = handleSaiCreateStatus(SAI_API_HOSTIF, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } SWSS_LOG_NOTICE("Create host interface for port %s", alias.c_str()); @@ -3398,7 +3722,11 @@ bool PortsOrch::setBridgePortLearningFDB(Port &port, sai_bridge_port_fdb_learnin if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to set bridge port %" PRIx64 " learning_mode attribute: %d", bridge_port_id, status); - return false; + task_process_status handle_status = handleSaiSetStatus(SAI_API_BRIDGE, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } SWSS_LOG_NOTICE("Disable FDB learning on bridge port %s(%" PRIx64 ")", port.m_alias.c_str(), bridge_port_id); return true; @@ -3408,40 +3736,8 @@ bool PortsOrch::addBridgePort(Port &port) { SWSS_LOG_ENTER(); - if (port.m_rif_id) - { - SWSS_LOG_ERROR("Adding router interface %s as bridge port is not allowed", port.m_alias.c_str()); - return false; - } if (port.m_bridge_port_id != SAI_NULL_OBJECT_ID) { - /* If the port is being added to the first VLAN, - * set bridge port admin status to UP. - * This can happen if the port was just removed from - * last VLAN and fdb flush is still in progress. - */ - if (m_portVlanMember[port.m_alias].empty()) - { - sai_attribute_t attr; - attr.id = SAI_BRIDGE_PORT_ATTR_ADMIN_STATE; - attr.value.booldata = true; - - sai_status_t status = sai_bridge_api->set_bridge_port_attribute(port.m_bridge_port_id, &attr); - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to set bridge port %s admin status to UP, rv:%d", - port.m_alias.c_str(), status); - return false; - } - port.m_bridge_port_admin_state = true; - m_portList[port.m_alias] = port; - if (!setHostIntfsStripTag(port, SAI_HOSTIF_VLAN_TAG_KEEP)) - { - SWSS_LOG_ERROR("Failed to set %s for hostif of port %s", - hostif_vlan_tag[SAI_HOSTIF_VLAN_TAG_KEEP], port.m_alias.c_str()); - return false; - } - } return true; } @@ -3512,15 +3808,12 @@ bool PortsOrch::addBridgePort(Port &port) { SWSS_LOG_ERROR("Failed to add bridge port %s to default 1Q bridge, rv:%d", port.m_alias.c_str(), status); - return false; - } - if (!setPortPvid(port, 0)) - { - SWSS_LOG_ERROR("Failed to set pvid for port %s, rv:%d", - port.m_alias.c_str(), status); - return false; + task_process_status handle_status = handleSaiCreateStatus(SAI_API_BRIDGE, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } - port.m_bridge_port_admin_state = true; if (!setHostIntfsStripTag(port, SAI_HOSTIF_VLAN_TAG_KEEP)) { @@ -3529,13 +3822,11 @@ bool PortsOrch::addBridgePort(Port &port) return false; } m_portList[port.m_alias] = port; - portOidToName[port.m_bridge_port_id] = port.m_alias; SWSS_LOG_NOTICE("Add bridge port %s to default 1Q bridge", port.m_alias.c_str()); return true; } - bool PortsOrch::removeBridgePort(Port &port) { SWSS_LOG_ENTER(); @@ -3544,45 +3835,46 @@ bool PortsOrch::removeBridgePort(Port &port) { return true; } - if (port.m_bridge_port_admin_state) - { - /* Set bridge port admin status to DOWN */ - sai_attribute_t attr; - attr.id = SAI_BRIDGE_PORT_ATTR_ADMIN_STATE; - attr.value.booldata = false; - - sai_status_t status = sai_bridge_api->set_bridge_port_attribute(port.m_bridge_port_id, &attr); - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to set bridge port %s admin status to DOWN, rv:%d", - port.m_alias.c_str(), status); - return false; - } - port.m_bridge_port_admin_state = false; - m_portList[port.m_alias] = port; + /* Set bridge port admin status to DOWN */ + sai_attribute_t attr; + attr.id = SAI_BRIDGE_PORT_ATTR_ADMIN_STATE; + attr.value.booldata = false; - if (!setHostIntfsStripTag(port, SAI_HOSTIF_VLAN_TAG_STRIP)) + sai_status_t status = sai_bridge_api->set_bridge_port_attribute(port.m_bridge_port_id, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set bridge port %s admin status to DOWN, rv:%d", + port.m_alias.c_str(), status); + task_process_status handle_status = handleSaiSetStatus(SAI_API_BRIDGE, status); + if (handle_status != task_success) { - SWSS_LOG_ERROR("Failed to set %s for hostif of port %s", - hostif_vlan_tag[SAI_HOSTIF_VLAN_TAG_STRIP], port.m_alias.c_str()); - return false; + return parseHandleSaiStatusFailure(handle_status); } } - if (port.m_fdb_count != 0) { - //SWSS_LOG_NOTICE("Port still has fdb entries, will not remove bridge port for %s", port.m_alias.c_str()); + if (!setHostIntfsStripTag(port, SAI_HOSTIF_VLAN_TAG_STRIP)) + { + SWSS_LOG_ERROR("Failed to set %s for hostif of port %s", + hostif_vlan_tag[SAI_HOSTIF_VLAN_TAG_STRIP], port.m_alias.c_str()); return false; } + //Flush the FDB entires corresponding to the port + gFdbOrch->flushFDBEntries(port.m_bridge_port_id, SAI_NULL_OBJECT_ID); + SWSS_LOG_INFO("Flush FDB entries for port %s", port.m_alias.c_str()); + /* Remove bridge port */ - sai_status_t status = sai_bridge_api->remove_bridge_port(port.m_bridge_port_id); + status = sai_bridge_api->remove_bridge_port(port.m_bridge_port_id); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to remove bridge port %s from default 1Q bridge, rv:%d", port.m_alias.c_str(), status); - return false; + task_process_status handle_status = handleSaiRemoveStatus(SAI_API_BRIDGE, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } - portOidToName.erase(port.m_bridge_port_id); port.m_bridge_port_id = SAI_NULL_OBJECT_ID; SWSS_LOG_NOTICE("Remove bridge port %s from default 1Q bridge", port.m_alias.c_str()); @@ -3617,7 +3909,11 @@ bool PortsOrch::setBridgePortLearnMode(Port &port, string learn_mode) { SWSS_LOG_ERROR("Failed to set bridge port %s learning mode, rv:%d", port.m_alias.c_str(), status); - return false; + task_process_status handle_status = handleSaiSetStatus(SAI_API_BRIDGE, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } SWSS_LOG_NOTICE("Set bridge port %s learning mode %s", port.m_alias.c_str(), learn_mode.c_str()); @@ -3635,22 +3931,16 @@ bool PortsOrch::addVlan(string vlan_alias) sai_attribute_t attr; attr.id = SAI_VLAN_ATTR_VLAN_ID; attr.value.u16 = vlan_id; - sai_status_t status = SAI_STATUS_SUCCESS; - - /* Do not create default VLAN. It is already created by default */ - if (vlan_id != m_defaultVlan_Id) - { - status = sai_vlan_api->create_vlan(&vlan_oid, gSwitchId, 1, &attr); - } - else - { - vlan_oid = m_defaultVlan_ObjId; /* use the default VLAN object id instead */ - } + sai_status_t status = sai_vlan_api->create_vlan(&vlan_oid, gSwitchId, 1, &attr); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to create VLAN %s vid:%hu", vlan_alias.c_str(), vlan_id); - return false; + task_process_status handle_status = handleSaiCreateStatus(SAI_API_VLAN, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } SWSS_LOG_NOTICE("Create an empty VLAN %s vid:%hu", vlan_alias.c_str(), vlan_id); @@ -3660,7 +3950,6 @@ bool PortsOrch::addVlan(string vlan_alias) vlan.m_vlan_info.vlan_id = vlan_id; vlan.m_members = set(); m_portList[vlan_alias] = vlan; - portOidToName[vlan_oid] = vlan_alias; m_port_ref_count[vlan_alias] = 0; return true; @@ -3669,7 +3958,6 @@ bool PortsOrch::addVlan(string vlan_alias) bool PortsOrch::removeVlan(Port vlan) { SWSS_LOG_ENTER(); - if (m_port_ref_count[vlan.m_alias] > 0) { SWSS_LOG_ERROR("Failed to remove ref count %d VLAN %s", @@ -3677,12 +3965,6 @@ bool PortsOrch::removeVlan(Port vlan) vlan.m_alias.c_str()); return false; } - /* If there are still fdb entries associated with the VLAN, - return false for retry */ - if (vlan.m_fdb_count > 0) - { - return false; - } /* Vlan removing is not allowed when the VLAN still has members */ if (vlan.m_members.size() > 0) @@ -3699,18 +3981,23 @@ bool PortsOrch::removeVlan(Port vlan) return false; } + + if (vlan.m_vlan_info.host_intf_id && !removeVlanHostIntf(vlan)) + { + SWSS_LOG_ERROR("Failed to remove VLAN %d host interface", vlan.m_vlan_info.vlan_id); + return false; + } + sai_status_t status = sai_vlan_api->remove_vlan(vlan.m_vlan_info.vlan_oid); if (status != SAI_STATUS_SUCCESS) - /* Do not delete default VLAN from driver, but clear internal state */ - if (vlan.m_vlan_info.vlan_id != m_defaultVlan_Id) { - sai_status_t status = sai_vlan_api->remove_vlan(vlan.m_vlan_info.vlan_oid); - if (status != SAI_STATUS_SUCCESS) - { SWSS_LOG_ERROR("Failed to remove VLAN %s vid:%hu", vlan.m_alias.c_str(), vlan.m_vlan_info.vlan_id); - return false; - } + task_process_status handle_status = handleSaiRemoveStatus(SAI_API_VLAN, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } removeAclTableGroup(vlan); @@ -3718,7 +4005,6 @@ bool PortsOrch::removeVlan(Port vlan) SWSS_LOG_NOTICE("Remove VLAN %s vid:%hu", vlan.m_alias.c_str(), vlan.m_vlan_info.vlan_id); - portOidToName.erase(vlan.m_vlan_info.vlan_oid); m_portList.erase(vlan.m_alias); m_port_ref_count.erase(vlan.m_alias); @@ -3774,7 +4060,11 @@ bool PortsOrch::addVlanMember(Port &vlan, Port &port, string &tagging_mode) { SWSS_LOG_ERROR("Failed to add member %s to VLAN %s vid:%hu pid:%" PRIx64, port.m_alias.c_str(), vlan.m_alias.c_str(), vlan.m_vlan_info.vlan_id, port.m_port_id); - return false; + task_process_status handle_status = handleSaiCreateStatus(SAI_API_VLAN, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } SWSS_LOG_NOTICE("Add member %s to VLAN %s vid:%hu pid%" PRIx64, port.m_alias.c_str(), vlan.m_alias.c_str(), vlan.m_vlan_info.vlan_id, port.m_port_id); @@ -3789,19 +4079,10 @@ bool PortsOrch::addVlanMember(Port &vlan, Port &port, string &tagging_mode) } /* a physical port may join multiple vlans */ - VlanMemberEntry vme = {vlan.m_alias, vlan_member_id, sai_tagging_mode}; - m_portVlanMember[port.m_alias][vlan.m_vlan_info.vlan_id] = vme; + VlanMemberEntry vme = {vlan_member_id, sai_tagging_mode}; + port.m_vlan_members[vlan.m_vlan_info.vlan_id] = vme; m_portList[port.m_alias] = port; vlan.m_members.insert(port.m_alias); - if (port.m_oper_status == SAI_PORT_OPER_STATUS_UP) - { - auto old_count = vlan.m_up_member_count; - vlan.m_up_member_count++; - if (old_count == 0) - { - updateDbVlanOperStatus(vlan, "up"); - } - } m_portList[vlan.m_alias] = vlan; VlanMemberUpdate update = { vlan, port, true }; @@ -3816,10 +4097,10 @@ bool PortsOrch::removeVlanMember(Port &vlan, Port &port) sai_object_id_t vlan_member_id; sai_vlan_tagging_mode_t sai_tagging_mode; - auto vlan_member = m_portVlanMember[port.m_alias].find(vlan.m_vlan_info.vlan_id); + auto vlan_member = port.m_vlan_members.find(vlan.m_vlan_info.vlan_id); /* Assert the port belongs to this VLAN */ - assert (vlan_member != m_portVlanMember[port.m_alias].end()); + assert (vlan_member != port.m_vlan_members.end()); sai_tagging_mode = vlan_member->second.vlan_mode; vlan_member_id = vlan_member->second.vlan_member_id; @@ -3828,18 +4109,20 @@ bool PortsOrch::removeVlanMember(Port &vlan, Port &port) { SWSS_LOG_ERROR("Failed to remove member %s from VLAN %s vid:%hx vmid:%" PRIx64, port.m_alias.c_str(), vlan.m_alias.c_str(), vlan.m_vlan_info.vlan_id, vlan_member_id); - return false; + task_process_status handle_status = handleSaiRemoveStatus(SAI_API_VLAN, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } - m_portVlanMember[port.m_alias].erase(vlan_member); - if (m_portVlanMember[port.m_alias].empty()) - m_portVlanMember.erase(port.m_alias); + port.m_vlan_members.erase(vlan_member); SWSS_LOG_NOTICE("Remove member %s from VLAN %s lid:%hx vmid:%" PRIx64, port.m_alias.c_str(), vlan.m_alias.c_str(), vlan.m_vlan_info.vlan_id, vlan_member_id); /* Restore to default pvid if this port joined this VLAN in untagged mode previously */ if (sai_tagging_mode == SAI_VLAN_TAGGING_MODE_UNTAGGED) { - if (!setPortPvid(port, 0)) + if (!setPortPvid(port, DEFAULT_PORT_VLAN_ID)) { return false; } @@ -3847,14 +4130,6 @@ bool PortsOrch::removeVlanMember(Port &vlan, Port &port) m_portList[port.m_alias] = port; vlan.m_members.erase(port.m_alias); - if (port.m_oper_status == SAI_PORT_OPER_STATUS_UP) - { - vlan.m_up_member_count--; - if (vlan.m_up_member_count == 0) - { - updateDbVlanOperStatus(vlan, "down"); - } - } m_portList[vlan.m_alias] = vlan; VlanMemberUpdate update = { vlan, port, false }; @@ -3871,28 +4146,52 @@ bool PortsOrch::isVlanMember(Port &vlan, Port &port) return true; } -bool PortsOrch::addLag(string lag_alias) +bool PortsOrch::addLag(string lag_alias, uint32_t spa_id, int32_t switch_id) { SWSS_LOG_ENTER(); - auto lagport = m_portList.find(lag_alias); - if (lagport != m_portList.end()) + vector lag_attrs; + string system_lag_alias = lag_alias; + + if (gMySwitchType == "voq") { - if ((m_portList[lag_alias].m_bridge_port_id != SAI_NULL_OBJECT_ID) && - (m_portVlanMember[lag_alias].empty())) + if (switch_id < 0) { - return false; + // Local PortChannel. Allocate unique lag id from central CHASSIS_APP_DB + // Use the chassis wide unique system lag name. + + // Get the local switch id and derive the system lag name. + + switch_id = gVoqMySwitchId; + system_lag_alias = gMyHostName + "|" + gMyAsicName + "|" + lag_alias; + + // Allocate unique lag id + spa_id = m_lagIdAllocator->lagIdAdd(system_lag_alias, 0); + + if ((int32_t)spa_id <= 0) + { + SWSS_LOG_ERROR("Failed to allocate unique LAG id for local lag %s rv:%d", lag_alias.c_str(), spa_id); + return false; + } } - return true; + + sai_attribute_t attr; + attr.id = SAI_LAG_ATTR_SYSTEM_PORT_AGGREGATE_ID; + attr.value.u32 = spa_id; + lag_attrs.push_back(attr); } sai_object_id_t lag_id; - sai_status_t status = sai_lag_api->create_lag(&lag_id, gSwitchId, 0, NULL); + sai_status_t status = sai_lag_api->create_lag(&lag_id, gSwitchId, static_cast(lag_attrs.size()), lag_attrs.data()); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to create LAG %s lid:%" PRIx64, lag_alias.c_str(), lag_id); - return false; + task_process_status handle_status = handleSaiCreateStatus(SAI_API_LAG, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } SWSS_LOG_NOTICE("Create an empty LAG %s lid:%" PRIx64, lag_alias.c_str(), lag_id); @@ -3901,17 +4200,33 @@ bool PortsOrch::addLag(string lag_alias) lag.m_lag_id = lag_id; lag.m_members = set(); m_portList[lag_alias] = lag; - portOidToName[lag_id] = lag_alias; m_port_ref_count[lag_alias] = 0; - /* Add lag name map to counter table */ + PortUpdate update = { lag, true }; + notify(SUBJECT_TYPE_PORT_CHANGE, static_cast(&update)); + FieldValueTuple tuple(lag_alias, sai_serialize_object_id(lag_id)); vector fields; fields.push_back(tuple); m_counterLagTable->set("", fields); - PortUpdate update = { lag, true }; - notify(SUBJECT_TYPE_PORT_CHANGE, static_cast(&update)); + if (gMySwitchType == "voq") + { + // If this is voq switch, record system lag info + + lag.m_system_lag_info.alias = system_lag_alias; + lag.m_system_lag_info.switch_id = switch_id; + lag.m_system_lag_info.spa_id = spa_id; + + // This will update port list with local port channel name for local port channels + // and with system lag name for the system lags received from chassis app db + + m_portList[lag_alias] = lag; + + // Sync to SYSTEM_LAG_TABLE of CHASSIS_APP_DB + + voqSyncAddLag(lag); + } return true; } @@ -3934,27 +4249,25 @@ bool PortsOrch::removeLag(Port lag) SWSS_LOG_ERROR("Failed to remove non-empty LAG %s", lag.m_alias.c_str()); return false; } - if (m_portVlanMember[lag.m_alias].size() > 0) + if (lag.m_vlan_members.size() > 0) { SWSS_LOG_ERROR("Failed to remove LAG %s, it is still in VLAN", lag.m_alias.c_str()); return false; } - if (lag.m_bridge_port_id != SAI_NULL_OBJECT_ID) - { - return false; - } sai_status_t status = sai_lag_api->remove_lag(lag.m_lag_id); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to remove LAG %s lid:%" PRIx64, lag.m_alias.c_str(), lag.m_lag_id); - return false; + task_process_status handle_status = handleSaiRemoveStatus(SAI_API_LAG, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } - SWSS_LOG_NOTICE("Remove LAG %s lid:%" PRIx64, lag.m_alias.c_str(), lag.m_lag_id); - portOidToName.erase(lag.m_lag_id); m_portList.erase(lag.m_alias); m_port_ref_count.erase(lag.m_alias); @@ -3963,8 +4276,31 @@ bool PortsOrch::removeLag(Port lag) m_counterLagTable->hdel("", lag.m_alias); - return true; -} + if (gMySwitchType == "voq") + { + // Free the lag id, if this is local LAG + + if (lag.m_system_lag_info.switch_id == gVoqMySwitchId) + { + int32_t rv; + int32_t spa_id = lag.m_system_lag_info.spa_id; + + rv = m_lagIdAllocator->lagIdDel(lag.m_system_lag_info.alias); + + if (rv != spa_id) + { + SWSS_LOG_ERROR("Failed to delete LAG id %d of local lag %s rv:%d", spa_id, lag.m_alias.c_str(), rv); + return false; + } + + // Sync to SYSTEM_LAG_TABLE of CHASSIS_APP_DB + + voqSyncDelLag(lag); + } + } + + return true; +} void PortsOrch::getLagMember(Port &lag, vector &portv) { @@ -4002,7 +4338,7 @@ bool PortsOrch::addLagMember(Port &lag, Port &port, bool enableForwarding) attr.value.oid = port.m_port_id; attrs.push_back(attr); - if (!enableForwarding) + if (!enableForwarding && port.m_type != Port::SYSTEM) { attr.id = SAI_LAG_MEMBER_ATTR_EGRESS_DISABLE; attr.value.booldata = true; @@ -4020,7 +4356,11 @@ bool PortsOrch::addLagMember(Port &lag, Port &port, bool enableForwarding) { SWSS_LOG_ERROR("Failed to add member %s to LAG %s lid:%" PRIx64 " pid:%" PRIx64, port.m_alias.c_str(), lag.m_alias.c_str(), lag.m_lag_id, port.m_port_id); - return false; + task_process_status handle_status = handleSaiCreateStatus(SAI_API_LAG, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } SWSS_LOG_NOTICE("Add member %s to LAG %s lid:%" PRIx64 " pid:%" PRIx64, @@ -4046,6 +4386,12 @@ bool PortsOrch::addLagMember(Port &lag, Port &port, bool enableForwarding) LagMemberUpdate update = { lag, port, true }; notify(SUBJECT_TYPE_LAG_MEMBER_CHANGE, static_cast(&update)); + if (gMySwitchType == "voq") + { + //Sync to SYSTEM_LAG_MEMBER_TABLE of CHASSIS_APP_DB + voqSyncAddLagMember(lag, port); + } + return true; } @@ -4057,7 +4403,11 @@ bool PortsOrch::removeLagMember(Port &lag, Port &port) { SWSS_LOG_ERROR("Failed to remove member %s from LAG %s lid:%" PRIx64 " lmid:%" PRIx64, port.m_alias.c_str(), lag.m_alias.c_str(), lag.m_lag_id, port.m_lag_member_id); - return false; + task_process_status handle_status = handleSaiRemoveStatus(SAI_API_LAG, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } SWSS_LOG_NOTICE("Remove member %s from LAG %s lid:%" PRIx64 " lmid:%" PRIx64, @@ -4081,6 +4431,12 @@ bool PortsOrch::removeLagMember(Port &lag, Port &port) LagMemberUpdate update = { lag, port, false }; notify(SUBJECT_TYPE_LAG_MEMBER_CHANGE, static_cast(&update)); + if (gMySwitchType == "voq") + { + //Sync to SYSTEM_LAG_MEMBER_TABLE of CHASSIS_APP_DB + voqSyncDelLagMember(lag, port); + } + return true; } @@ -4089,6 +4445,12 @@ bool PortsOrch::setCollectionOnLagMember(Port &lagMember, bool enableCollection) /* Port must be LAG member */ assert(lagMember.m_lag_member_id); + // Collection is not applicable for system port lag members (i.e, members of remote LAGs) + if (lagMember.m_type == Port::SYSTEM) + { + return true; + } + sai_status_t status = SAI_STATUS_FAILURE; sai_attribute_t attr {}; @@ -4101,7 +4463,11 @@ bool PortsOrch::setCollectionOnLagMember(Port &lagMember, bool enableCollection) SWSS_LOG_ERROR("Failed to %s collection on LAG member %s", enableCollection ? "enable" : "disable", lagMember.m_alias.c_str()); - return false; + task_process_status handle_status = handleSaiSetStatus(SAI_API_LAG, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } SWSS_LOG_NOTICE("%s collection on LAG member %s", @@ -4116,6 +4482,12 @@ bool PortsOrch::setDistributionOnLagMember(Port &lagMember, bool enableDistribut /* Port must be LAG member */ assert(lagMember.m_lag_member_id); + // Distribution is not applicable for system port lag members (i.e, members of remote LAGs) + if (lagMember.m_type == Port::SYSTEM) + { + return true; + } + sai_status_t status = SAI_STATUS_FAILURE; sai_attribute_t attr {}; @@ -4128,7 +4500,11 @@ bool PortsOrch::setDistributionOnLagMember(Port &lagMember, bool enableDistribut SWSS_LOG_ERROR("Failed to %s distribution on LAG member %s", enableDistribution ? "enable" : "disable", lagMember.m_alias.c_str()); - return false; + task_process_status handle_status = handleSaiSetStatus(SAI_API_LAG, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } SWSS_LOG_NOTICE("%s distribution on LAG member %s", @@ -4296,7 +4672,22 @@ void PortsOrch::generatePriorityGroupMapPerPort(const Port& port) vector fieldValues; fieldValues.emplace_back(PG_COUNTER_ID_LIST, counters_stream.str()); + m_flexCounterTable->set(key, fieldValues); + delimiter = ""; + std::ostringstream ingress_pg_drop_packets_counters_stream; + key = getPriorityGroupDropPacketsFlexCounterTableKey(id); + /* Add dropped packets counters to flex_counter */ + for (const auto& it: ingressPriorityGroupDropStatIds) + { + ingress_pg_drop_packets_counters_stream << delimiter << sai_serialize_ingress_priority_group_stat(it); + if (delimiter.empty()) + { + delimiter = comma; + } + } + fieldValues.clear(); + fieldValues.emplace_back(PG_COUNTER_ID_LIST, ingress_pg_drop_packets_counters_stream.str()); m_flexCounterTable->set(key, fieldValues); } @@ -4382,26 +4773,7 @@ void PortsOrch::updatePortOperStatus(Port &port, sai_port_oper_status_t status) } bool isUp = status == SAI_PORT_OPER_STATUS_UP; - - for(auto vlan_member: m_portVlanMember[port.m_alias]) - { - auto Vlan = m_portList[vlan_member.second.alias]; - auto old_count = Vlan.m_up_member_count; - isUp ? Vlan.m_up_member_count++ : Vlan.m_up_member_count--; - if (Vlan.m_up_member_count == 0) - { - updateDbVlanOperStatus(Vlan, "down"); - } - else if ((old_count == 0) && (Vlan.m_up_member_count == 1)) - { - updateDbVlanOperStatus(Vlan, "up"); - } - SWSS_LOG_NOTICE("Vlan %s Port %s state %s m_up_member_count %d", - vlan_member.second.alias.c_str(), port.m_alias.c_str(), oper_status_strings.at(port.m_oper_status).c_str(), Vlan.m_up_member_count); - - m_portList[Vlan.m_alias] = Vlan; - } - if (!setHostIntfsOperStatus(port, isUp)) + if (port.m_type == Port::PHY) { if (!setHostIntfsOperStatus(port, isUp)) { @@ -4413,7 +4785,6 @@ void PortsOrch::updatePortOperStatus(Port &port, sai_port_oper_status_t status) { SWSS_LOG_WARN("Inform nexthop operation failed for interface %s", port.m_alias.c_str()); } - for (const auto &child_port : port.m_child_ports) { if (!gNeighOrch->ifChangeInformNextHop(child_port, isUp)) @@ -4421,46 +4792,6 @@ void PortsOrch::updatePortOperStatus(Port &port, sai_port_oper_status_t status) SWSS_LOG_WARN("Inform nexthop operation failed for sub interface %s", child_port.c_str()); } } - /* flush all dynamic FDB on this port */ - if (status == SAI_PORT_OPER_STATUS_DOWN) - { - gFdbOrch->flushFdbByPort(port.m_alias, 0); - } -} - -void PortsOrch::updateLagOperStatus(Port &port, sai_port_oper_status_t status) -{ - if (status == port.m_oper_status) - { - return ; - } - SWSS_LOG_NOTICE("Port %s oper state set from %s to %s", - port.m_alias.c_str(), oper_status_strings.at(port.m_oper_status).c_str(), - oper_status_strings.at(status).c_str()); - - port.m_oper_status = status; - m_portList[port.m_alias] = port; - - bool isUp = status == SAI_PORT_OPER_STATUS_UP; - - for(auto vlan_member: m_portVlanMember[port.m_alias]) - { - auto Vlan = m_portList[vlan_member.second.alias]; - auto old_count = Vlan.m_up_member_count; - isUp ? Vlan.m_up_member_count++ : Vlan.m_up_member_count--; - if (Vlan.m_up_member_count == 0) - { - updateDbVlanOperStatus(Vlan, "down"); - } - else if ((old_count == 0) && (Vlan.m_up_member_count == 1)) - { - updateDbVlanOperStatus(Vlan, "up"); - } - SWSS_LOG_NOTICE("Vlan %s Port %s state %s m_up_member_count %d", - vlan_member.second.alias.c_str(), port.m_alias.c_str(), oper_status_strings.at(port.m_oper_status).c_str(), Vlan.m_up_member_count); - - m_portList[Vlan.m_alias] = Vlan; - } PortOperStateUpdate update = {port, status}; notify(SUBJECT_TYPE_PORT_OPER_STATE_CHANGE, static_cast(&update)); @@ -4561,7 +4892,11 @@ bool PortsOrch::removeAclTableGroup(const Port &p) if (ret != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to remove ingress acl table group for %s", p.m_alias.c_str()); - return false; + task_process_status handle_status = handleSaiRemoveStatus(SAI_API_ACL, ret); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } gCrmOrch->decCrmAclUsedCounter(CrmResourceType::CRM_ACL_GROUP, SAI_ACL_STAGE_INGRESS, bind_type, p.m_ingress_acl_table_group_id); } @@ -4572,36 +4907,115 @@ bool PortsOrch::removeAclTableGroup(const Port &p) if (ret != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to remove egress acl table group for %s", p.m_alias.c_str()); - return false; + task_process_status handle_status = handleSaiRemoveStatus(SAI_API_ACL, ret); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } gCrmOrch->decCrmAclUsedCounter(CrmResourceType::CRM_ACL_GROUP, SAI_ACL_STAGE_EGRESS, bind_type, p.m_egress_acl_table_group_id); } return true; } -bool PortsOrch::setPortSerdesAttribute(sai_object_id_t port_id, sai_attr_id_t attr_id, - vector &serdes_val) +bool PortsOrch::setPortSerdesAttribute(sai_object_id_t port_id, + map> &serdes_attr) { SWSS_LOG_ENTER(); - sai_attribute_t attr; + vector attr_list; + sai_attribute_t port_attr; + sai_attribute_t port_serdes_attr; + sai_status_t status; + sai_object_id_t port_serdes_id = SAI_NULL_OBJECT_ID; - memset(&attr, 0, sizeof(attr)); - attr.id = attr_id; + port_attr.id = SAI_PORT_ATTR_PORT_SERDES_ID; + status = sai_port_api->get_port_attribute(port_id, 1, &port_attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to get port attr serdes id %d to port pid:0x%" PRIx64, + port_attr.id, port_id); + return false; + } - attr.value.u32list.count = (uint32_t)serdes_val.size(); - attr.value.u32list.list = serdes_val.data(); + if (port_attr.value.oid != SAI_NULL_OBJECT_ID) + { + status = sai_port_api->remove_port_serdes(port_attr.value.oid); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to remove existing port serdes attr 0x%" PRIx64 " port 0x%" PRIx64, + port_attr.value.oid, port_id); + task_process_status handle_status = handleSaiRemoveStatus(SAI_API_PORT, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } + } + } + + + port_serdes_attr.id = SAI_PORT_SERDES_ATTR_PORT_ID; + port_serdes_attr.value.oid = port_id; + attr_list.emplace_back(port_serdes_attr); + SWSS_LOG_INFO("Creating serdes for port 0x%" PRIx64, port_id); + + for (auto it = serdes_attr.begin(); it != serdes_attr.end(); it++) + { + port_serdes_attr.id = it->first; + port_serdes_attr.value.u32list.count = (uint32_t)it->second.size(); + port_serdes_attr.value.u32list.list = it->second.data(); + attr_list.emplace_back(port_serdes_attr); + } + status = sai_port_api->create_port_serdes(&port_serdes_id, gSwitchId, + static_cast(serdes_attr.size()+1), + attr_list.data()); - sai_status_t status = sai_port_api->set_port_attribute(port_id, &attr); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("Failed to set serdes attribute %d to port pid:%" PRIx64, - attr_id, port_id); - return false; + SWSS_LOG_ERROR("Failed to create port serdes for port 0x%" PRIx64, + port_id); + task_process_status handle_status = handleSaiCreateStatus(SAI_API_PORT, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } + SWSS_LOG_NOTICE("Created port serdes object 0x%" PRIx64 " for port 0x%" PRIx64, port_serdes_id, port_id); return true; } +void PortsOrch::removePortSerdesAttribute(sai_object_id_t port_id) +{ + SWSS_LOG_ENTER(); + + sai_attribute_t port_attr; + sai_status_t status; + sai_object_id_t port_serdes_id = SAI_NULL_OBJECT_ID; + + port_attr.id = SAI_PORT_ATTR_PORT_SERDES_ID; + status = sai_port_api->get_port_attribute(port_id, 1, &port_attr); + + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_DEBUG("Failed to get port attr serdes id %d to port pid:0x%" PRIx64, + port_attr.id, port_id); + return; + } + + if (port_attr.value.oid != SAI_NULL_OBJECT_ID) + { + status = sai_port_api->remove_port_serdes(port_attr.value.oid); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to remove existing port serdes attr 0x%" PRIx64 " port 0x%" PRIx64, + port_attr.value.oid, port_id); + handleSaiRemoveStatus(SAI_API_PORT, status); + return; + } + } + SWSS_LOG_NOTICE("Removed port serdes object 0x%" PRIx64 " for port 0x%" PRIx64, port_serdes_id, port_id); +} + void PortsOrch::getPortSerdesVal(const std::string& val_str, std::vector &lane_values) { @@ -4712,7 +5126,7 @@ bool PortsOrch::initGearboxPort(Port &port) { if (m_gearboxInterfaceMap.find(port.m_index) != m_gearboxInterfaceMap.end()) { - SWSS_LOG_NOTICE("BOX: port_id:0x%lx index:%d alias:%s", port.m_port_id, port.m_index, port.m_alias.c_str()); + SWSS_LOG_NOTICE("BOX: port_id:0x%" PRIx64 " index:%d alias:%s", port.m_port_id, port.m_index, port.m_alias.c_str()); phy_id = m_gearboxInterfaceMap[port.m_index].phy_id; phyOidStr = m_gearboxPhyMap[phy_id].phy_oid; @@ -4769,11 +5183,15 @@ bool PortsOrch::initGearboxPort(Port &port) status = sai_port_api->create_port(&systemPort, phyOid, static_cast(attrs.size()), attrs.data()); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("BOX: Failed to create Gearbox system-side port for alias:%s port_id:0x%lx index:%d status:%d", + SWSS_LOG_ERROR("BOX: Failed to create Gearbox system-side port for alias:%s port_id:0x%" PRIx64 " index:%d status:%d", port.m_alias.c_str(), port.m_port_id, port.m_index, status); - return false; + task_process_status handle_status = handleSaiCreateStatus(SAI_API_PORT, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } - SWSS_LOG_NOTICE("BOX: Created Gearbox system-side port 0x%lx for alias:%s index:%d", + SWSS_LOG_NOTICE("BOX: Created Gearbox system-side port 0x%" PRIx64 " for alias:%s index:%d", systemPort, port.m_alias.c_str(), port.m_index); /* Create LINE-SIDE port */ @@ -4852,11 +5270,15 @@ bool PortsOrch::initGearboxPort(Port &port) status = sai_port_api->create_port(&linePort, phyOid, static_cast(attrs.size()), attrs.data()); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("BOX: Failed to create Gearbox line-side port for alias:%s port_id:0x%lx index:%d status:%d", + SWSS_LOG_ERROR("BOX: Failed to create Gearbox line-side port for alias:%s port_id:0x%" PRIx64 " index:%d status:%d", port.m_alias.c_str(), port.m_port_id, port.m_index, status); - return false; + task_process_status handle_status = handleSaiCreateStatus(SAI_API_PORT, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } - SWSS_LOG_NOTICE("BOX: Created Gearbox line-side port 0x%lx for alias:%s index:%d", + SWSS_LOG_NOTICE("BOX: Created Gearbox line-side port 0x%" PRIx64 " for alias:%s index:%d", linePort, port.m_alias.c_str(), port.m_index); /* Connect SYSTEM-SIDE to LINE-SIDE */ @@ -4872,14 +5294,339 @@ bool PortsOrch::initGearboxPort(Port &port) status = sai_port_api->create_port_connector(&connector, phyOid, static_cast(attrs.size()), attrs.data()); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("BOX: Failed to connect Gearbox system-side:0x%lx to line-side:0x%lx; status:%d", systemPort, linePort, status); - return false; + SWSS_LOG_ERROR("BOX: Failed to connect Gearbox system-side:0x%" PRIx64 " to line-side:0x%" PRIx64 "; status:%d", systemPort, linePort, status); + task_process_status handle_status = handleSaiCreateStatus(SAI_API_PORT, status); + if (handle_status != task_success) + { + return parseHandleSaiStatusFailure(handle_status); + } } - SWSS_LOG_NOTICE("BOX: Connected Gearbox ports; system-side:0x%lx to line-side:0x%lx", systemPort, linePort); + SWSS_LOG_NOTICE("BOX: Connected Gearbox ports; system-side:0x%" PRIx64 " to line-side:0x%" PRIx64, systemPort, linePort); m_gearboxPortListLaneMap[port.m_port_id] = make_tuple(systemPort, linePort); } } return true; } + +bool PortsOrch::getSystemPorts() +{ + sai_status_t status; + sai_attribute_t attr; + uint32_t i; + + m_systemPortCount = 0; + + attr.id = SAI_SWITCH_ATTR_NUMBER_OF_SYSTEM_PORTS; + + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_INFO("Failed to get number of system ports, rv:%d", status); + return false; + } + + m_systemPortCount = attr.value.u32; + SWSS_LOG_NOTICE("Got %d system ports", m_systemPortCount); + + if(m_systemPortCount) + { + /* Make tuple and system port oid map */ + + vector system_port_list; + system_port_list.resize(m_systemPortCount); + + attr.id = SAI_SWITCH_ATTR_SYSTEM_PORT_LIST; + attr.value.objlist.count = (uint32_t)system_port_list.size(); + attr.value.objlist.list = system_port_list.data(); + + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to get system port list, rv:%d", status); + return false; + } + + uint32_t spcnt = attr.value.objlist.count; + for(i = 0; i < spcnt; i++) + { + attr.id = SAI_SYSTEM_PORT_ATTR_CONFIG_INFO; + + status = sai_system_port_api->get_system_port_attribute(system_port_list[i], 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to get system port config info spid:%" PRIx64, system_port_list[i]); + return false; + } + + SWSS_LOG_NOTICE("SystemPort(0x%" PRIx64 ") - port_id:%u, switch_id:%u, core:%u, core_port:%u, speed:%u, voqs:%u", + system_port_list[i], + attr.value.sysportconfig.port_id, + attr.value.sysportconfig.attached_switch_id, + attr.value.sysportconfig.attached_core_index, + attr.value.sysportconfig.attached_core_port_index, + attr.value.sysportconfig.speed, + attr.value.sysportconfig.num_voq); + + tuple sp_key(attr.value.sysportconfig.attached_switch_id, + attr.value.sysportconfig.attached_core_index, + attr.value.sysportconfig.attached_core_port_index); + + m_systemPortOidMap[sp_key] = system_port_list[i]; + } + } + + return true; +} + +bool PortsOrch::addSystemPorts() +{ + vector keys; + vector spFv; + + DBConnector appDb(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + Table appSystemPortTable(&appDb, APP_SYSTEM_PORT_TABLE_NAME); + + //Retrieve system port configurations from APP DB + appSystemPortTable.getKeys(keys); + for ( auto &alias : keys ) + { + appSystemPortTable.get(alias, spFv); + + int32_t system_port_id = -1; + int32_t switch_id = -1; + int32_t core_index = -1; + int32_t core_port_index = -1; + + for ( auto &fv : spFv ) + { + if(fv.first == "switch_id") + { + switch_id = stoi(fv.second); + continue; + } + if(fv.first == "core_index") + { + core_index = stoi(fv.second); + continue; + } + if(fv.first == "core_port_index") + { + core_port_index = stoi(fv.second); + continue; + } + if(fv.first == "system_port_id") + { + system_port_id = stoi(fv.second); + continue; + } + } + + if(system_port_id < 0 || switch_id < 0 || core_index < 0 || core_port_index < 0) + { + SWSS_LOG_ERROR("Invalid or Missing field values for %s! system_port id:%d, switch_id:%d, core_index:%d, core_port_index:%d", + alias.c_str(), system_port_id, switch_id, core_index, core_port_index); + continue; + } + + tuple sp_key(switch_id, core_index, core_port_index); + + if(m_systemPortOidMap.find(sp_key) != m_systemPortOidMap.end()) + { + + sai_attribute_t attr; + vector attrs; + sai_object_id_t system_port_oid; + sai_status_t status; + + //Retrive system port config info and enable + system_port_oid = m_systemPortOidMap[sp_key]; + + attr.id = SAI_SYSTEM_PORT_ATTR_TYPE; + attrs.push_back(attr); + + attr.id = SAI_SYSTEM_PORT_ATTR_CONFIG_INFO; + attrs.push_back(attr); + + status = sai_system_port_api->get_system_port_attribute(system_port_oid, static_cast(attrs.size()), attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to get system port config info spid:%" PRIx64, system_port_oid); + continue; + } + + //Create or update system port and add to the port list. + Port port(alias, Port::SYSTEM); + port.m_port_id = system_port_oid; + port.m_admin_state_up = true; + port.m_oper_status = SAI_PORT_OPER_STATUS_UP; + port.m_speed = attrs[1].value.sysportconfig.speed; + if (attrs[0].value.s32 == SAI_SYSTEM_PORT_TYPE_LOCAL) + { + //Get the local port oid + attr.id = SAI_SYSTEM_PORT_ATTR_PORT; + + status = sai_system_port_api->get_system_port_attribute(system_port_oid, 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to get local port oid of local system port spid:%" PRIx64, system_port_oid); + continue; + } + + //System port for local port. Update the system port info in the existing physical port + if(!getPort(attr.value.oid, port)) + { + //This is system port for non-front panel local port (CPU or OLP or RCY (Inband)). Not an error + SWSS_LOG_NOTICE("Add port for non-front panel local system port 0x%" PRIx64 "; core: %d, core port: %d", + system_port_oid, core_index, core_port_index); + } + port.m_system_port_info.local_port_oid = attr.value.oid; + } + + port.m_system_port_oid = system_port_oid; + + port.m_system_port_info.alias = alias; + port.m_system_port_info.type = (sai_system_port_type_t) attrs[0].value.s32; + port.m_system_port_info.port_id = attrs[1].value.sysportconfig.port_id; + port.m_system_port_info.switch_id = attrs[1].value.sysportconfig.attached_switch_id; + port.m_system_port_info.core_index = attrs[1].value.sysportconfig.attached_core_index; + port.m_system_port_info.core_port_index = attrs[1].value.sysportconfig.attached_core_port_index; + port.m_system_port_info.speed = attrs[1].value.sysportconfig.speed; + port.m_system_port_info.num_voq = attrs[1].value.sysportconfig.num_voq; + + setPort(port.m_alias, port); + if(m_port_ref_count.find(port.m_alias) == m_port_ref_count.end()) + { + m_port_ref_count[port.m_alias] = 0; + } + + SWSS_LOG_NOTICE("Added system port %" PRIx64 " for %s", system_port_oid, alias.c_str()); + } + else + { + //System port does not exist in the switch + //This can not happen since all the system ports are supposed to be created during switch creation itself + + SWSS_LOG_ERROR("System port %s does not exist in switch. Port not added!", alias.c_str()); + continue; + } + } + + return true; +} + +bool PortsOrch::getInbandPort(Port &port) +{ + if (m_portList.find(m_inbandPortName) == m_portList.end()) + { + return false; + } + else + { + port = m_portList[m_inbandPortName]; + return true; + } +} + +bool PortsOrch::isInbandPort(const string &alias) +{ + return (m_inbandPortName == alias); +} + +bool PortsOrch::setVoqInbandIntf(string &alias, string &type) +{ + if(m_inbandPortName == alias) + { + //Inband interface already exists with this name + SWSS_LOG_NOTICE("Interface %s is already configured as inband!", alias.c_str()); + return true; + } + + Port port; + if(type == "port") + { + if (!getPort(alias, port)) + { + SWSS_LOG_NOTICE("Port configured for inband intf %s is not ready!", alias.c_str()); + return false; + } + } + + // Check for existence of host interface. If does not exist, may create + // host if for the inband here + + // May do the processing for other inband type like type=vlan here + + //Store the name of the local inband port + m_inbandPortName = alias; + + return true; +} + +void PortsOrch::voqSyncAddLag (Port &lag) +{ + int32_t switch_id = lag.m_system_lag_info.switch_id; + + // Sync only local lag add to CHASSIS_APP_DB + + if (switch_id != gVoqMySwitchId) + { + return; + } + + uint32_t spa_id = lag.m_system_lag_info.spa_id; + + vector attrs; + + FieldValueTuple li ("lag_id", to_string(spa_id)); + attrs.push_back(li); + + FieldValueTuple si ("switch_id", to_string(switch_id)); + attrs.push_back(si); + + string key = lag.m_system_lag_info.alias; + + m_tableVoqSystemLagTable->set(key, attrs); +} + +void PortsOrch::voqSyncDelLag(Port &lag) +{ + // Sync only local lag del to CHASSIS_APP_DB + if (lag.m_system_lag_info.switch_id != gVoqMySwitchId) + { + return; + } + + string key = lag.m_system_lag_info.alias; + + m_tableVoqSystemLagTable->del(key); +} + +void PortsOrch::voqSyncAddLagMember(Port &lag, Port &port) +{ + // Sync only local lag's member add to CHASSIS_APP_DB + if (lag.m_system_lag_info.switch_id != gVoqMySwitchId) + { + return; + } + + vector attrs; + FieldValueTuple nullFv ("NULL", "NULL"); + attrs.push_back(nullFv); + + string key = lag.m_system_lag_info.alias + ":" + port.m_system_port_info.alias; + m_tableVoqSystemLagMemberTable->set(key, attrs); +} + +void PortsOrch::voqSyncDelLagMember(Port &lag, Port &port) +{ + // Sync only local lag's member del to CHASSIS_APP_DB + if (lag.m_system_lag_info.switch_id != gVoqMySwitchId) + { + return; + } + + string key = lag.m_system_lag_info.alias + ":" + port.m_system_port_info.alias; + m_tableVoqSystemLagMemberTable->del(key); +} diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index af2a5e1bbd..1725196287 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -9,10 +9,10 @@ #include "observer.h" #include "macaddress.h" #include "producertable.h" -#include "notificationproducer.h" #include "flex_counter_manager.h" #include "gearboxutils.h" #include "saihelper.h" +#include "lagid.h" #define FCS_LEN 4 @@ -23,7 +23,7 @@ #define QUEUE_STAT_COUNTER_FLEX_COUNTER_GROUP "QUEUE_STAT_COUNTER" #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" typedef std::vector PortSupportedSpeeds; @@ -74,7 +74,7 @@ struct VlanMemberUpdate class PortsOrch : public Orch, public Subject { public: - PortsOrch(DBConnector *db, vector &tableNames); + PortsOrch(DBConnector *db, vector &tableNames, DBConnector *chassisAppDb); bool allPortsReady(); bool isInitDone(); @@ -92,13 +92,15 @@ class PortsOrch : public Orch, public Subject void decreasePortRefCount(const string &alias); bool getPortByBridgePortId(sai_object_id_t bridge_port_id, Port &port); void setPort(string alias, Port port); - void erasePort(string alias); void getCpuPort(Port &port); + bool getInbandPort(Port &port); bool getVlanByVlanId(sai_vlan_id_t vlan_id, Port &vlan); bool setHostIntfsOperStatus(const Port& port, bool up) const; void updateDbPortOperStatus(const Port& port, sai_port_oper_status_t status) const; - void updateDbVlanOperStatus(const Port& port, string status) const; + + bool createVlanHostIntf(Port& vl, string hostif_name); + bool removeVlanHostIntf(Port vl); bool createBindAclTableGroup(sai_object_id_t port_oid, sai_object_id_t acl_table_oid, @@ -117,7 +119,7 @@ class PortsOrch : public Orch, public Subject acl_stage_type_t acl_stage); bool bindUnbindAclTableGroup(Port &port, bool ingress, - bool bind); + bool bind); bool getPortPfc(sai_object_id_t portId, uint8_t *pfc_bitmask); bool setPortPfc(sai_object_id_t portId, uint8_t pfc_bitmask); @@ -141,11 +143,14 @@ class PortsOrch : public Orch, public Subject bool removeVlanMember(Port &vlan, Port &port); bool isVlanMember(Port &vlan, Port &port); + string m_inbandPortName = ""; + bool isInbandPort(const string &alias); + bool setVoqInbandIntf(string &alias, string &type); + private: unique_ptr
m_counterTable; unique_ptr
m_counterLagTable; unique_ptr
m_portTable; - unique_ptr
m_vlanTable; unique_ptr
m_gearboxTable; unique_ptr
m_queueTable; unique_ptr
m_queuePortTable; @@ -154,16 +159,18 @@ class PortsOrch : public Orch, public Subject unique_ptr
m_pgTable; unique_ptr
m_pgPortTable; unique_ptr
m_pgIndexTable; + unique_ptr
m_stateBufferMaximumValueTable; unique_ptr m_flexCounterTable; unique_ptr m_flexCounterGroupTable; - unique_ptr notifications; std::string getQueueWatermarkFlexCounterTableKey(std::string s); std::string getPriorityGroupWatermarkFlexCounterTableKey(std::string s); + std::string getPriorityGroupDropPacketsFlexCounterTableKey(std::string s); std::string getPortRateFlexCounterTableKey(std::string s); shared_ptr m_counter_db; shared_ptr m_flex_db; + shared_ptr m_state_db; FlexCounterManager port_stat_manager; FlexCounterManager port_buffer_drop_stat_manager; @@ -175,8 +182,7 @@ class PortsOrch : public Orch, public Subject Port m_cpuPort; // TODO: Add Bridge/Vlan class sai_object_id_t m_default1QBridge; - sai_object_id_t m_defaultVlan_ObjId; - sai_vlan_id_t m_defaultVlan_Id; + sai_object_id_t m_defaultVlan; typedef enum { @@ -204,15 +210,6 @@ class PortsOrch : public Orch, public Subject map, sai_object_id_t> m_portListLaneMap; map, tuple> m_lanesAliasSpeedMap; map m_portList; - map m_portVlanMember; - - /* mapping from SAI object ID to Name for faster - retrieval of Port/VLAN from object ID for events - - coming from SAI - */ - unordered_map portOidToName; - unordered_map m_portOidToIndex; map m_port_ref_count; unordered_set m_pendingPortSet; @@ -236,6 +233,7 @@ class PortsOrch : public Orch, public Subject bool initializePort(Port &port); void initializePriorityGroups(Port &port); + void initializePortMaximumHeadroom(Port &port); void initializeQueues(Port &port); bool addHostIntfs(Port &port, string alias, sai_object_id_t &host_intfs_id); @@ -246,7 +244,7 @@ class PortsOrch : public Orch, public Subject bool addVlan(string vlan); bool removeVlan(Port vlan); - bool addLag(string lag); + bool addLag(string lag, uint32_t spa_id, int32_t switch_id); bool removeLag(Port lag); bool addLagMember(Port &lag, Port &port, bool enableForwarding); bool removeLagMember(Port &lag, Port &port); @@ -293,14 +291,29 @@ class PortsOrch : public Orch, public Subject void getPortSerdesVal(const std::string& s, std::vector &lane_values); - bool setPortSerdesAttribute(sai_object_id_t port_id, sai_attr_id_t attr_id, - vector &serdes_val); - void updateLagOperStatus(Port &port, sai_port_oper_status_t status); + bool setPortSerdesAttribute(sai_object_id_t port_id, + std::map> &serdes_attr); + + + void removePortSerdesAttribute(sai_object_id_t port_id); + bool getSaiAclBindPointType(Port::Type type, sai_acl_bind_point_type_t &sai_acl_bind_type); void initGearbox(); bool initGearboxPort(Port &port); + //map key is tuple of + map, sai_object_id_t> m_systemPortOidMap; + sai_uint32_t m_systemPortCount; + bool getSystemPorts(); + bool addSystemPorts(); + unique_ptr
m_tableVoqSystemLagTable; + unique_ptr
m_tableVoqSystemLagMemberTable; + void voqSyncAddLag(Port &lag); + void voqSyncDelLag(Port &lag); + void voqSyncAddLagMember(Port &lag, Port &port); + void voqSyncDelLagMember(Port &lag, Port &port); + unique_ptr m_lagIdAllocator; + }; #endif /* SWSS_PORTSORCH_H */ - From 936834c3b3db317bdf3cec7f44cb27c3e2a606c0 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Mon, 19 Apr 2021 20:56:30 -0700 Subject: [PATCH 16/54] fixed indentation --- orchagent/portsorch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index c3a0b145e7..b8198628a8 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -2056,7 +2056,7 @@ sai_status_t PortsOrch::removePort(sai_object_id_t port_id) Port port; - /* + /* * Make sure to bring down admin state. * SET would have replaced with DEL */ From 8d3b93251ee16f97bc0c70c50e72c8b53833026d Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Mon, 19 Apr 2021 20:56:53 -0700 Subject: [PATCH 17/54] fixed indentation. --- orchagent/portsorch.h | 1 + 1 file changed, 1 insertion(+) diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index 1725196287..a2d669c263 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -317,3 +317,4 @@ class PortsOrch : public Orch, public Subject }; #endif /* SWSS_PORTSORCH_H */ + From 26d5277e8a427094f361ea23be4ac29889c96ca6 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Mon, 19 Apr 2021 21:29:44 -0700 Subject: [PATCH 18/54] fixed re-declarations. --- orchagent/fdborch.h | 20 -------------------- orchagent/orchdaemon.cpp | 10 +++------- 2 files changed, 3 insertions(+), 27 deletions(-) diff --git a/orchagent/fdborch.h b/orchagent/fdborch.h index f639f4381a..c51feb3e46 100644 --- a/orchagent/fdborch.h +++ b/orchagent/fdborch.h @@ -64,26 +64,6 @@ struct FdbFlushUpdate Port port; }; -struct FdbData -{ - sai_object_id_t bridge_port_id; - string type; - FdbOrigin origin; - /** - {"dynamic", FDB_ORIGIN_LEARN} => dynamically learnt - {"dynamic", FDB_ORIGIN_PROVISIONED} => provisioned dynamic with swssconfig in APPDB - {"dynamic", FDB_ORIGIN_ADVERTIZED} => synced from remote device e.g. BGP MAC route - {"static", FDB_ORIGIN_LEARN} => Invalid - {"static", FDB_ORIGIN_PROVISIONED} => statically provisioned - {"static", FDB_ORIGIN_ADVERTIZED} => sticky synced from remote device - */ - - /* Remote FDB related info */ - string remote_ip; - string esi; - unsigned int vni; -}; - struct SavedFdbEntry { MacAddress mac; diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 41a1ea6ae9..d4f4c4c636 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -100,19 +100,15 @@ bool OrchDaemon::init() vector app_fdb_tables = { { APP_FDB_TABLE_NAME, FdbOrch::fdborch_pri}, - { APP_VXLAN_FDB_TABLE_NAME, FdbOrch::fdborch_pri} + { APP_VXLAN_FDB_TABLE_NAME, FdbOrch::fdborch_pri}, + { APP_MCLAG_FDB_TABLE_NAME, FdbOrch::fdborch_pri} }; gCrmOrch = new CrmOrch(m_configDb, CFG_CRM_TABLE_NAME); - gPortsOrch = new PortsOrch(m_applDb, ports_tables); + gPortsOrch = new PortsOrch(m_applDb, ports_tables, m_chassisAppDb); const int fdborch_pri = 20; - vector app_fdb_tables = { - { APP_FDB_TABLE_NAME, fdborch_pri}, - { APP_MCLAG_FDB_TABLE_NAME, fdborch_pri} - }; - TableConnector stateDbFdb(m_stateDb, STATE_FDB_TABLE_NAME); TableConnector stateMclagDbFdb(m_stateDb, STATE_MCLAG_REMOTE_FDB_TABLE_NAME); gFdbOrch = new FdbOrch(m_applDb, app_fdb_tables, stateDbFdb, stateMclagDbFdb, gPortsOrch); From b30825481e5878ec913d7fefcb37db64655c8c7c Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Mon, 19 Apr 2021 21:43:56 -0700 Subject: [PATCH 19/54] Removed unused variable. --- orchagent/orchdaemon.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index d4f4c4c636..d5563ab41e 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -107,8 +107,6 @@ bool OrchDaemon::init() gCrmOrch = new CrmOrch(m_configDb, CFG_CRM_TABLE_NAME); gPortsOrch = new PortsOrch(m_applDb, ports_tables, m_chassisAppDb); - const int fdborch_pri = 20; - TableConnector stateDbFdb(m_stateDb, STATE_FDB_TABLE_NAME); TableConnector stateMclagDbFdb(m_stateDb, STATE_MCLAG_REMOTE_FDB_TABLE_NAME); gFdbOrch = new FdbOrch(m_applDb, app_fdb_tables, stateDbFdb, stateMclagDbFdb, gPortsOrch); From ce9194f50bc1e47c3db68e465ba6ec69378ada11 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Mon, 19 Apr 2021 22:16:58 -0700 Subject: [PATCH 20/54] Fixed merge issues with master. --- orchagent/fdborch.cpp | 62 +++++++++++-------------------------------- orchagent/fdborch.h | 1 + 2 files changed, 16 insertions(+), 47 deletions(-) diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index e878c1241b..e18f301c9d 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -618,32 +618,6 @@ void FdbOrch::update(SubjectType type, void *cntx) return; } -void FdbOrch::update(SubjectType type, void *cntx) -{ - SWSS_LOG_ENTER(); - - assert(cntx); - - switch(type) { - case SUBJECT_TYPE_VLAN_MEMBER_CHANGE: - { - VlanMemberUpdate *update = reinterpret_cast(cntx); - updateVlanMember(*update); - break; - } - case SUBJECT_TYPE_PORT_OPER_STATE_CHANGE: - { - PortOperStateUpdate *update = reinterpret_cast(cntx); - updatePortOperState(*update); - break; - } - default: - break; - } - - return; -} - bool FdbOrch::getPort(const MacAddress& mac, uint16_t vlan, Port& port) { SWSS_LOG_ENTER(); @@ -1208,7 +1182,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, } else if ((oldOrigin == FDB_ORIGIN_LEARN) && (fdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED)) { - if ((port.m_bridge_port_id == it->second.bridge_port_id) && (oldType == "dynamic") && (type == "dynamic_local")) + if ((port.m_bridge_port_id == it->second.bridge_port_id) && (oldType == "dynamic") && (fdbData.type == "dynamic_local")) { SWSS_LOG_INFO("FdbOrch: mac=%s %s port=%s type=%s origin=%d old_origin=%d" " old_type=%s local mac exists," @@ -1361,7 +1335,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, FdbData storeFdbData = fdbData; storeFdbData.bridge_port_id = port.m_bridge_port_id; // overwrite the type and origin - if ((origin == FDB_ORIGIN_MCLAG_ADVERTIZED) && (type == "dynamic_local")) + if ((fdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) && (fdbData.type == "dynamic_local")) { //If the MAC is dynamic_local change the origin accordingly //MAC is added/updated as dynamic to allow aging. @@ -1373,28 +1347,22 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string(); - status = sai_fdb_api->create_fdb_entry(&fdb_entry, (uint32_t)attrs.size(), attrs.data()); - if (status != SAI_STATUS_SUCCESS) + status = sai_fdb_api->create_fdb_entry(&fdb_entry, (uint32_t)attrs.size(), attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to create %s FDB %s in %s on %s, rv:%d", + fdbData.type.c_str(), entry.mac.to_string().c_str(), + vlan.m_alias.c_str(), port_name.c_str(), status); + task_process_status handle_status = handleSaiCreateStatus(SAI_API_FDB, status); //FIXME: it should be based on status. Some could be retried, some not + if (handle_status != task_success) { - SWSS_LOG_ERROR("Failed to create %s FDB %s in %s on %s, rv:%d", - fdbData.type.c_str(), entry.mac.to_string().c_str(), - vlan.m_alias.c_str(), port_name.c_str(), status); - task_process_status handle_status = handleSaiCreateStatus(SAI_API_FDB, status); //FIXME: it should be based on status. Some could be retried, some not - if (handle_status != task_success) - { - return parseHandleSaiStatusFailure(handle_status); - } + return parseHandleSaiStatusFailure(handle_status); } - port.m_fdb_count++; - m_portsOrch->setPort(port.m_alias, port); - vlan.m_fdb_count++; - m_portsOrch->setPort(vlan.m_alias, vlan); } - - FdbData storeFdbData = fdbData; - storeFdbData.bridge_port_id = port.m_bridge_port_id; - - m_entries[entry] = storeFdbData; + port.m_fdb_count++; + m_portsOrch->setPort(port.m_alias, port); + vlan.m_fdb_count++; + m_portsOrch->setPort(vlan.m_alias, vlan); if ( (fdbData.type == "dynamic_local") || (fdbData.origin != FDB_ORIGIN_MCLAG_ADVERTIZED) || diff --git a/orchagent/fdborch.h b/orchagent/fdborch.h index c51feb3e46..408752e11c 100644 --- a/orchagent/fdborch.h +++ b/orchagent/fdborch.h @@ -107,6 +107,7 @@ class FdbOrch: public Orch, public Subject, public Observer fdb_entries_by_port_t saved_fdb_entries; vector m_appTables; Table m_fdbStateTable; + Table m_mclagFdbStateTable; NotificationConsumer* m_flushNotificationsConsumer; NotificationConsumer* m_fdbNotificationConsumer; From 7064b481018ce8445723a2f4030195e231e4387d Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Mon, 19 Apr 2021 23:13:34 -0700 Subject: [PATCH 21/54] Updated the missing key. --- orchagent/fdborch.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index e18f301c9d..b5c2dbd38a 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -800,6 +800,7 @@ void FdbOrch::doTask(Consumer& consumer) { if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED) { + string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string(); if (type == "dynamic_local") { m_mclagFdbStateTable.del(key); @@ -838,6 +839,7 @@ void FdbOrch::doTask(Consumer& consumer) { if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED) { + string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string(); m_mclagFdbStateTable.del(key); SWSS_LOG_NOTICE("fdbEvent: do Task Delete MCLAG FDB from state mclag remote fdb table: " "Mac: %s Vlan: %d ",entry.mac.to_string().c_str(), vlan.m_vlan_info.vlan_id ); @@ -1188,7 +1190,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, " old_type=%s local mac exists," " received dynamic_local from iccpd, ignore update", entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str(), - type.c_str(), fdbData.origin, oldOrigin, oldType.c_str()); + fdbData.type.c_str(), fdbData.origin, oldOrigin, oldType.c_str()); return true; } @@ -1398,14 +1400,14 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, SWSS_LOG_NOTICE("fdbEvent: AddFdbEntry: Add MCLAG MAC with state mclag remote fdb table " "Mac: %s Vlan: %d port:%s type:%s", entry.mac.to_string().c_str(), - vlan.m_vlan_info.vlan_id, port_name.c_str(), type.c_str()); + vlan.m_vlan_info.vlan_id, port_name.c_str(), fdbData.type.c_str()); } else if (macUpdate && (oldOrigin == FDB_ORIGIN_MCLAG_ADVERTIZED) && (fdbData.origin != FDB_ORIGIN_MCLAG_ADVERTIZED)) { SWSS_LOG_NOTICE("fdbEvent: AddFdbEntry: del MCLAG MAC from state MCLAG remote fdb table " "Mac: %s Vlan: %d port:%s type:%s", entry.mac.to_string().c_str(), - vlan.m_vlan_info.vlan_id, port_name.c_str(), type.c_str()); + vlan.m_vlan_info.vlan_id, port_name.c_str(), fdbData.type.c_str()); m_mclagFdbStateTable.del(key); } From 32fd3258febda1608d8352baea6f687135b40513 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Tue, 20 Apr 2021 00:23:10 -0700 Subject: [PATCH 22/54] Fix compilation error. --- orchagent/fdborch.cpp | 6 ++---- orchagent/observer.h | 46 +++++-------------------------------------- 2 files changed, 7 insertions(+), 45 deletions(-) diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index b5c2dbd38a..a233b5b950 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -1079,8 +1079,7 @@ void FdbOrch::updateVlanMember(const VlanMemberUpdate& update) } } -bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, - FdbData fdbData) +bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, FdbData fdbData) { Port vlan; Port port; @@ -1283,7 +1282,6 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, } } - if (macUpdate) { SWSS_LOG_INFO("MAC-Update FDB %s in %s on from-%s:to-%s from-%s:to-%s origin-%d-to-%d", @@ -1391,7 +1389,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, } //register with NeighborOrch for ICCP learned MAC addresses - if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED && (fdbData.type != "dynamic_local")) + if (fdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED && (fdbData.type != "dynamic_local")) { std::vector fvs; fvs.push_back(FieldValueTuple("port", port_name)); diff --git a/orchagent/observer.h b/orchagent/observer.h index 12744e497f..addcc9cc02 100644 --- a/orchagent/observer.h +++ b/orchagent/observer.h @@ -38,62 +38,26 @@ class Observer class Subject { public: - virtual void attach(SubjectType type, Observer *observer) - { - m_observers.emplace_back(type, observer); - } - virtual void attach(Observer *observer) { - attach(SUBJECT_TYPE_ALL_CHANGES, observer); - } - - virtual void detach(SubjectType type, Observer *observer) - { - pair temp(type, observer); - - auto it = find(m_observers.begin(), m_observers.end(), temp); - if (it != m_observers.end()) - { - m_observers.erase(it); - } + m_observers.push_back(observer); } virtual void detach(Observer *observer) { - detach(SUBJECT_TYPE_ALL_CHANGES, observer); - } - - virtual bool isObserver(SubjectType type, Observer *observer) - { - pair temp(type, observer); - - return m_observers.end() != find(m_observers.begin(), m_observers.end(), temp); - } - - virtual bool isObserver(Observer *observer) - { - return isObserver(SUBJECT_TYPE_ALL_CHANGES, observer); - } - - virtual bool hasObservers() - { - return m_observers.size() > 0; + m_observers.remove(observer); } virtual ~Subject() {} protected: - list> m_observers; + list m_observers; virtual void notify(SubjectType type, void *cntx) { - for (auto &iter: m_observers) + for (auto iter: m_observers) { - if ((iter.first == SUBJECT_TYPE_ALL_CHANGES) || (iter.first == type)) - { - iter.second->update(type, cntx); - } + iter->update(type, cntx); } } }; From 67024ee2758817d9e279c6d9fffc5d160823fb57 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Tue, 20 Apr 2021 08:21:17 -0700 Subject: [PATCH 23/54] Addressed review comments. --- fdbsyncd/fdbsync.cpp | 5 +++-- orchagent/fdborch.cpp | 8 ++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/fdbsyncd/fdbsync.cpp b/fdbsyncd/fdbsync.cpp index c80b171192..97103a38b4 100644 --- a/fdbsyncd/fdbsync.cpp +++ b/fdbsyncd/fdbsync.cpp @@ -435,14 +435,15 @@ void FdbSync::updateMclagRemoteMacPort(int ifindex, int vlan, std::string mac) if (type == FDB_TYPE_STATIC) { const std::string cmds = std::string("") - + " bridge fdb " + "replace" + " " + mac + " dev " - + port_name + " master " + "static" + " vlan " + to_string(vlan); + + " bridge fdb replace" + " " + mac + " dev " + + port_name + " master static vlan " + to_string(vlan); std::string res; int ret = swss::exec(cmds, res); if (ret != 0) { SWSS_LOG_NOTICE("Failed cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); + return; } SWSS_LOG_NOTICE("Update cmd:%s, res=%s, ret=%d", cmds.c_str(), res.c_str(), ret); diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index a233b5b950..53a6c2cdc5 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -301,7 +301,7 @@ void FdbOrch::update(sai_fdb_event_t type, } else { - SWSS_LOG_INFO("FdbOrch LEARN notification: mac %s is already in bv_id 0x%" + SWSS_LOG_INFO("FdbOrch LEARN notification: mac %s is already in bv_id 0x%" PRIx64 "existing-bp 0x%" PRIx64 "new-bp:0x%" PRIx64, update.entry.mac.to_string().c_str(), entry->bv_id, existing_entry->second.bridge_port_id, bridge_port_id); } @@ -770,11 +770,7 @@ void FdbOrch::doTask(Consumer& consumer) } } - /* FDB type is either dynamic or static */ - if (origin == FDB_ORIGIN_MCLAG_ADVERTIZED) - assert(type == "dynamic" || type == "dynamic_local" || type == "static" ); - else - assert(type == "dynamic" || type == "static"); + assert(type == "dynamic" || type == "dynamic_local" || type == "static" ); if(origin == FDB_ORIGIN_VXLAN_ADVERTIZED) { From 0aa6b21476e5975287a0da7d91acb5d75069eb49 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Tue, 20 Apr 2021 09:12:14 -0700 Subject: [PATCH 24/54] Addign observer support for mlagorch. --- orchagent/observer.h | 48 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/orchagent/observer.h b/orchagent/observer.h index addcc9cc02..93c87635f5 100644 --- a/orchagent/observer.h +++ b/orchagent/observer.h @@ -38,26 +38,64 @@ class Observer class Subject { public: + virtual void attach(SubjectType type, Observer *observer) + { + m_observers.emplace_back(type, observer); + } + virtual void attach(Observer *observer) { - m_observers.push_back(observer); + attach(SUBJECT_TYPE_ALL_CHANGES, observer); + } + + virtual void detach(SubjectType type, Observer *observer) + { + pair temp(type, observer); + + auto it = find(m_observers.begin(), m_observers.end(), temp); + if (it != m_observers.end()) + { + m_observers.erase(it); + } } virtual void detach(Observer *observer) { - m_observers.remove(observer); + detach(SUBJECT_TYPE_ALL_CHANGES, observer); + } + + virtual bool isObserver(SubjectType type, Observer *observer) + { + pair temp(type, observer); + + return m_observers.end() != find(m_observers.begin(), m_observers.end(), temp); + } + + virtual bool isObserver(Observer *observer) + { + return isObserver(SUBJECT_TYPE_ALL_CHANGES, observer); + } + + virtual bool hasObservers() + { + return m_observers.size() > 0; } virtual ~Subject() {} protected: - list m_observers; + list> m_observers; virtual void notify(SubjectType type, void *cntx) { - for (auto iter: m_observers) + for (auto iter = m_observers.begin(); iter != m_observers.end(); /* No-op */) { - iter->update(type, cntx); + auto nxt = next(iter); + if (((*iter).first == SUBJECT_TYPE_ALL_CHANGES) || ((*iter).first == type)) + { + (*iter).second->update(type, cntx); + } + iter = nxt; } } }; From d85e59d7deeab1fca83fd353a5c156ffe36fa950 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Tue, 20 Apr 2021 09:43:46 -0700 Subject: [PATCH 25/54] Fixing compilation due to casting issue with observer. --- orchagent/fdborch.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index 53a6c2cdc5..49e9a3ea8a 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -541,7 +541,7 @@ void FdbOrch::update(sai_fdb_event_t type, for (auto observer: m_observers) { - observer->update(SUBJECT_TYPE_FDB_CHANGE, &update); + observer->update(SUBJECT_TYPE_FDB_CHANGE, static_cast(&update)); } } } @@ -565,7 +565,7 @@ void FdbOrch::update(sai_fdb_event_t type, for (auto observer: m_observers) { - observer->update(SUBJECT_TYPE_FDB_CHANGE, &update); + observer->update(SUBJECT_TYPE_FDB_CHANGE, static_cast(&update)); } } itr = next_item; @@ -1007,7 +1007,7 @@ void FdbOrch::notifyObserversFDBFlush(Port &port, sai_object_id_t& bvid) { for (auto observer: m_observers) { - observer->update(SUBJECT_TYPE_FDB_FLUSH_CHANGE, &flushUpdate); + observer->update(SUBJECT_TYPE_FDB_FLUSH_CHANGE, static_cast(&flushUpdate)); } } } From 521b18c941fa30594d5a540951ee63933b6f0758 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Tue, 20 Apr 2021 10:17:42 -0700 Subject: [PATCH 26/54] Fix compilation issue. --- orchagent/fdborch.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index 49e9a3ea8a..ebdb138baf 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -539,7 +539,7 @@ void FdbOrch::update(sai_fdb_event_t type, storeFdbEntryState(update); - for (auto observer: m_observers) + for (auto &observer: m_observers) { observer->update(SUBJECT_TYPE_FDB_CHANGE, static_cast(&update)); } @@ -563,7 +563,7 @@ void FdbOrch::update(sai_fdb_event_t type, storeFdbEntryState(update); - for (auto observer: m_observers) + for (auto &observer: m_observers) { observer->update(SUBJECT_TYPE_FDB_CHANGE, static_cast(&update)); } @@ -1005,7 +1005,7 @@ void FdbOrch::notifyObserversFDBFlush(Port &port, sai_object_id_t& bvid) if (!flushUpdate.entries.empty()) { - for (auto observer: m_observers) + for (auto &observer: m_observers) { observer->update(SUBJECT_TYPE_FDB_FLUSH_CHANGE, static_cast(&flushUpdate)); } From 1fbd559f410bfcb4cdc1607ca2babe89b5118fb7 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Tue, 20 Apr 2021 10:56:07 -0700 Subject: [PATCH 27/54] Fixing the compilation issue. --- orchagent/fdborch.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index ebdb138baf..1d60d43b95 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -538,11 +538,12 @@ void FdbOrch::update(sai_fdb_event_t type, itr++; storeFdbEntryState(update); - +#if 0 //tbd_build for (auto &observer: m_observers) { observer->update(SUBJECT_TYPE_FDB_CHANGE, static_cast(&update)); } +#endif } } else if (entry->bv_id == SAI_NULL_OBJECT_ID) @@ -562,11 +563,12 @@ void FdbOrch::update(sai_fdb_event_t type, update.add = false; storeFdbEntryState(update); - +#if 0 //tbd_build for (auto &observer: m_observers) { observer->update(SUBJECT_TYPE_FDB_CHANGE, static_cast(&update)); } +#endif } itr = next_item; } @@ -1002,7 +1004,7 @@ void FdbOrch::notifyObserversFDBFlush(Port &port, sai_object_id_t& bvid) flushUpdate.entries.push_back(entry); } } - +#if 0 //tbd_build if (!flushUpdate.entries.empty()) { for (auto &observer: m_observers) @@ -1010,6 +1012,7 @@ void FdbOrch::notifyObserversFDBFlush(Port &port, sai_object_id_t& bvid) observer->update(SUBJECT_TYPE_FDB_FLUSH_CHANGE, static_cast(&flushUpdate)); } } +#endif } void FdbOrch::updatePortOperState(const PortOperStateUpdate& update) From 358482feef04dc6f793c39fd4d0ef4cd9cdc8523 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Wed, 21 Apr 2021 15:12:22 -0700 Subject: [PATCH 28/54] Resolving the auto merge duplicate code. --- tests/mock_tests/aclorch_ut.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/mock_tests/aclorch_ut.cpp b/tests/mock_tests/aclorch_ut.cpp index a3864fa710..a72e3ea455 100644 --- a/tests/mock_tests/aclorch_ut.cpp +++ b/tests/mock_tests/aclorch_ut.cpp @@ -330,11 +330,6 @@ namespace aclorch_test const int fdborch_pri = 20; - vector app_fdb_tables = { - { APP_FDB_TABLE_NAME, fdborch_pri}, - { APP_MCLAG_FDB_TABLE_NAME, fdborch_pri} - }; - vector app_fdb_tables = { { APP_FDB_TABLE_NAME, FdbOrch::fdborch_pri}, { APP_VXLAN_FDB_TABLE_NAME, FdbOrch::fdborch_pri}, From 7a7e3b841dd6a1774b81641c920c9dd1674d4f8e Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Wed, 21 Apr 2021 15:12:22 -0700 Subject: [PATCH 29/54] Resolving the auto merge duplicate code. --- orchagent/fdborch.cpp | 6 +++--- tests/mock_tests/aclorch_ut.cpp | 5 ----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index 1d60d43b95..1b4d34daaa 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -1211,7 +1211,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, FdbDat vector attrs; attr.id = SAI_FDB_ENTRY_ATTR_TYPE; - if (fdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED || fdbData.origin == FDB_ORIGIN_VXLAN_ADVERTIZED) + if ((fdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) || (fdbData.origin == FDB_ORIGIN_VXLAN_ADVERTIZED)) { if (fdbData.type == "dynamic_local") attr.value.s32 = SAI_FDB_ENTRY_TYPE_DYNAMIC; @@ -1225,8 +1225,8 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, FdbDat attrs.push_back(attr); - if ((fdbData.origin == FDB_ORIGIN_VXLAN_ADVERTIZED || fdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) - && (fdbData.type == "dynamic")) + if ((fdbData.origin == FDB_ORIGIN_VXLAN_ADVERTIZED) || (fdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + || (fdbData.type == "dynamic")) { attr.id = SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE; attr.value.booldata = true; diff --git a/tests/mock_tests/aclorch_ut.cpp b/tests/mock_tests/aclorch_ut.cpp index a3864fa710..a72e3ea455 100644 --- a/tests/mock_tests/aclorch_ut.cpp +++ b/tests/mock_tests/aclorch_ut.cpp @@ -330,11 +330,6 @@ namespace aclorch_test const int fdborch_pri = 20; - vector app_fdb_tables = { - { APP_FDB_TABLE_NAME, fdborch_pri}, - { APP_MCLAG_FDB_TABLE_NAME, fdborch_pri} - }; - vector app_fdb_tables = { { APP_FDB_TABLE_NAME, FdbOrch::fdborch_pri}, { APP_VXLAN_FDB_TABLE_NAME, FdbOrch::fdborch_pri}, From b007eef5631d5b3b9c1b3080e62f200ea5c88b18 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Fri, 30 Apr 2021 16:51:08 -0700 Subject: [PATCH 30/54] Fixed FDB notifiation issue --- orchagent/fdborch.cpp | 53 ++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index 1b4d34daaa..f8a6abef71 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -169,8 +169,8 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) m_mclagFdbStateTable.del(key); } - if ((oldFdbData.origin != FDB_ORIGIN_VXLAN_ADVERTIZED) && - (oldFdbData.origin != FDB_ORIGIN_MCLAG_ADVERTIZED)) + if ((oldFdbData.origin == FDB_ORIGIN_LEARN) || + (oldFdbData.origin == FDB_ORIGIN_PROVISIONED)) { // Remove in StateDb for non advertised mac addresses m_fdbStateTable.del(key); @@ -538,12 +538,9 @@ void FdbOrch::update(sai_fdb_event_t type, itr++; storeFdbEntryState(update); -#if 0 //tbd_build - for (auto &observer: m_observers) - { - observer->update(SUBJECT_TYPE_FDB_CHANGE, static_cast(&update)); - } -#endif + + notify(SUBJECT_TYPE_FDB_CHANGE, &update); + } } else if (entry->bv_id == SAI_NULL_OBJECT_ID) @@ -563,12 +560,7 @@ void FdbOrch::update(sai_fdb_event_t type, update.add = false; storeFdbEntryState(update); -#if 0 //tbd_build - for (auto &observer: m_observers) - { - observer->update(SUBJECT_TYPE_FDB_CHANGE, static_cast(&update)); - } -#endif + notify(SUBJECT_TYPE_FDB_CHANGE, &update); } itr = next_item; } @@ -1004,15 +996,11 @@ void FdbOrch::notifyObserversFDBFlush(Port &port, sai_object_id_t& bvid) flushUpdate.entries.push_back(entry); } } -#if 0 //tbd_build + if (!flushUpdate.entries.empty()) { - for (auto &observer: m_observers) - { - observer->update(SUBJECT_TYPE_FDB_FLUSH_CHANGE, static_cast(&flushUpdate)); - } + notify(SUBJECT_TYPE_FDB_CHANGE, &flushUpdate); } -#endif } void FdbOrch::updatePortOperState(const PortOperStateUpdate& update) @@ -1078,7 +1066,8 @@ void FdbOrch::updateVlanMember(const VlanMemberUpdate& update) } } -bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, FdbData fdbData) +bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, + FdbData fdbData) { Port vlan; Port port; @@ -1122,6 +1111,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, FdbDat string oldType; FdbOrigin oldOrigin = FDB_ORIGIN_INVALID ; bool macUpdate = false; + auto it = m_entries.find(entry); if (it != m_entries.end()) { @@ -1193,6 +1183,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, FdbDat return true; } } + } else /* (fdbData.origin == oldOrigin) */ { @@ -1211,12 +1202,13 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, FdbDat vector attrs; attr.id = SAI_FDB_ENTRY_ATTR_TYPE; - if ((fdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) || (fdbData.origin == FDB_ORIGIN_VXLAN_ADVERTIZED)) + if (fdbData.origin == FDB_ORIGIN_VXLAN_ADVERTIZED) { - if (fdbData.type == "dynamic_local") - attr.value.s32 = SAI_FDB_ENTRY_TYPE_DYNAMIC; - else - attr.value.s32 = SAI_FDB_ENTRY_TYPE_STATIC; + attr.value.s32 = SAI_FDB_ENTRY_TYPE_STATIC; + } + else if (fdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) + { + attr.value.s32 = (fdbData.type == "dynamic_local") ? SAI_FDB_ENTRY_TYPE_DYNAMIC : SAI_FDB_ENTRY_TYPE_STATIC; } else { @@ -1363,9 +1355,8 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, FdbDat vlan.m_fdb_count++; m_portsOrch->setPort(vlan.m_alias, vlan); - if ( (fdbData.type == "dynamic_local") || - (fdbData.origin != FDB_ORIGIN_MCLAG_ADVERTIZED) || - (fdbData.origin != FDB_ORIGIN_VXLAN_ADVERTIZED)) + if ((fdbData.origin != FDB_ORIGIN_MCLAG_ADVERTIZED) || + (fdbData.origin != FDB_ORIGIN_VXLAN_ADVERTIZED)) { /* State-DB is updated only for Local Mac addresses */ // Write to StateDb @@ -1377,6 +1368,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, FdbDat fvs.push_back(FieldValueTuple("type", fdbData.type)); m_fdbStateTable.set(key, fvs); } + else if (macUpdate && (oldOrigin != FDB_ORIGIN_MCLAG_ADVERTIZED) && (oldOrigin != FDB_ORIGIN_VXLAN_ADVERTIZED)) { @@ -1387,8 +1379,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, FdbDat m_fdbStateTable.del(key); } - //register with NeighborOrch for ICCP learned MAC addresses - if (fdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED && (fdbData.type != "dynamic_local")) + if ((fdbData.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) && (fdbData.type != "dynamic_local")) { std::vector fvs; fvs.push_back(FieldValueTuple("port", port_name)); From 29d2e0057e78550456d544d12d2920dba6670462 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Sat, 1 May 2021 10:21:09 -0700 Subject: [PATCH 31/54] Fixing ARM build issue. --- orchagent/fdborch.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index f8a6abef71..d0fe17557b 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -241,11 +241,11 @@ void FdbOrch::update(sai_fdb_event_t type, if (existing_entry->second.bridge_port_id != bridge_port_id) { Port port; - SWSS_LOG_NOTICE("FdbOrch LEARN notification: mac %s is already in bv_id 0x%lx with different existing-bp 0x%lx new-bp:0x%lx", - update.entry.mac.to_string().c_str(), entry->bv_id, existing_entry->second.bridge_port_id, bridge_port_id); + SWSS_LOG_NOTICE("FdbOrch LEARN notification: mac %s is already in bv_id 0x%" PRIx64 "with different existing-bp 0x%" PRIx64 " new-bp:0x%" PRIx64, + update.entry.mac.to_string().c_str(), entry->bv_id, existing_entry->second.bridge_port_id, bridge_port_id); if (!m_portsOrch->getPortByBridgePortId(existing_entry->second.bridge_port_id, port)) { - SWSS_LOG_NOTICE("FdbOrch LEARN notification: Failed to get port by bridge port ID 0x%lx", existing_entry->second.bridge_port_id); + SWSS_LOG_NOTICE("FdbOrch LEARN notification: Failed to get port by bridge port ID 0x%" PRIx64, existing_entry->second.bridge_port_id); return; } else @@ -260,7 +260,7 @@ void FdbOrch::update(sai_fdb_event_t type, } else { - SWSS_LOG_NOTICE("FdbOrch LEARN notification: mac %s is already in bv_id 0x%lx with same bp 0x%lx ", + SWSS_LOG_NOTICE("FdbOrch LEARN notification: mac %s is already in bv_id 0x%" PRIx64 "with same bp 0x%" PRIx64, update.entry.mac.to_string().c_str(), entry->bv_id, existing_entry->second.bridge_port_id); // Continue to move the MAC as local. @@ -287,7 +287,7 @@ void FdbOrch::update(sai_fdb_event_t type, status = sai_fdb_api->set_fdb_entry_attribute(&fdb_entry, &itr); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("macUpdate-Failed for MCLAG mac attr.id=0x%x for FDB %s in 0x%lx on %s, rv:%d", + SWSS_LOG_ERROR("macUpdate-Failed for MCLAG mac attr.id=0x%x for FDB %s in 0x%" PRIx64 "on %s, rv:%d", itr.id, update.entry.mac.to_string().c_str(), entry->bv_id, update.port.m_alias.c_str(), status); } } From 44e430ec70fbcc38c0996cad4ae1ae858618d00c Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Sat, 1 May 2021 14:29:12 -0700 Subject: [PATCH 32/54] Fixed ARM build errors. --- orchagent/isolationgrouporch.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/orchagent/isolationgrouporch.cpp b/orchagent/isolationgrouporch.cpp index 5279fd5c5e..9781b1e03a 100644 --- a/orchagent/isolationgrouporch.cpp +++ b/orchagent/isolationgrouporch.cpp @@ -272,7 +272,7 @@ IsolationGroup::create() } else { - SWSS_LOG_NOTICE("Isolation group %s has oid %lx", m_name.c_str(), m_oid); + SWSS_LOG_NOTICE("Isolation group %s has oid 0x%" PRIx64 , m_name.c_str(), m_oid); } return ISO_GRP_STATUS_SUCCESS; @@ -325,7 +325,7 @@ IsolationGroup::destroy() { if (SAI_STATUS_SUCCESS != sai_isolation_group_api->remove_isolation_group_member(kv.second)) { - SWSS_LOG_ERROR("Unable to delete isolation group member %lx from %s:%lx for port %s", + SWSS_LOG_ERROR("Unable to delete isolation group member 0x%" PRIx64 " from %s: 0x%" PRIx64 " for port %s", kv.second, m_name.c_str(), m_oid, @@ -333,7 +333,7 @@ IsolationGroup::destroy() } else { - SWSS_LOG_NOTICE("Isolation group member %lx deleted from %s:%lx for port %s", + SWSS_LOG_NOTICE("Isolation group member 0x%" PRIx64 " deleted from %s: 0x%" PRIx64 " for port %s", kv.second, m_name.c_str(), m_oid, @@ -345,11 +345,11 @@ IsolationGroup::destroy() sai_status_t status = sai_isolation_group_api->remove_isolation_group(m_oid); if (SAI_STATUS_SUCCESS != status) { - SWSS_LOG_ERROR("Unable to delete isolation group %s with oid %lx", m_name.c_str(), m_oid); + SWSS_LOG_ERROR("Unable to delete isolation group %s with oid 0x%" PRIx64 , m_name.c_str(), m_oid); } else { - SWSS_LOG_NOTICE("Isolation group %s with oid %lx deleted", m_name.c_str(), m_oid); + SWSS_LOG_NOTICE("Isolation group %s with oid 0x%" PRIx64 " deleted", m_name.c_str(), m_oid); } m_oid = SAI_NULL_OBJECT_ID; @@ -385,7 +385,7 @@ IsolationGroup::addMember(Port &port) if (m_members.find(port.m_alias) != m_members.end()) { - SWSS_LOG_DEBUG("Port %s:%lx already a member of %s", port.m_alias.c_str(), port_id, m_name.c_str()); + SWSS_LOG_DEBUG("Port %s: 0x%" PRIx64 "already a member of %s", port.m_alias.c_str(), port_id, m_name.c_str()); } else { @@ -401,14 +401,14 @@ IsolationGroup::addMember(Port &port) status = sai_isolation_group_api->create_isolation_group_member(&mem_id, gSwitchId, 2, mem_attr); if (SAI_STATUS_SUCCESS != status) { - SWSS_LOG_ERROR("Unable to add %s:%lx as member of %s:%lx", port.m_alias.c_str(), port_id, + SWSS_LOG_ERROR("Unable to add %s: 0x%" PRIx64 " as member of %s:0x%" PRIx64 , port.m_alias.c_str(), port_id, m_name.c_str(), m_oid); return ISO_GRP_STATUS_FAIL; } else { m_members[port.m_alias] = mem_id; - SWSS_LOG_NOTICE("Port %s:%lx added as member of %s:%lx with oid %lx", + SWSS_LOG_NOTICE("Port %s: 0x%" PRIx64 " added as member of %s: 0x%" PRIx64 "with oid 0x%" PRIx64, port.m_alias.c_str(), port_id, m_name.c_str(), @@ -442,7 +442,7 @@ IsolationGroup::delMember(Port &port, bool do_fwd_ref) status = sai_isolation_group_api->remove_isolation_group_member(mem_id); if (SAI_STATUS_SUCCESS != status) { - SWSS_LOG_ERROR("Unable to delete isolation group member %lx for port %s and iso group %s %lx", + SWSS_LOG_ERROR("Unable to delete isolation group member 0x%" PRIx64 " for port %s and iso group %s 0x%" PRIx64 , mem_id, port.m_alias.c_str(), m_name.c_str(), @@ -452,7 +452,7 @@ IsolationGroup::delMember(Port &port, bool do_fwd_ref) } else { - SWSS_LOG_NOTICE("Deleted isolation group member %lx for port %s and iso group %s %lx", + SWSS_LOG_NOTICE("Deleted isolation group member 0x%" PRIx64 "for port %s and iso group %s 0x%" PRIx64 , mem_id, port.m_alias.c_str(), m_name.c_str(), @@ -555,7 +555,7 @@ IsolationGroup::bind(Port &port) status = sai_bridge_api->set_bridge_port_attribute(port.m_bridge_port_id, &attr); if (SAI_STATUS_SUCCESS != status) { - SWSS_LOG_ERROR("Unable to set attribute %d value %lx to %s", + SWSS_LOG_ERROR("Unable to set attribute %d value 0x%" PRIx64 "to %s", attr.id, attr.value.oid, port.m_alias.c_str()); @@ -582,7 +582,7 @@ IsolationGroup::bind(Port &port) status = sai_port_api->set_port_attribute((port.m_type == Port::PHY ? port.m_port_id : port.m_lag_id), &attr); if (SAI_STATUS_SUCCESS != status) { - SWSS_LOG_ERROR("Unable to set attribute %d value %lx to %s", + SWSS_LOG_ERROR("Unable to set attribute %d value 0x%" PRIx64 "to %s", attr.id, attr.value.oid, port.m_alias.c_str()); @@ -645,7 +645,7 @@ IsolationGroup::unbind(Port &port, bool do_fwd_ref) if (SAI_STATUS_SUCCESS != status) { - SWSS_LOG_ERROR("Unable to set attribute %d value %lx to %s", attr.id, attr.value.oid, port.m_alias.c_str()); + SWSS_LOG_ERROR("Unable to set attribute %d value 0x%" PRIx64 "to %s", attr.id, attr.value.oid, port.m_alias.c_str()); } else { From f1fb39bfe3046b4d3c858e9777d9a74c89c3a29c Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Sat, 1 May 2021 18:59:24 -0700 Subject: [PATCH 33/54] Fixing Mlagorch ARM build failures. --- orchagent/mlagorch.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/orchagent/mlagorch.cpp b/orchagent/mlagorch.cpp index e4b42324ec..6a6ba8de34 100644 --- a/orchagent/mlagorch.cpp +++ b/orchagent/mlagorch.cpp @@ -300,7 +300,7 @@ bool MlagOrch::addIslIsolationGroup() //Need peer link and at least one MLAG interface to create an isolation group if (m_isl_name.empty() || (m_mlagIntfs.size() == 0)) { - SWSS_LOG_NOTICE("MLAG skips adding isolation group: isl name(%s), num MLAG interface %lu", + SWSS_LOG_NOTICE("MLAG skips adding isolation group: isl name(%s), num MLAG interface %zu", m_isl_name.empty() ? "invalid" : m_isl_name.c_str(), m_mlagIntfs.size()); return false; } @@ -366,7 +366,7 @@ bool MlagOrch::deleteIslIsolationGroup() //Delete isolation group if either peer link or all MLAG interfaces are removed if (!m_isl_name.empty() && (m_mlagIntfs.size() > 0)) { - SWSS_LOG_NOTICE("MLAG skips deleting isolation group: isl name %s, num MLAG interface %lu", + SWSS_LOG_NOTICE("MLAG skips deleting isolation group: isl name %s, num MLAG interface %zu", m_isl_name.c_str(), m_mlagIntfs.size()); return false; } @@ -479,7 +479,7 @@ bool MlagOrch::addAllMlagInterfacesToIsolationGroup() //Need peer link and at least one MLAG interface to create an isolation group if (m_isl_name.empty() || (m_mlagIntfs.size() == 0)) { - SWSS_LOG_NOTICE("MLAG skips adding mlag-if to isolation group: isl name(%s), mlag-if count %lu", + SWSS_LOG_NOTICE("MLAG skips adding mlag-if to isolation group: isl name(%s), mlag-if count %zu", m_isl_name.empty() ? "invalid" : m_isl_name.c_str(), m_mlagIntfs.size()); return false; } From 0a652da36f9b5f481f7422b463efeb566975c859 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Sun, 2 May 2021 18:02:19 -0700 Subject: [PATCH 34/54] Fixing the test_mclag_fdb type attributes. --- tests/test_mclag_fdb.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/test_mclag_fdb.py b/tests/test_mclag_fdb.py index 7de7ab632f..08ce3b1c3a 100644 --- a/tests/test_mclag_fdb.py +++ b/tests/test_mclag_fdb.py @@ -138,7 +138,8 @@ def test_mclagFdb_remote_dynamic_mac_add(dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], - [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC_MACMOVE"), + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0005")))] ) @@ -223,7 +224,8 @@ def test_mclagFdb_remote_to_local_mac_move(dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], - [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC_MACMOVE"), + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0005")))] ) @@ -327,7 +329,8 @@ def test_mclagFdb_local_to_remote_move(dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], - [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC_MACMOVE"), + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0005")))] ) @@ -350,7 +353,8 @@ def test_mclagFdb_remote_move_del(dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], - [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC_MACMOVE"), + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0005")))] ) @@ -389,7 +393,8 @@ def test_mclagFdb_remote_move_peer_node(dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], - [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC_MACMOVE"), + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0005")))] ) @@ -410,7 +415,8 @@ def test_mclagFdb_remote_move_peer_node(dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], - [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC_MACMOVE"), + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0006")))] ) From a88f71fbe41469c046b611cd2f844b08d8c96c64 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Mon, 5 Jul 2021 10:45:55 -0700 Subject: [PATCH 35/54] Addressing the review comments. --- fdbsyncd/fdbsyncd.cpp | 2 +- orchagent/fdborch.cpp | 58 ++++++++++++-------------------- orchagent/isolationgrouporch.cpp | 7 +++- orchagent/isolationgrouporch.h | 2 +- 4 files changed, 30 insertions(+), 39 deletions(-) diff --git a/fdbsyncd/fdbsyncd.cpp b/fdbsyncd/fdbsyncd.cpp index 99492df184..36bd042a94 100644 --- a/fdbsyncd/fdbsyncd.cpp +++ b/fdbsyncd/fdbsyncd.cpp @@ -101,7 +101,7 @@ int main(int argc, char **argv) } catch (const std::exception& e) { - cout << "Exception \"" << e.what() << "\" had been thrown in deamon" << endl; + cout << "Exception \"" << e.what() << "\" had been thrown in daemon" << endl; return 0; } } diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index 8ecf6f76ec..80514142d2 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -99,12 +99,7 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) */ if (port.m_bridge_port_id == it->second.bridge_port_id) { - if (it->second.origin == FDB_ORIGIN_MCLAG_ADVERTIZED) - { - mac_move=true; - oldFdbData = it->second; - } - else + if (it->second.origin != FDB_ORIGIN_MCLAG_ADVERTIZED) { SWSS_LOG_INFO("FdbOrch notification: mac %s is duplicate", entry.mac.to_string().c_str()); return false; @@ -243,19 +238,18 @@ void FdbOrch::update(sai_fdb_event_t type, Port port; SWSS_LOG_NOTICE("FdbOrch LEARN notification: mac %s is already in bv_id 0x%" PRIx64 "with different existing-bp 0x%" PRIx64 " new-bp:0x%" PRIx64, update.entry.mac.to_string().c_str(), entry->bv_id, existing_entry->second.bridge_port_id, bridge_port_id); - if (!m_portsOrch->getPortByBridgePortId(existing_entry->second.bridge_port_id, port)) - { - SWSS_LOG_NOTICE("FdbOrch LEARN notification: Failed to get port by bridge port ID 0x%" PRIx64, existing_entry->second.bridge_port_id); - return; - } - else - { - port.m_fdb_count--; - m_portsOrch->setPort(port.m_alias, port); - vlan.m_fdb_count--; - m_portsOrch->setPort(vlan.m_alias, vlan); - } - + if (!m_portsOrch->getPortByBridgePortId(existing_entry->second.bridge_port_id, port)) + { + SWSS_LOG_NOTICE("FdbOrch LEARN notification: Failed to get port by bridge port ID 0x%" PRIx64, existing_entry->second.bridge_port_id); + return; + } + else + { + port.m_fdb_count--; + m_portsOrch->setPort(port.m_alias, port); + vlan.m_fdb_count--; + m_portsOrch->setPort(vlan.m_alias, vlan); + } // Continue to add (update/move) the MAC } else @@ -797,27 +791,19 @@ void FdbOrch::doTask(Consumer& consumer) } } - if(origin == FDB_ORIGIN_VXLAN_ADVERTIZED) - { - VxlanTunnelOrch* tunnel_orch = gDirectory.get(); - - if(!remote_ip.length()) + if(origin == FDB_ORIGIN_VXLAN_ADVERTIZED) { - it = consumer.m_toSync.erase(it); - continue; + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); + + if(!remote_ip.length()) + { + it = consumer.m_toSync.erase(it); + continue; + } + port = tunnel_orch->getTunnelPortName(remote_ip); } - port = tunnel_orch->getTunnelPortName(remote_ip); - } - FdbData fdbData; - fdbData.bridge_port_id = SAI_NULL_OBJECT_ID; - fdbData.type = type; - fdbData.origin = origin; - fdbData.remote_ip = remote_ip; - fdbData.esi = esi; - fdbData.vni = vni; - if (addFdbEntry(entry, port, fdbData)) it = consumer.m_toSync.erase(it); } else diff --git a/orchagent/isolationgrouporch.cpp b/orchagent/isolationgrouporch.cpp index 9781b1e03a..b4a0e9e249 100644 --- a/orchagent/isolationgrouporch.cpp +++ b/orchagent/isolationgrouporch.cpp @@ -119,6 +119,8 @@ IsoGrpOrch::doIsoGrpTblTask(Consumer &consumer) { type = ISOLATION_GROUP_TYPE_BRIDGE_PORT; } + else + SWSS_LOG_WARN("Attr:%s unknown type:%s", attr_name.c_str(), type.c_str()); } else if (attr_name == ISOLATION_GRP_PORTS) { @@ -128,6 +130,8 @@ IsoGrpOrch::doIsoGrpTblTask(Consumer &consumer) { mem_ports = attr_value; } + else + SWSS_LOG_WARN("unknown Attr:%s ", attr_name.c_str()); } status = addIsolationGroup(name, type, descr, bind_ports, mem_ports); @@ -193,7 +197,7 @@ IsoGrpOrch::addIsolationGroup(string name, isolation_group_type_t type, string d grp->setBindPorts(bindPorts); this->m_isolationGrps[name] = grp; } - else if ((grp) && (grp->getType() == type)) + else if (grp->getType() == type) { grp->m_description = descr; grp->setMembers(memPorts); @@ -603,6 +607,7 @@ IsolationGroup::bind(Port &port) } else { + SWSS_LOG_ERROR("Invalid attribute type %d ", m_type); return ISO_GRP_STATUS_INVALID_PARAM; } diff --git a/orchagent/isolationgrouporch.h b/orchagent/isolationgrouporch.h index b8152cf96c..7bf8ef4c14 100644 --- a/orchagent/isolationgrouporch.h +++ b/orchagent/isolationgrouporch.h @@ -42,7 +42,7 @@ typedef enum IsolationGroupStatus ISO_GRP_STATUS_FAIL, ISO_GRP_STATUS_INVALID_PARAM, ISO_GRP_STATUS_SUCCESS = 0 -}isolation_group_status_t; +} isolation_group_status_t; class IsolationGroup: public Observer, public Subject { From c3331793c8a05266bfee2e7898c5363d8ba07fea Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Mon, 5 Jul 2021 15:54:39 -0700 Subject: [PATCH 36/54] Fix Build error. --- orchagent/isolationgrouporch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orchagent/isolationgrouporch.cpp b/orchagent/isolationgrouporch.cpp index b4a0e9e249..3dc881259a 100644 --- a/orchagent/isolationgrouporch.cpp +++ b/orchagent/isolationgrouporch.cpp @@ -120,7 +120,7 @@ IsoGrpOrch::doIsoGrpTblTask(Consumer &consumer) type = ISOLATION_GROUP_TYPE_BRIDGE_PORT; } else - SWSS_LOG_WARN("Attr:%s unknown type:%s", attr_name.c_str(), type.c_str()); + SWSS_LOG_WARN("Attr:%s unknown type:%d", attr_name.c_str(), type); } else if (attr_name == ISOLATION_GRP_PORTS) { From 5ec2686c69b4ef23d4c55892fb306d185c24ae9e Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Tue, 6 Jul 2021 16:06:38 -0700 Subject: [PATCH 37/54] Addressed review comments. --- orchagent/isolationgrouporch.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/orchagent/isolationgrouporch.cpp b/orchagent/isolationgrouporch.cpp index 3dc881259a..0d73d3010e 100644 --- a/orchagent/isolationgrouporch.cpp +++ b/orchagent/isolationgrouporch.cpp @@ -578,12 +578,12 @@ IsolationGroup::bind(Port &port) m_type); } } - else if (m_type == ISOLATION_GROUP_TYPE_PORT) + else if ((m_type == ISOLATION_GROUP_TYPE_PORT) && (port.m_type == Port::PHY)) { - if ((port.m_type == Port::PHY ? port.m_port_id : port.m_lag_id) != SAI_NULL_OBJECT_ID) + if (port.m_port_id != SAI_NULL_OBJECT_ID) { attr.id = SAI_PORT_ATTR_ISOLATION_GROUP; - status = sai_port_api->set_port_attribute((port.m_type == Port::PHY ? port.m_port_id : port.m_lag_id), &attr); + status = sai_port_api->set_port_attribute(port.m_port_id, &attr); if (SAI_STATUS_SUCCESS != status) { SWSS_LOG_ERROR("Unable to set attribute %d value 0x%" PRIx64 "to %s", @@ -638,7 +638,7 @@ IsolationGroup::unbind(Port &port, bool do_fwd_ref) attr.id = SAI_BRIDGE_PORT_ATTR_ISOLATION_GROUP; status = sai_bridge_api->set_bridge_port_attribute(port.m_bridge_port_id, &attr); } - else if (m_type == ISOLATION_GROUP_TYPE_PORT) + else if ((m_type == ISOLATION_GROUP_TYPE_PORT) && (port.m_type == Port::PORT)) { attr.id = SAI_PORT_ATTR_ISOLATION_GROUP; status = sai_port_api->set_port_attribute(port.m_port_id, &attr); From b80ece8407b91f3ae45335b52d327e5d0770bee1 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Thu, 8 Jul 2021 14:21:32 -0700 Subject: [PATCH 38/54] Fixed build issue. --- orchagent/isolationgrouporch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orchagent/isolationgrouporch.cpp b/orchagent/isolationgrouporch.cpp index 0d73d3010e..feab4aa628 100644 --- a/orchagent/isolationgrouporch.cpp +++ b/orchagent/isolationgrouporch.cpp @@ -638,7 +638,7 @@ IsolationGroup::unbind(Port &port, bool do_fwd_ref) attr.id = SAI_BRIDGE_PORT_ATTR_ISOLATION_GROUP; status = sai_bridge_api->set_bridge_port_attribute(port.m_bridge_port_id, &attr); } - else if ((m_type == ISOLATION_GROUP_TYPE_PORT) && (port.m_type == Port::PORT)) + else if ((m_type == ISOLATION_GROUP_TYPE_PORT) && (port.m_type == Port::PHY)) { attr.id = SAI_PORT_ATTR_ISOLATION_GROUP; status = sai_port_api->set_port_attribute(port.m_port_id, &attr); From 1d890a65e1d70fa46bdbd3e6d4f2466d1d49de75 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Thu, 8 Jul 2021 15:31:22 -0700 Subject: [PATCH 39/54] updated the orchdaemon.h --- orchagent/orchdaemon.h | 1 + 1 file changed, 1 insertion(+) diff --git a/orchagent/orchdaemon.h b/orchagent/orchdaemon.h index ec2389b906..bdcc053ed3 100644 --- a/orchagent/orchdaemon.h +++ b/orchagent/orchdaemon.h @@ -32,6 +32,7 @@ #include "debugcounterorch.h" #include "directory.h" #include "natorch.h" +#include "isolationgrouporch.h" #include "mlagorch.h" #include "muxorch.h" #include "macsecorch.h" From 153ea2ce08c9b73f4a10a04515ede7505cd850e3 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Fri, 9 Jul 2021 08:45:49 -0700 Subject: [PATCH 40/54] Fixed py test issue. --- tests/test_mclag_fdb.py | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/tests/test_mclag_fdb.py b/tests/test_mclag_fdb.py index 08ce3b1c3a..5049859437 100644 --- a/tests/test_mclag_fdb.py +++ b/tests/test_mclag_fdb.py @@ -139,8 +139,7 @@ def test_mclagFdb_remote_dynamic_mac_add(dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), - ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), - ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0005")))] + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true")] ) assert ok, str(extra) @@ -181,8 +180,7 @@ def test_mclagFdb_remote_static_mac_add(dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], - [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), - ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0005")))] + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC")] ) assert ok, str(extra) @@ -225,8 +223,7 @@ def test_mclagFdb_remote_to_local_mac_move(dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), - ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), - ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0005")))] + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true")] ) assert ok, str(extra) @@ -246,8 +243,7 @@ def test_mclagFdb_remote_to_local_mac_move(dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], - [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC"), - ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0008")))] + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC")] ) assert ok, str(extra) @@ -269,8 +265,7 @@ def test_mclagFdb_local_mac_move_del(dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], - [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC"), - ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0008")))] + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC")] ) assert ok, str(extra) @@ -308,8 +303,7 @@ def test_mclagFdb_local_to_remote_move(dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], - [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC"), - ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0008")))] + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC")] ) assert ok, str(extra) @@ -330,8 +324,7 @@ def test_mclagFdb_local_to_remote_move(dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), - ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), - ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0005")))] + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true")] ) assert ok, str(extra) @@ -354,8 +347,7 @@ def test_mclagFdb_remote_move_del(dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), - ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), - ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0005")))] + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true")] ) assert ok, str(extra) @@ -394,8 +386,7 @@ def test_mclagFdb_remote_move_peer_node(dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), - ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), - ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0005")))] + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true")] ) assert ok, str(extra) @@ -416,8 +407,7 @@ def test_mclagFdb_remote_move_peer_node(dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), - ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), - ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0006")))] + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true")] ) assert ok, str(extra) @@ -454,8 +444,7 @@ def test_mclagFdb_static_mac_dynamic_move_reject(dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], - [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), - ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0008")))] + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC")] ) assert ok, str(extra) @@ -475,8 +464,7 @@ def test_mclagFdb_static_mac_dynamic_move_reject(dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "3C:85:99:5E:00:01"), ("bvid", str(dvs.getVlanOid("200")))], - [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), - ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", get_bridge_port_oid(dvs, get_port_oid(dvs, "PortChannel0008")))] + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC")] ) assert ok, str(extra) From 532f1e744e8a8e946fea34d3e533824f14952185 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Fri, 9 Jul 2021 11:01:41 -0700 Subject: [PATCH 41/54] Remove as the change may not be supported on non-brcm for PortChannel settings. --- tests/test_mclag.py | 111 -------------------------------------------- 1 file changed, 111 deletions(-) delete mode 100644 tests/test_mclag.py diff --git a/tests/test_mclag.py b/tests/test_mclag.py deleted file mode 100644 index 7addbd9b11..0000000000 --- a/tests/test_mclag.py +++ /dev/null @@ -1,111 +0,0 @@ -# Common file to test all MCLAG related changes -from swsscommon import swsscommon -import time -import re -import json -import pytest -import platform -from distutils.version import StrictVersion - -# Create port-channel -def create_portchannel(table, po_name): - fvs = swsscommon.FieldValuePairs([("admin", "up"), ("mtu", "1500")]) - table.set(po_name, fvs) - time.sleep(1) - -# Delete port-channel -def delete_portchannel(table, po_name): - table._del(po_name) - time.sleep(1) - -# Create port-channel member -def create_portchannel_member(table, po_name, po_member_name): - fvs = swsscommon.FieldValuePairs([("status", "enabled")]) - table.set(po_name + ":" + po_member_name, fvs) - time.sleep(1) - -# Delete port-channel member -def delete_portchannel_member(table, po_name, po_member_name): - table._del(po_name + ":" + po_member_name) - time.sleep(1) - - -# Test newly introduce traffic_disable attribute in APP_DB LAG table -class TestPortChannelTrafficDisable(object): - - APP_LAG_TABLE = "LAG_TABLE" - APP_LAG_MEMBER_TABLE = "LAG_MEMBER_TABLE" - ASIC_LAG_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_LAG" - ASIC_LAG_MEMBER_TABLE = "ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER" - - PORTCHANNEL_NAME = "PortChannel100" - PORTCHANNEL_MEMBER1 = "Ethernet0" - PORTCHANNEL_MEMBER2 = "Ethernet4" - - # Set LAG traffic_disable attribute - def set_portchannel_trafficdisable(self, table, po_name, bool_str): - fvs = swsscommon.FieldValuePairs([("traffic_disable", bool_str)]) - table.set(po_name, fvs) - time.sleep(1) - - def check_portchannel_member_in_asicdb(self, dvs, po_member_name): - asic_lag_table = swsscommon.Table(self.asic_db, self.ASIC_LAG_TABLE) - lag_entries = asic_lag_table.getKeys() - assert len(lag_entries) == 1, "No LAG entry in ASIC_DB" - - asic_lag_mbr_table = swsscommon.Table(self.asic_db, self.ASIC_LAG_MEMBER_TABLE) - lag_mem_entries = asic_lag_mbr_table.getKeys() - if len(lag_mem_entries) == 0: - return False - for i in range(len(lag_mem_entries)): - (status, fvs) = asic_lag_mbr_table.get(lag_mem_entries[i]) - for fv in fvs: - if fv[0] == "SAI_LAG_MEMBER_ATTR_LAG_ID": - assert fv[1] == lag_entries[0] - elif fv[0] == "SAI_LAG_MEMBER_ATTR_PORT_ID": - if dvs.asicdb.portoidmap[fv[1]] == po_member_name: - return True - return False - - # Test traffic_disable attribute setting on LAG table entry in APP_DB - # 1. Create LAG with 1 member. Verify LAG and LAG member are added to ASIC_DB - # 2. Set traffic disable to true for LAG. Verify LAG member is removed from ASIC_DB - # 3. Add a second LAG member. Verify it is not added to ASIC_DB - # 4. Set traffic disable to false for LAG. Verify both LAG members are added to ASIC_DB - # 5. Delete LAG and its two members - def test_portchannel_traffic_disable(self, dvs, testlog): - self.app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) - self.asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) - lag_table = swsscommon.ProducerStateTable(self.app_db, self.APP_LAG_TABLE) - lag_member_table = swsscommon.ProducerStateTable(self.app_db, self.APP_LAG_MEMBER_TABLE) - - # Test1: verify default traffic_disable is not set - create_portchannel(lag_table, self.PORTCHANNEL_NAME) - create_portchannel_member(lag_member_table, self.PORTCHANNEL_NAME, self.PORTCHANNEL_MEMBER1) - status = self.check_portchannel_member_in_asicdb(dvs, self.PORTCHANNEL_MEMBER1) - assert status == True, "LAG member is not added to ASIC_DB" - - # Test2: verify LAG member is removed from ASIC_DB when traffic_disable - # attribute is set to true - self.set_portchannel_trafficdisable(lag_table, self.PORTCHANNEL_NAME, "true") - status = self.check_portchannel_member_in_asicdb(dvs, self.PORTCHANNEL_MEMBER1) - assert status == False, "LAG member is not removed from ASIC_DB" - - # Test3: verify new LAG member is not added to ASIC_DB when traffic_disable - # attribute is set to true - create_portchannel_member(lag_member_table, self.PORTCHANNEL_NAME, self.PORTCHANNEL_MEMBER2) - status = self.check_portchannel_member_in_asicdb(dvs, self.PORTCHANNEL_MEMBER2) - assert status == False, "LAG member is incorrectly added to ASIC_DB" - - # Test4: verify both LAG members are added to ASIC_DB whent traffic_disable - # attribute is set to false - self.set_portchannel_trafficdisable(lag_table, self.PORTCHANNEL_NAME, "false") - status = self.check_portchannel_member_in_asicdb(dvs, self.PORTCHANNEL_MEMBER1) - assert status == True, "LAG member Ethernet0 is not added to ASIC_DB" - status = self.check_portchannel_member_in_asicdb(dvs, self.PORTCHANNEL_MEMBER2) - assert status == True, "LAG member Ethernet4 is not added to ASIC_DB" - - # Cleanup - delete_portchannel_member(lag_member_table, self.PORTCHANNEL_NAME, self.PORTCHANNEL_MEMBER1) - delete_portchannel_member(lag_member_table, self.PORTCHANNEL_NAME, self.PORTCHANNEL_MEMBER2) - delete_portchannel(lag_table, self.PORTCHANNEL_NAME) From b1dcb477b78bccf0843ea037b40a110b644828c9 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Fri, 9 Jul 2021 11:05:43 -0700 Subject: [PATCH 42/54] Addressed a review comment. --- orchagent/isolationgrouporch.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/orchagent/isolationgrouporch.cpp b/orchagent/isolationgrouporch.cpp index feab4aa628..52be7fa91d 100644 --- a/orchagent/isolationgrouporch.cpp +++ b/orchagent/isolationgrouporch.cpp @@ -157,10 +157,10 @@ IsoGrpOrch::doIsoGrpTblTask(Consumer &consumer) /* Send a notification and see if observers want to detach */ IsolationGroupUpdate update = {grp.get(), false}; grp->notifyObservers(SUBJECT_TYPE_ISOLATION_GROUP_CHANGE, &update); - } - // Finally delete it if it - status = delIsolationGroup(name); + // Finally delete it if it + status = delIsolationGroup(name); + } } if (status != ISO_GRP_STATUS_RETRY) From c0e1c993b48f4efa723fc6f7237aa8b9115ac370 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Fri, 9 Jul 2021 16:05:05 -0700 Subject: [PATCH 43/54] Addressing FIXME alert. --- orchagent/fdborch.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index 520e8d6e26..4fef9ee4ad 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -1367,7 +1367,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, SWSS_LOG_ERROR("Failed to create %s FDB %s in %s on %s, rv:%d", fdbData.type.c_str(), entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str(), status); - task_process_status handle_status = handleSaiCreateStatus(SAI_API_FDB, status); //FIXME: it should be based on status. Some could be retried, some not + task_process_status handle_status = handleSaiCreateStatus(SAI_API_FDB, status); //Address me: it should be based on status. Some could be retried, some not if (handle_status != task_success) { return parseHandleSaiStatusFailure(handle_status); @@ -1400,7 +1400,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, SWSS_LOG_ERROR("Failed to create %s FDB %s in %s on %s, rv:%d", fdbData.type.c_str(), entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str(), status); - task_process_status handle_status = handleSaiCreateStatus(SAI_API_FDB, status); //FIXME: it should be based on status. Some could be retried, some not + task_process_status handle_status = handleSaiCreateStatus(SAI_API_FDB, status); //Address me: it should be based on status. Some could be retried, some not if (handle_status != task_success) { return parseHandleSaiStatusFailure(handle_status); @@ -1546,7 +1546,7 @@ bool FdbOrch::removeFdbEntry(const FdbEntry& entry, FdbOrigin origin) { SWSS_LOG_ERROR("FdbOrch RemoveFDBEntry: Failed to remove FDB entry. mac=%s, bv_id=0x%" PRIx64, entry.mac.to_string().c_str(), entry.bv_id); - task_process_status handle_status = handleSaiRemoveStatus(SAI_API_FDB, status); //FIXME: it should be based on status. Some could be retried. some not + task_process_status handle_status = handleSaiRemoveStatus(SAI_API_FDB, status); //Address me: it should be based on status. Some could be retried. some not if (handle_status != task_success) { return parseHandleSaiStatusFailure(handle_status); From fc21a8253363a1039517fcfcc2af031c7f85601c Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Tue, 27 Jul 2021 09:36:33 -0700 Subject: [PATCH 44/54] Address review comments. --- orchagent/fdborch.cpp | 4 ++-- orchagent/fdborch.h | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index 4fef9ee4ad..ee4ede9f08 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -44,8 +44,8 @@ FdbOrch::FdbOrch(DBConnector* applDbConnector, vector app Orch::addExecutor(flushNotifier); /* Add FDB notifications support from ASIC */ - DBConnector *notificationsDb = new DBConnector("ASIC_DB", 0); - m_fdbNotificationConsumer = new swss::NotificationConsumer(notificationsDb, "NOTIFICATIONS"); + DBConnector *notificationsDb = new DBConnector("ASIC_DB", 0); + m_fdbNotificationConsumer = new swss::NotificationConsumer(notificationsDb, "NOTIFICATIONS"); auto fdbNotifier = new Notifier(m_fdbNotificationConsumer, this, "FDB_NOTIFICATIONS"); Orch::addExecutor(fdbNotifier); diff --git a/orchagent/fdborch.h b/orchagent/fdborch.h index 408752e11c..82611e686f 100644 --- a/orchagent/fdborch.h +++ b/orchagent/fdborch.h @@ -38,6 +38,12 @@ struct FdbUpdate bool add; }; +struct FdbFlushUpdate +{ + vector entries; + Port port; +}; + struct FdbData { sai_object_id_t bridge_port_id; @@ -58,12 +64,6 @@ struct FdbData unsigned int vni; }; -struct FdbFlushUpdate -{ - vector entries; - Port port; -}; - struct SavedFdbEntry { MacAddress mac; From e931849ea9bbd9686c8db0e9f27f67230385f37b Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Tue, 27 Jul 2021 14:03:47 -0700 Subject: [PATCH 45/54] Addressed review comments. --- fdbsyncd/fdbsync.cpp | 3 +++ fdbsyncd/fdbsyncd.cpp | 4 ++-- orchagent/fdborch.cpp | 2 -- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/fdbsyncd/fdbsync.cpp b/fdbsyncd/fdbsync.cpp index d304c302fd..0cdcc63214 100644 --- a/fdbsyncd/fdbsync.cpp +++ b/fdbsyncd/fdbsync.cpp @@ -659,6 +659,9 @@ void FdbSync::macAddVxlan(string key, struct in_addr vtep, string type, uint32_t fvVector.push_back(t); fvVector.push_back(v); + SWSS_LOG_INFO("%sVXLAN_FDB_TABLE: ADD_KEY %s vtep:%s type:%s", + m_AppRestartAssist->isWarmStartInProgress() ? "WARM-RESTART:" : "" , + key.c_str(), svtep.c_str(), type.c_str()); // If warmstart is in progress, we take all netlink changes into the cache map if (m_AppRestartAssist->isWarmStartInProgress()) { diff --git a/fdbsyncd/fdbsyncd.cpp b/fdbsyncd/fdbsyncd.cpp index ccec76931c..a83b2693e1 100644 --- a/fdbsyncd/fdbsyncd.cpp +++ b/fdbsyncd/fdbsyncd.cpp @@ -92,11 +92,11 @@ int main(int argc, char **argv) { s.select(&temps); - if(temps == (Selectable *)sync.getFdbStateTable()) + if (temps == (Selectable *)sync.getFdbStateTable()) { sync.processStateFdb(); } - else if(temps == (Selectable *)sync.getMclagRemoteFdbStateTable()) + else if (temps == (Selectable *)sync.getMclagRemoteFdbStateTable()) { sync.processStateMclagRemoteFdb(); } diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index ee4ede9f08..8e57508f83 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -32,7 +32,6 @@ FdbOrch::FdbOrch(DBConnector* applDbConnector, vector app m_fdbStateTable(stateDbFdbConnector.first, stateDbFdbConnector.second), m_mclagFdbStateTable(stateDbMclagFdbConnector.first, stateDbMclagFdbConnector.second) { - for(auto it: appFdbTables) { m_appTables.push_back(new Table(applDbConnector, it.first)); @@ -46,7 +45,6 @@ FdbOrch::FdbOrch(DBConnector* applDbConnector, vector app /* Add FDB notifications support from ASIC */ DBConnector *notificationsDb = new DBConnector("ASIC_DB", 0); m_fdbNotificationConsumer = new swss::NotificationConsumer(notificationsDb, "NOTIFICATIONS"); - auto fdbNotifier = new Notifier(m_fdbNotificationConsumer, this, "FDB_NOTIFICATIONS"); Orch::addExecutor(fdbNotifier); } From 92b425506f9b7c3997c49807d550631f67130737 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Tue, 27 Jul 2021 15:14:28 -0700 Subject: [PATCH 46/54] Address review comments. --- orchagent/fdborch.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index 8e57508f83..ec8aac5109 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -1365,7 +1365,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, SWSS_LOG_ERROR("Failed to create %s FDB %s in %s on %s, rv:%d", fdbData.type.c_str(), entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str(), status); - task_process_status handle_status = handleSaiCreateStatus(SAI_API_FDB, status); //Address me: it should be based on status. Some could be retried, some not + task_process_status handle_status = handleSaiCreateStatus(SAI_API_FDB, status); //FIXME: it should be based on status. Some could be retried, some not if (handle_status != task_success) { return parseHandleSaiStatusFailure(handle_status); @@ -1398,7 +1398,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, SWSS_LOG_ERROR("Failed to create %s FDB %s in %s on %s, rv:%d", fdbData.type.c_str(), entry.mac.to_string().c_str(), vlan.m_alias.c_str(), port_name.c_str(), status); - task_process_status handle_status = handleSaiCreateStatus(SAI_API_FDB, status); //Address me: it should be based on status. Some could be retried, some not + task_process_status handle_status = handleSaiCreateStatus(SAI_API_FDB, status); //FIXME: it should be based on status. Some could be retried, some not if (handle_status != task_success) { return parseHandleSaiStatusFailure(handle_status); @@ -1544,7 +1544,7 @@ bool FdbOrch::removeFdbEntry(const FdbEntry& entry, FdbOrigin origin) { SWSS_LOG_ERROR("FdbOrch RemoveFDBEntry: Failed to remove FDB entry. mac=%s, bv_id=0x%" PRIx64, entry.mac.to_string().c_str(), entry.bv_id); - task_process_status handle_status = handleSaiRemoveStatus(SAI_API_FDB, status); //Address me: it should be based on status. Some could be retried. some not + task_process_status handle_status = handleSaiRemoveStatus(SAI_API_FDB, status); //FIXME: it should be based on status. Some could be retried. some not if (handle_status != task_success) { return parseHandleSaiStatusFailure(handle_status); From 0acbd54b58b8820848573b609366962d75170784 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Thu, 29 Jul 2021 13:57:04 -0700 Subject: [PATCH 47/54] Addressed review comments. --- orchagent/isolationgrouporch.cpp | 20 ++++--------- orchagent/mlagorch.cpp | 18 +++++------- orchagent/observer.h | 48 ++++---------------------------- 3 files changed, 17 insertions(+), 69 deletions(-) diff --git a/orchagent/isolationgrouporch.cpp b/orchagent/isolationgrouporch.cpp index 52be7fa91d..0138a6ab95 100644 --- a/orchagent/isolationgrouporch.cpp +++ b/orchagent/isolationgrouporch.cpp @@ -138,13 +138,10 @@ IsoGrpOrch::doIsoGrpTblTask(Consumer &consumer) if (ISO_GRP_STATUS_SUCCESS == status) { auto grp = getIsolationGroup(name); - if (!grp->isObserver(this)) - { - IsolationGroupUpdate update = {grp.get(), true}; - grp->notifyObservers(SUBJECT_TYPE_ISOLATION_GROUP_CHANGE, &update); + IsolationGroupUpdate update = {grp.get(), true}; + grp->notifyObservers(SUBJECT_TYPE_ISOLATION_GROUP_CHANGE, &update); - grp->attach(this); - } + grp->attach(this); } } else @@ -220,15 +217,8 @@ IsoGrpOrch::delIsolationGroup(string name) auto grp = m_isolationGrps.find(name); if (grp != m_isolationGrps.end()) { - if (!grp->second->hasObservers()) - { - grp->second->destroy(); - m_isolationGrps.erase(name); - } - else - { - SWSS_LOG_NOTICE("%s group has observers. Not deleting", name.c_str()); - } + grp->second->destroy(); + m_isolationGrps.erase(name); } return ISO_GRP_STATUS_SUCCESS; diff --git a/orchagent/mlagorch.cpp b/orchagent/mlagorch.cpp index 6a6ba8de34..51309d2cad 100644 --- a/orchagent/mlagorch.cpp +++ b/orchagent/mlagorch.cpp @@ -312,15 +312,11 @@ bool MlagOrch::addIslIsolationGroup() m_iccp_control_isolation_grp = true; //Register with IsoGrpOrch to receive update when ICCP deletes the group - if (!isolation_grp->isObserver(this)) - { - isolation_grp->attach(SUBJECT_TYPE_ISOLATION_GROUP_CHANGE, this); - ++m_num_isolation_grp_attach; - m_attach_isolation_grp = true; - SWSS_LOG_NOTICE("MLAG found ICCP-controlled isolation group. Attach to it"); - } - else - SWSS_LOG_NOTICE("MLAG is already attached to ICCP-controlled isolation group"); + isolation_grp->attach(this); + ++m_num_isolation_grp_attach; + m_attach_isolation_grp = true; + SWSS_LOG_NOTICE("MLAG found ICCP-controlled isolation group. Attach to it"); + return false; } //Create a new isolation group @@ -394,7 +390,7 @@ bool MlagOrch::deleteIslIsolationGroup() //Mlag configuration is deleted while it is up if (m_attach_isolation_grp) { - isolation_grp->detach(SUBJECT_TYPE_ISOLATION_GROUP_CHANGE, this); + isolation_grp->detach(this); ++m_num_isolation_grp_detach; m_attach_isolation_grp = false; SWSS_LOG_NOTICE("MLAG detaches from ICCP-controlled isolation group"); @@ -408,7 +404,7 @@ bool MlagOrch::deleteIslIsolationGroup() //only after all observers are removed if (m_attach_isolation_grp) { - isolation_grp->detach(SUBJECT_TYPE_ISOLATION_GROUP_CHANGE, this); + isolation_grp->detach(this); ++m_num_isolation_grp_detach; m_attach_isolation_grp = false; } diff --git a/orchagent/observer.h b/orchagent/observer.h index 93c87635f5..addcc9cc02 100644 --- a/orchagent/observer.h +++ b/orchagent/observer.h @@ -38,64 +38,26 @@ class Observer class Subject { public: - virtual void attach(SubjectType type, Observer *observer) - { - m_observers.emplace_back(type, observer); - } - virtual void attach(Observer *observer) { - attach(SUBJECT_TYPE_ALL_CHANGES, observer); - } - - virtual void detach(SubjectType type, Observer *observer) - { - pair temp(type, observer); - - auto it = find(m_observers.begin(), m_observers.end(), temp); - if (it != m_observers.end()) - { - m_observers.erase(it); - } + m_observers.push_back(observer); } virtual void detach(Observer *observer) { - detach(SUBJECT_TYPE_ALL_CHANGES, observer); - } - - virtual bool isObserver(SubjectType type, Observer *observer) - { - pair temp(type, observer); - - return m_observers.end() != find(m_observers.begin(), m_observers.end(), temp); - } - - virtual bool isObserver(Observer *observer) - { - return isObserver(SUBJECT_TYPE_ALL_CHANGES, observer); - } - - virtual bool hasObservers() - { - return m_observers.size() > 0; + m_observers.remove(observer); } virtual ~Subject() {} protected: - list> m_observers; + list m_observers; virtual void notify(SubjectType type, void *cntx) { - for (auto iter = m_observers.begin(); iter != m_observers.end(); /* No-op */) + for (auto iter: m_observers) { - auto nxt = next(iter); - if (((*iter).first == SUBJECT_TYPE_ALL_CHANGES) || ((*iter).first == type)) - { - (*iter).second->update(type, cntx); - } - iter = nxt; + iter->update(type, cntx); } } }; From bf8193927c168eba4f920ec21a39b32c3cac6d7e Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Thu, 29 Jul 2021 14:16:42 -0700 Subject: [PATCH 48/54] Removing the isolation group handling from Mlagorch, Isolation group now will be added/updated only via mclagsyncd updates. --- orchagent/mlagorch.cpp | 272 ----------------------------------------- orchagent/mlagorch.h | 12 -- 2 files changed, 284 deletions(-) diff --git a/orchagent/mlagorch.cpp b/orchagent/mlagorch.cpp index 51309d2cad..aa12ecb9c6 100644 --- a/orchagent/mlagorch.cpp +++ b/orchagent/mlagorch.cpp @@ -18,15 +18,10 @@ #include "portsorch.h" #include "mlagorch.h" -//Name of ISL isolation group must match with the name used by Mclagsyncd -#define MLAG_ISL_ISOLATION_GROUP_NAME "MCLAG_ISO_GRP" -#define MLAG_ISL_ISOLATION_GROUP_DESCR "Isolation group for MCLAG" - using namespace std; using namespace swss; extern PortsOrch *gPortsOrch; -extern IsoGrpOrch *gIsoGrpOrch; extern MlagOrch *gMlagOrch; MlagOrch::MlagOrch(DBConnector *db, vector &tableNames): @@ -40,28 +35,6 @@ MlagOrch::~MlagOrch() SWSS_LOG_ENTER(); } -void MlagOrch::update(SubjectType type, void *cntx) -{ - IsolationGroupUpdate *update; - - if (type == SUBJECT_TYPE_ISOLATION_GROUP_CHANGE) - { - update = static_cast(cntx); - - if (update->add) - { - m_iccp_control_isolation_grp = true; - SWSS_LOG_NOTICE("MLAG yields control of isolation group"); - } - else - { - m_iccp_control_isolation_grp = false; - addAllMlagInterfacesToIsolationGroup(); - SWSS_LOG_NOTICE("MLAG takes control of isolation group"); - } - } -} - //------------------------------------------------------------------ //Private API section //------------------------------------------------------------------ @@ -187,9 +160,6 @@ bool MlagOrch::addIslInterface(string isl_name) m_isl_name = isl_name; - //Create isolation group if ICCPd has not created it yet - addIslIsolationGroup(); - //Update observers update.isl_name = isl_name; update.is_add = true; @@ -208,8 +178,6 @@ bool MlagOrch::delIslInterface() update.is_add = false; m_isl_name.clear(); - //Delete isolation group if ICCP has not taken control yet - deleteIslIsolationGroup(); //Notify observer notify(SUBJECT_TYPE_MLAG_ISL_CHANGE, static_cast(&update)); @@ -232,12 +200,6 @@ bool MlagOrch::addMlagInterface(string if_name) m_mlagIntfs.insert(if_name); - //If this is the first MLAG interface added, create isolation group - if (m_mlagIntfs.size() == 1) - addIslIsolationGroup(); - else - updateIslIsolationGroup(if_name, true); - //Notify observer update.if_name = if_name; update.is_add = true; @@ -259,12 +221,6 @@ bool MlagOrch::delMlagInterface(string if_name) { m_mlagIntfs.erase(if_name); - //If this is the last MLAG interface added, delete isolation group - if (m_mlagIntfs.size() == 0) - deleteIslIsolationGroup(); - else - updateIslIsolationGroup(if_name, false); - //Notify observers update.if_name = if_name; update.is_add = false; @@ -288,231 +244,3 @@ bool MlagOrch::isIslInterface(string if_name) else return false; } - -/* Create isolation group based on MLAG configuration before ICCPd - * takes control of the isolation group - */ -bool MlagOrch::addIslIsolationGroup() -{ - isolation_group_status_t status; - string isolate_dst_ports; - - //Need peer link and at least one MLAG interface to create an isolation group - if (m_isl_name.empty() || (m_mlagIntfs.size() == 0)) - { - SWSS_LOG_NOTICE("MLAG skips adding isolation group: isl name(%s), num MLAG interface %zu", - m_isl_name.empty() ? "invalid" : m_isl_name.c_str(), m_mlagIntfs.size()); - return false; - } - //During SwSS warm reboot, isolation group can be created first by ICCP - //due to IsoGrpOrch processing info from APP_DB first - auto isolation_grp = gIsoGrpOrch->getIsolationGroup(MLAG_ISL_ISOLATION_GROUP_NAME); - if (isolation_grp) - { - m_iccp_control_isolation_grp = true; - - //Register with IsoGrpOrch to receive update when ICCP deletes the group - isolation_grp->attach(this); - ++m_num_isolation_grp_attach; - m_attach_isolation_grp = true; - SWSS_LOG_NOTICE("MLAG found ICCP-controlled isolation group. Attach to it"); - - return false; - } - //Create a new isolation group - for (auto mlag_if = m_mlagIntfs.begin(); mlag_if != m_mlagIntfs.end(); ++mlag_if) - { - if (isolate_dst_ports.length()) - { - isolate_dst_ports = isolate_dst_ports + ',' + *mlag_if; - } - else - { - isolate_dst_ports = *mlag_if; - } - } - status = gIsoGrpOrch->addIsolationGroup( - MLAG_ISL_ISOLATION_GROUP_NAME, - ISOLATION_GROUP_TYPE_BRIDGE_PORT, - MLAG_ISL_ISOLATION_GROUP_DESCR, - m_isl_name, isolate_dst_ports); - - if (status != ISO_GRP_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("MLAG failed to create ISL isolation group, status %d", status); - ++m_num_isolation_grp_add_error; - return false; - } - //Register wiht IsoGrpOrch to receive update when ICCP adds the group - isolation_grp = gIsoGrpOrch->getIsolationGroup(MLAG_ISL_ISOLATION_GROUP_NAME); - if (isolation_grp) - { - isolation_grp->attach(SUBJECT_TYPE_ISOLATION_GROUP_CHANGE, this); - ++m_num_isolation_grp_attach; - m_attach_isolation_grp = true; - } - SWSS_LOG_NOTICE("MLAG creates ISL isolation group"); - return true; -} - -bool MlagOrch::deleteIslIsolationGroup() -{ - isolation_group_status_t status; - - //Delete isolation group if either peer link or all MLAG interfaces are removed - if (!m_isl_name.empty() && (m_mlagIntfs.size() > 0)) - { - SWSS_LOG_NOTICE("MLAG skips deleting isolation group: isl name %s, num MLAG interface %zu", - m_isl_name.c_str(), m_mlagIntfs.size()); - return false; - } - //The delete request is triggered when the last MLAG interface is deleted - //or when peer link interface is deleted. If MlagOrch no longer attaches - //to isolation group due to previous deletion, do not need to do anything - if (!m_attach_isolation_grp) - return false; - - auto isolation_grp = gIsoGrpOrch->getIsolationGroup(MLAG_ISL_ISOLATION_GROUP_NAME); - - if (!isolation_grp) - { - SWSS_LOG_ERROR("MLAG fails to find isolation group, iccp_control %d", - m_iccp_control_isolation_grp); - return false; - } - //Reset the ICCP control flag since MlagOrch will detach from the group - //and won't receive any further update - m_iccp_control_isolation_grp = false; - - //Only need to unregister with IsoGrpOrch if ICCP is in control - if (m_iccp_control_isolation_grp) - { - //Mlag configuration is deleted while it is up - if (m_attach_isolation_grp) - { - isolation_grp->detach(this); - ++m_num_isolation_grp_detach; - m_attach_isolation_grp = false; - SWSS_LOG_NOTICE("MLAG detaches from ICCP-controlled isolation group"); - } - else - SWSS_LOG_ERROR("MLAG is not attached to ICCP-controlled isolation group"); - } - else - { - //Unregister with IsoGrpOrch before deleting since the group is deleted - //only after all observers are removed - if (m_attach_isolation_grp) - { - isolation_grp->detach(this); - ++m_num_isolation_grp_detach; - m_attach_isolation_grp = false; - } - status = gIsoGrpOrch->delIsolationGroup(MLAG_ISL_ISOLATION_GROUP_NAME); - if (status == ISO_GRP_STATUS_SUCCESS) - { - SWSS_LOG_NOTICE("MLAG deletes ISL isolation group"); - return true; - } - else - { - SWSS_LOG_ERROR("MLAG can't delete ISL isolation group, status %d", status); - ++m_num_isolation_grp_del_error; - return false; - } - } - return true; -} - -bool MlagOrch::updateIslIsolationGroup(string if_name, bool is_add) -{ - string isolate_dst_ports; - isolation_group_status_t status; - - //Do not trigger any update if ICCP already tooks control - if (m_iccp_control_isolation_grp) - return false; - - auto isolation_grp = gIsoGrpOrch->getIsolationGroup(MLAG_ISL_ISOLATION_GROUP_NAME); - if (isolation_grp) - { - //Isolation group can handle forward reference. Updated it with - //the latest set of MLAG interfaces - for (auto mlag_if = m_mlagIntfs.begin(); mlag_if != m_mlagIntfs.end(); ++mlag_if) - { - if (isolate_dst_ports.length()) - isolate_dst_ports = isolate_dst_ports + ',' + *mlag_if; - else - isolate_dst_ports = *mlag_if; - } - status = isolation_grp->setMembers(isolate_dst_ports); - if (status != ISO_GRP_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("MLAG can't %s member %s for isolation group, status %d", - is_add ? "add" : "delete", if_name.c_str(), status); - ++m_num_isolation_grp_update_error; - return false; - } - else - { - SWSS_LOG_NOTICE("MLAG %s member %s for isolation group", - is_add ? "adds" : "deletes", if_name.c_str()); - return true; - } - } - else - { - SWSS_LOG_ERROR("MLAG can't find MlagOrch-controlled isolation group to update"); - } - return true; -} - -bool MlagOrch::addAllMlagInterfacesToIsolationGroup() -{ - isolation_group_status_t status; - string isolate_dst_ports; - - //Need peer link and at least one MLAG interface to create an isolation group - if (m_isl_name.empty() || (m_mlagIntfs.size() == 0)) - { - SWSS_LOG_NOTICE("MLAG skips adding mlag-if to isolation group: isl name(%s), mlag-if count %zu", - m_isl_name.empty() ? "invalid" : m_isl_name.c_str(), m_mlagIntfs.size()); - return false; - } - auto isolation_grp = gIsoGrpOrch->getIsolationGroup(MLAG_ISL_ISOLATION_GROUP_NAME); - if (!isolation_grp) - { - SWSS_LOG_ERROR("MLAG can't find ISL isolation group"); - return false; - } - for (auto mlag_if = m_mlagIntfs.begin(); mlag_if != m_mlagIntfs.end(); ++mlag_if) - { - if (isolate_dst_ports.length()) - { - isolate_dst_ports = isolate_dst_ports + ',' + *mlag_if; - } - else - { - isolate_dst_ports = *mlag_if; - } - } - //Update isolation group - status = gIsoGrpOrch->addIsolationGroup( - MLAG_ISL_ISOLATION_GROUP_NAME, - ISOLATION_GROUP_TYPE_BRIDGE_PORT, - MLAG_ISL_ISOLATION_GROUP_DESCR, - m_isl_name, isolate_dst_ports); - - if (status != ISO_GRP_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("MLAG fails to update ISL isolation group, status %d", status); - ++m_num_isolation_grp_update_error; - return false; - } - else - { - SWSS_LOG_NOTICE("MLAG adds all MLAG interfaces to ISL isolation group"); - return true; - } -} - diff --git a/orchagent/mlagorch.h b/orchagent/mlagorch.h index 8144d8a72b..27f4e9219b 100644 --- a/orchagent/mlagorch.h +++ b/orchagent/mlagorch.h @@ -22,7 +22,6 @@ #include #include "orch.h" #include "port.h" -#include "isolationgrouporch.h" struct MlagIfUpdate { @@ -54,13 +53,6 @@ class MlagOrch: public Orch, public Observer, public Subject private: std::string m_isl_name; std::set m_mlagIntfs; - bool m_iccp_control_isolation_grp = false; - bool m_attach_isolation_grp = false; - uint32_t m_num_isolation_grp_attach = 0; - uint32_t m_num_isolation_grp_detach = 0; - uint32_t m_num_isolation_grp_add_error = 0; - uint32_t m_num_isolation_grp_del_error = 0; - uint32_t m_num_isolation_grp_update_error = 0; void doTask(Consumer &consumer); void doMlagDomainTask(Consumer &consumer); @@ -69,10 +61,6 @@ class MlagOrch: public Orch, public Observer, public Subject bool delIslInterface(); bool addMlagInterface(string if_name); bool delMlagInterface(string if_name); - bool addIslIsolationGroup(); - bool deleteIslIsolationGroup(); - bool updateIslIsolationGroup(string if_name, bool is_add); - bool addAllMlagInterfacesToIsolationGroup(); }; #endif /* SWSS_MLAGORCH_H */ From de4ab05d20d485e37eabfe7ffc464b0d17c299f8 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Thu, 29 Jul 2021 15:21:49 -0700 Subject: [PATCH 49/54] Fix compilation issue --- orchagent/mlagorch.h | 1 - 1 file changed, 1 deletion(-) diff --git a/orchagent/mlagorch.h b/orchagent/mlagorch.h index 27f4e9219b..9915d0e712 100644 --- a/orchagent/mlagorch.h +++ b/orchagent/mlagorch.h @@ -40,7 +40,6 @@ class MlagOrch: public Orch, public Observer, public Subject public: MlagOrch(DBConnector *db, vector &tableNames); ~MlagOrch(); - void update(SubjectType type, void *cntx); bool isMlagInterface(string if_name); bool isIslInterface(string if_name); From eaecfa2339b6ed59b8c0b404791970326d6775fd Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Thu, 29 Jul 2021 15:41:11 -0700 Subject: [PATCH 50/54] Added back the update function. --- orchagent/mlagorch.cpp | 4 ++++ orchagent/mlagorch.h | 1 + 2 files changed, 5 insertions(+) diff --git a/orchagent/mlagorch.cpp b/orchagent/mlagorch.cpp index aa12ecb9c6..81fd169fe4 100644 --- a/orchagent/mlagorch.cpp +++ b/orchagent/mlagorch.cpp @@ -35,6 +35,10 @@ MlagOrch::~MlagOrch() SWSS_LOG_ENTER(); } +void MlagOrch::update(SubjectType type, void *cntx) +{ + SWSS_LOG_ENTER(); +} //------------------------------------------------------------------ //Private API section //------------------------------------------------------------------ diff --git a/orchagent/mlagorch.h b/orchagent/mlagorch.h index 9915d0e712..27f4e9219b 100644 --- a/orchagent/mlagorch.h +++ b/orchagent/mlagorch.h @@ -40,6 +40,7 @@ class MlagOrch: public Orch, public Observer, public Subject public: MlagOrch(DBConnector *db, vector &tableNames); ~MlagOrch(); + void update(SubjectType type, void *cntx); bool isMlagInterface(string if_name); bool isIslInterface(string if_name); From a28f55764c484107a06f41758c61f0b802104e83 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Fri, 30 Jul 2021 14:27:47 -0700 Subject: [PATCH 51/54] Addressed review comments. --- orchagent/fdborch.cpp | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index ec8aac5109..61ce3d58be 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -1053,7 +1053,7 @@ void FdbOrch::notifyObserversFDBFlush(Port &port, sai_object_id_t& bvid) if (!flushUpdate.entries.empty()) { - notify(SUBJECT_TYPE_FDB_CHANGE, &flushUpdate); + notify(SUBJECT_TYPE_FDB_FLUSH_CHANGE, &flushUpdate); } } @@ -1392,23 +1392,6 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string(); - status = sai_fdb_api->create_fdb_entry(&fdb_entry, (uint32_t)attrs.size(), attrs.data()); - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to create %s FDB %s in %s on %s, rv:%d", - fdbData.type.c_str(), entry.mac.to_string().c_str(), - vlan.m_alias.c_str(), port_name.c_str(), status); - task_process_status handle_status = handleSaiCreateStatus(SAI_API_FDB, status); //FIXME: it should be based on status. Some could be retried, some not - if (handle_status != task_success) - { - return parseHandleSaiStatusFailure(handle_status); - } - } - port.m_fdb_count++; - m_portsOrch->setPort(port.m_alias, port); - vlan.m_fdb_count++; - m_portsOrch->setPort(vlan.m_alias, vlan); - if ((fdbData.origin != FDB_ORIGIN_MCLAG_ADVERTIZED) || (fdbData.origin != FDB_ORIGIN_VXLAN_ADVERTIZED)) { From 329016b1172f59c237ee2dd7bbcdf5d16611660a Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Fri, 30 Jul 2021 17:00:29 -0700 Subject: [PATCH 52/54] Addressed review comments. --- orchagent/observer.h | 2 -- orchagent/portsorch.cpp | 7 +++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/orchagent/observer.h b/orchagent/observer.h index addcc9cc02..03668c1198 100644 --- a/orchagent/observer.h +++ b/orchagent/observer.h @@ -2,14 +2,12 @@ #define SWSS_OBSERVER_H #include -#include using namespace std; using namespace swss; enum SubjectType { - SUBJECT_TYPE_ALL_CHANGES, SUBJECT_TYPE_NEXTHOP_CHANGE, SUBJECT_TYPE_NEIGH_CHANGE, SUBJECT_TYPE_FDB_CHANGE, diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 4ac36258b9..ff5f35facc 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -4245,6 +4245,9 @@ bool PortsOrch::addBridgePort(Port &port) m_portList[port.m_alias] = port; SWSS_LOG_NOTICE("Add bridge port %s to default 1Q bridge", port.m_alias.c_str()); + PortUpdate update = { port, true }; + notify(SUBJECT_TYPE_BRIDGE_PORT_CHANGE, static_cast(&update)) + return true; } @@ -4298,6 +4301,10 @@ bool PortsOrch::removeBridgePort(Port &port) } port.m_bridge_port_id = SAI_NULL_OBJECT_ID; + /* Remove bridge port */ + PortUpdate update = { port, false }; + notify(SUBJECT_TYPE_BRIDGE_PORT_CHANGE, static_cast(&update)); + SWSS_LOG_NOTICE("Remove bridge port %s from default 1Q bridge", port.m_alias.c_str()); m_portList[port.m_alias] = port; From dcbf3f4f3601c5cdf6ccb12e39342d8fdbe48e1a Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Sun, 1 Aug 2021 17:28:25 -0700 Subject: [PATCH 53/54] Addressed review comment. --- orchagent/fdborch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index 61ce3d58be..6094c12c05 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -1392,7 +1392,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string(); - if ((fdbData.origin != FDB_ORIGIN_MCLAG_ADVERTIZED) || + if ((fdbData.origin != FDB_ORIGIN_MCLAG_ADVERTIZED) && (fdbData.origin != FDB_ORIGIN_VXLAN_ADVERTIZED)) { /* State-DB is updated only for Local Mac addresses */ From 7a18eb71ec7fc758fb33e1208479ed3f4738f1d1 Mon Sep 17 00:00:00 2001 From: Praveen Elagala Date: Mon, 2 Aug 2021 11:15:26 -0700 Subject: [PATCH 54/54] Addressed a build failure. --- orchagent/portsorch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index ff5f35facc..bf8b1ed557 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -4246,7 +4246,7 @@ bool PortsOrch::addBridgePort(Port &port) SWSS_LOG_NOTICE("Add bridge port %s to default 1Q bridge", port.m_alias.c_str()); PortUpdate update = { port, true }; - notify(SUBJECT_TYPE_BRIDGE_PORT_CHANGE, static_cast(&update)) + notify(SUBJECT_TYPE_BRIDGE_PORT_CHANGE, static_cast(&update)); return true; }