diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index d2edd0ba20..0d06faddea 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -11,23 +11,30 @@ #include "crmorch.h" #include "notifier.h" #include "sai_serialize.h" +#include "vxlanorch.h" +#include "directory.h" extern sai_fdb_api_t *sai_fdb_api; extern sai_object_id_t gSwitchId; extern PortsOrch* gPortsOrch; extern CrmOrch * gCrmOrch; +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); @@ -57,7 +64,11 @@ bool FdbOrch::bake() 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; Port vlan; if (!m_portsOrch->getPort(entry.bv_id, vlan)) @@ -72,31 +83,55 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) if (update.add) { - SWSS_LOG_INFO("Storing FDB entry: [%s, 0x%" PRIx64 "] [ port: %s ]", - entry.mac.to_string().c_str(), - entry.bv_id, entry.port_name.c_str()); - auto inserted = m_entries.insert(entry); - - SWSS_LOG_DEBUG("FdbOrch notification: mac %s was inserted into bv_id 0x%" PRIx64, - entry.mac.to_string().c_str(), entry.bv_id); - - if (!inserted.second) + bool mac_move = false; + auto it = m_entries.find(entry); + if (it != m_entries.end()) { - SWSS_LOG_INFO("FdbOrch notification: mac %s is duplicate", entry.mac.to_string().c_str()); - return false; + /* 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) + { + SWSS_LOG_INFO("FdbOrch notification: mac %s is duplicate", entry.mac.to_string().c_str()); + return false; + } + 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.remote_ip = ""; + fdbdata.esi = ""; + fdbdata.vni = 0; + + m_entries[entry] = fdbdata; + 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=%lu mac=%s port=0x%" PRIx64, + m_entries.size(), entry.mac.to_string().c_str(), m_entries[entry].bridge_port_id); + // Write to StateDb std::vector fvs; - fvs.push_back(FieldValueTuple("port", entry.port_name)); - fvs.push_back(FieldValueTuple("type", "dynamic")); + fvs.push_back(FieldValueTuple("port", portName)); + 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); @@ -105,8 +140,11 @@ bool FdbOrch::storeFdbEntryState(const FdbUpdate& update) return false; } - // Remove in StateDb - m_fdbStateTable.del(key); + if (oldFdbData.origin != FDB_ORIGIN_VXLAN_ADVERTIZED) + { + // Remove in StateDb for non advertised mac addresses + m_fdbStateTable.del(key); + } gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); return true; @@ -122,6 +160,8 @@ void FdbOrch::update(sai_fdb_event_t type, FdbUpdate update; update.entry.mac = entry->mac_address; update.entry.bv_id = entry->bv_id; + update.type = "dynamic"; + Port vlan; SWSS_LOG_INFO("FDB event:%d, MAC: %s , BVID: 0x%" PRIx64 " , \ bridge port ID: 0x%" PRIx64 ".", @@ -139,45 +179,168 @@ void FdbOrch::update(sai_fdb_event_t type, switch (type) { case SAI_FDB_EVENT_LEARNED: - if (!m_portsOrch->getPortByBridgePortId(bridge_port_id, update.port)) + { + 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("Failed to get port by bridge port ID 0x%" PRIx64, bridge_port_id); + SWSS_LOG_ERROR("FdbOrch LEARN notification: Failed to locate vlan port from bv_id 0x%" PRIx64, entry->bv_id); return; } // 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); + 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.entry.port_name = update.port.m_alias; + 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); + notify(SUBJECT_TYPE_FDB_CHANGE, &update); - SWSS_LOG_INFO("Notifying observers of FDB entry LEARN"); - for (auto observer: m_observers) + 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); + + if (!m_portsOrch->getPort(entry->bv_id, vlan)) { - observer->update(SUBJECT_TYPE_FDB_CHANGE, &update); + SWSS_LOG_NOTICE("FdbOrch AGE notification: Failed to locate vlan port from bv_id 0x%lx", entry->bv_id); } - break; + 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", + update.entry.mac.to_string().c_str(), entry->bv_id, bridge_port_id); + break; + } + + if (existing_entry->second.bridge_port_id != bridge_port_id) + { + SWSS_LOG_INFO("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); + // 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_INFO("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") + { + update.type = "static"; + + if (vlan.m_members.find(update.port.m_alias) == vlan.m_members.end()) + { + 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; + + 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_BRIDGE_PORT_ID; + attr.value.oid = bridge_port_id; + attrs.push_back(attr); + auto status = sai_fdb_api->create_fdb_entry(entry, (uint32_t)attrs.size(), attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + 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; + } + return; + } + } - case SAI_FDB_EVENT_AGED: - case SAI_FDB_EVENT_MOVE: update.add = false; + if (!update.port.m_alias.empty()) + { + update.port.m_fdb_count--; + m_portsOrch->setPort(update.port.m_alias, update.port); + } + if (!vlan.m_alias.empty()) + { + 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"); - for (auto observer: m_observers) + notify(SUBJECT_TYPE_FDB_CHANGE, &update); + + notifyTunnelOrch(update.port); + 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_ERROR("FdbOrch MOVE notification: Failed to locate vlan port from bv_id 0x%lx", entry->bv_id); + return; } - break; + // 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", + 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); + return; + } + update.add = true; + if (!port_old.m_alias.empty()) + { + 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); + + notifyTunnelOrch(port_old); + + break; + } case SAI_FDB_EVENT_FLUSHED: SWSS_LOG_INFO("FDB Flush event received: [ %s , 0x%" PRIx64 " ], \ @@ -212,8 +375,8 @@ void FdbOrch::update(sai_fdb_event_t type, 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.entry.mac = itr->first.mac; + update.entry.bv_id = itr->first.bv_id; update.add = false; itr++; @@ -235,10 +398,10 @@ void FdbOrch::update(sai_fdb_event_t type, for (auto itr = m_entries.begin(); itr != m_entries.end();) { auto next_item = std::next(itr); - if (itr->port_name == update.port.m_alias) + if (itr->first.port_name == update.port.m_alias) { - update.entry.mac = itr->mac; - update.entry.bv_id = itr->bv_id; + update.entry.mac = itr->first.mac; + update.entry.bv_id = itr->first.bv_id; update.add = false; storeFdbEntryState(update); @@ -342,6 +505,15 @@ void FdbOrch::doTask(Consumer& consumer) return; } + FdbOrigin origin = FDB_ORIGIN_PROVISIONED; + + string table_name = consumer.getTableName(); + if(table_name == APP_VXLAN_FDB_TABLE_NAME) + { + origin = FDB_ORIGIN_VXLAN_ADVERTIZED; + } + + auto it = consumer.m_toSync.begin(); while (it != consumer.m_toSync.end()) { @@ -355,7 +527,24 @@ void FdbOrch::doTask(Consumer& consumer) 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 */ + unsigned short vlan_id; + 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; } @@ -365,8 +554,12 @@ void FdbOrch::doTask(Consumer& consumer) 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)) { @@ -379,28 +572,74 @@ 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 */ assert(type == "dynamic" || type == "static"); - if (addFdbEntry(entry, type)) + 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)) 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)) it = consumer.m_toSync.erase(it); else it++; @@ -550,14 +789,14 @@ 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->first.port_name == port.m_alias) && + (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); } } @@ -613,102 +852,352 @@ void FdbOrch::updateVlanMember(const VlanMemberUpdate& update) string port_name = update.member.m_alias; 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()) { - // 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, fdb.type); + for (const auto& fdb: fdb_list) + { + // 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() + 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.fdbData); + } + else + { + saved_fdb_entries[port_name].push_back(fdb); + } + } } } -bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& type) +bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, + FdbData fdbData) { - SWSS_LOG_ENTER(); + Port vlan; + Port port; - sai_fdb_entry_t fdb_entry; + SWSS_LOG_ENTER(); + SWSS_LOG_INFO("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(), + fdbData.type.c_str(), fdbData.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(entry.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", - entry.port_name.c_str()); - saved_fdb_entries[entry.port_name].push_back({entry, type}); + 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; + } + /* Retry until port is member of vlan*/ + 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()); + saved_fdb_entries[port_name].push_back({entry.mac, + vlan.m_vlan_info.vlan_id, fdbData}); return true; } - /* Retry until port is added to the VLAN */ - if (!port.m_bridge_port_id) + 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()) { - SWSS_LOG_DEBUG("Saving a fdb entry until port %s has got a bridge port ID", - entry.port_name.c_str()); - saved_fdb_entries[entry.port_name].push_back({entry, type}); + /* get existing port and type */ + oldType = it->second.type; + oldOrigin = it->second.origin; - return true; + 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 == 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(), + fdbData.type.c_str(), fdbData.origin); + return true; + } + else if (fdbData.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, + fdbData.remote_ip.c_str()); + + return true; + } + 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 /* (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; } 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 (fdbData.origin == FDB_ORIGIN_VXLAN_ADVERTIZED) + { + attr.value.s32 = SAI_FDB_ENTRY_TYPE_STATIC; + } + else + { + attr.value.s32 = (fdbData.type == "dynamic") ? SAI_FDB_ENTRY_TYPE_DYNAMIC : SAI_FDB_ENTRY_TYPE_STATIC; + } attrs.push_back(attr); + if ((fdbData.origin == FDB_ORIGIN_VXLAN_ADVERTIZED) && (fdbData.type == "dynamic")) + { + 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); + if (fdbData.origin == FDB_ORIGIN_VXLAN_ADVERTIZED) + { + IpAddress remote = IpAddress(fdbData.remote_ip); + sai_ip_address_t ipaddr; + if (remote.isV4()) + { + ipaddr.addr_family = SAI_IP_ADDR_FAMILY_IPV4; + ipaddr.addr.ip4 = remote.getV4Addr(); + } + else + { + 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); + } - if (m_entries.count(entry) != 0) // we already have such entries + if (macUpdate && (oldOrigin == FDB_ORIGIN_VXLAN_ADVERTIZED)) { - removeFdbEntry(entry); + 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); + } } - sai_status_t 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); + 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 + { + 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()); - 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()); + 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); + 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 storeFdbData = fdbData; + storeFdbData.bridge_port_id = port.m_bridge_port_id; - (void) m_entries.insert(entry); + m_entries[entry] = storeFdbData; - 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 (fdbData.origin != FDB_ORIGIN_VXLAN_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 (fdbData.type == "dynamic_local") + fvs.push_back(FieldValueTuple("type", "dynamic")); + else + fvs.push_back(FieldValueTuple("type", fdbData.type)); + m_fdbStateTable.set(key, fvs); + } + else if (macUpdate && (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 + * in state-db + */ + m_fdbStateTable.del(key); } + if (!macUpdate) + { + gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); + } + + FdbUpdate update; + update.entry = entry; + update.port = port; + update.type = fdbData.type; + update.add = true; + + 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_INFO("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_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_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); + 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); + return false; + } + + if (fdbData.origin != origin) { - SWSS_LOG_ERROR("FDB entry isn't found. mac=%s bv_id=0x%" PRIx64 ".", - entry.mac.to_string().c_str(), entry.bv_id); + /* 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); + return true; } + string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string(); + sai_status_t status; sai_fdb_entry_t fdb_entry; fdb_entry.switch_id = gSwitchId; @@ -718,24 +1207,98 @@ bool FdbOrch::removeFdbEntry(const FdbEntry& entry) 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_INFO("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--; + m_portsOrch->setPort(vlan.m_alias, vlan); (void)m_entries.erase(entry); + // Remove in StateDb + if (fdbData.origin != FDB_ORIGIN_VXLAN_ADVERTIZED) + { + m_fdbStateTable.del(key); + } + gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_FDB_ENTRY); - Port port; - m_portsOrch->getPortByBridgePortId(entry.bv_id, port); + FdbUpdate update; + update.entry = entry; + update.port = port; + update.type = fdbData.type; + update.add = false; + + notify(SUBJECT_TYPE_FDB_CHANGE, &update); + + notifyTunnelOrch(update.port); + + return true; +} - SWSS_LOG_INFO("Notifying observers of FDB entry removal"); - FdbUpdate update = {entry, port, false}; - for (auto observer: m_observers) +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.fdbData.type = "static"; + /* Below members are unused during delete compare */ + entry.fdbData.origin = origin; + + for (auto& itr: saved_fdb_entries) { - observer->update(SUBJECT_TYPE_FDB_CHANGE, &update); + 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->fdbData.origin == origin) + { + 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()); + saved_fdb_entries[itr.first].erase(iter); + + found=true; + break; + } + else + { + 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, + iter->fdbData.origin, itr.first.c_str()); + } + } + iter++; + } + } + if (found) + break; } +} - return true; +// 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 874bf0229f..201493f574 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_VXLAN_ADVERTIZED = 4 +}; + struct FdbEntry { MacAddress mac; @@ -15,12 +23,17 @@ 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 FdbUpdate { FdbEntry entry; Port port; + string type; bool add; }; @@ -30,10 +43,35 @@ struct FdbFlushUpdate Port port; }; -struct SavedFdbEntry +struct FdbData { - FdbEntry entry; + 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; + unsigned short vlanId; + FdbData fdbData; + bool operator==(const SavedFdbEntry& other) const + { + return tie(mac, vlanId) == tie(other.mac, other.vlanId); + } }; typedef unordered_map> fdb_entries_by_port_t; @@ -42,7 +80,7 @@ class FdbOrch: public Orch, public Subject, public Observer { public: - FdbOrch(TableConnector applDbConnector, TableConnector stateDbConnector, PortsOrch *port); + FdbOrch(DBConnector* applDbConnector, vector appFdbTables, TableConnector stateDbFdbConnector, PortsOrch *port); ~FdbOrch() { @@ -53,15 +91,19 @@ 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 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&); private: PortsOrch *m_portsOrch; - set m_entries; + map m_entries; fdb_entries_by_port_t saved_fdb_entries; - Table m_table; + vector m_appTables; Table m_fdbStateTable; NotificationConsumer* m_flushNotificationsConsumer; NotificationConsumer* m_fdbNotificationConsumer; @@ -71,9 +113,12 @@ class FdbOrch: public Orch, public Subject, public Observer void updateVlanMember(const VlanMemberUpdate&); void updatePortOperState(const PortOperStateUpdate&); - bool addFdbEntry(const FdbEntry&, const string&); - bool removeFdbEntry(const FdbEntry&); + + 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/orchdaemon.cpp b/orchagent/orchdaemon.cpp index a1f77854e8..d0307a43e2 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -87,11 +87,15 @@ bool OrchDaemon::init() { APP_LAG_MEMBER_TABLE_NAME, portsorch_base_pri } }; + vector app_fdb_tables = { + { APP_FDB_TABLE_NAME, FdbOrch::fdborch_pri}, + { APP_VXLAN_FDB_TABLE_NAME, FdbOrch::fdborch_pri} + }; + gCrmOrch = new CrmOrch(m_configDb, CFG_CRM_TABLE_NAME); gPortsOrch = new PortsOrch(m_applDb, ports_tables); - TableConnector applDbFdb(m_applDb, APP_FDB_TABLE_NAME); TableConnector stateDbFdb(m_stateDb, STATE_FDB_TABLE_NAME); - gFdbOrch = new FdbOrch(applDbFdb, stateDbFdb, gPortsOrch); + gFdbOrch = new FdbOrch(m_applDb, app_fdb_tables, stateDbFdb, gPortsOrch); vector vnet_tables = { APP_VNET_RT_TABLE_NAME, diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index f806cad95f..5dd76f70b9 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -229,14 +229,13 @@ 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)); /* Initialize gearbox */ diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index 42cb7278b8..dfd5ab875d 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -96,6 +96,7 @@ class PortsOrch : public Orch, public Subject bool setHostIntfsOperStatus(const Port& port, bool up) const; void updateDbPortOperStatus(const Port& port, sai_port_oper_status_t status) const; + bool createBindAclTableGroup(sai_object_id_t port_oid, sai_object_id_t acl_table_oid, sai_object_id_t &group_oid, diff --git a/tests/conftest.py b/tests/conftest.py index fe86b58053..357cb4f15f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1079,6 +1079,24 @@ def setup_db(self): self.cdb = swsscommon.DBConnector(4, self.redis_sock, 0) self.sdb = swsscommon.DBConnector(6, self.redis_sock, 0) + def getSwitchOid(self): + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_SWITCH") + keys = tbl.getKeys() + return str(keys[0]) + + def getVlanOid(self, vlanId): + tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN") + vlan_oid = None + keys = tbl.getKeys() + for k in keys: + (status, fvs) = tbl.get(k) + assert status == True, "Could not read vlan from DB" + for fv in fvs: + if fv[0] == "SAI_VLAN_ATTR_VLAN_ID" and fv[1] == str(vlanId): + vlan_oid = str(k) + break + return vlan_oid + # deps: acl_portchannel, fdb def getCrmCounterValue(self, key, counter): counters_db = swsscommon.DBConnector(swsscommon.COUNTERS_DB, self.redis_sock, 0) diff --git a/tests/mock_tests/aclorch_ut.cpp b/tests/mock_tests/aclorch_ut.cpp index 5f71471a57..39ab3ce179 100644 --- a/tests/mock_tests/aclorch_ut.cpp +++ b/tests/mock_tests/aclorch_ut.cpp @@ -316,8 +316,13 @@ namespace aclorch_test TableConnector applDbFdb(m_app_db.get(), APP_FDB_TABLE_NAME); TableConnector stateDbFdb(m_state_db.get(), STATE_FDB_TABLE_NAME); + vector app_fdb_tables = { + { APP_FDB_TABLE_NAME, FdbOrch::fdborch_pri}, + { APP_VXLAN_FDB_TABLE_NAME, FdbOrch::fdborch_pri} + }; + ASSERT_EQ(gFdbOrch, nullptr); - gFdbOrch = new FdbOrch(applDbFdb, stateDbFdb, gPortsOrch); + gFdbOrch = new FdbOrch(m_app_db.get(), app_fdb_tables, stateDbFdb, gPortsOrch); ASSERT_EQ(gNeighOrch, nullptr); gNeighOrch = new NeighOrch(m_app_db.get(), APP_NEIGH_TABLE_NAME, gIntfsOrch, gFdbOrch, gPortsOrch); diff --git a/tests/test_evpn_fdb.py b/tests/test_evpn_fdb.py new file mode 100644 index 0000000000..0989815b9d --- /dev/null +++ b/tests/test_evpn_fdb.py @@ -0,0 +1,499 @@ +from swsscommon import swsscommon +import time + +def create_entry(tbl, key, pairs): + fvs = swsscommon.FieldValuePairs(pairs) + tbl.set(key, fvs) + + # FIXME: better to wait until DB create them + 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 how_many_entries_exist(db, table): + tbl = swsscommon.Table(db, table) + return len(tbl.getKeys()) + +def remove_mac(db, table, mac, vlan): + tbl = swsscommon.Table(db, table) + tbl._del("Vlan" + vlan + "|" + mac.lower()) + time.sleep(1) + +def delete_entry_tbl(db, table, key): + tbl = swsscommon.Table(db, table) + tbl._del(key) + time.sleep(1) + +def create_evpn_nvo(db, nvoname, tnlname): + #conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + attrs = [ + ("source_vtep", tnlname), + ] + + # create the VXLAN tunnel Term entry in Config DB + create_entry_tbl( + db, + "VXLAN_EVPN_NVO", nvoname, + attrs, + ) + +def remove_evpn_nvo(db, nvoname): + #conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + delete_entry_tbl(db,"VXLAN_EVPN_NVO", nvoname,) + +def create_vxlan_tunnel(db, name, src_ip): + #conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + attrs = [ + ("src_ip", src_ip), + ] + + # create the VXLAN tunnel Term entry in Config DB + create_entry_tbl( + db, + "VXLAN_TUNNEL", name, + attrs, + ) + +def remove_vxlan_tunnel(db, tnlname): + #conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + # create the VXLAN tunnel Term entry in Config DB + delete_entry_tbl( + db, + "VXLAN_TUNNEL", tnlname, + ) + +def create_vxlan_tunnel_map(db, tnlname, mapname, vni_id, vlan_id): + #conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + attrs = [ + ("vni", vni_id), + ("vlan", vlan_id), + ] + + # create the VXLAN tunnel Term entry in Config DB + create_entry_tbl( + db, + "VXLAN_TUNNEL_MAP", "%s|%s" % (tnlname, mapname), + attrs, + ) + +def remove_vxlan_tunnel_map(db, tnlname, mapname): + #conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + # create the VXLAN tunnel Term entry in Config DB + delete_entry_tbl( + db, + "VXLAN_TUNNEL_MAP", "%s|%s" % (tnlname, mapname), + ) + +def create_evpn_remote_vni(db, vlan_id, remotevtep, vnid): + #app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + create_entry_pst( + db, + "VXLAN_REMOTE_VNI_TABLE", "%s:%s" % (vlan_id, remotevtep), + [ + ("vni", vnid), + ], + ) + +def remove_evpn_remote_vni(db, vlan_id, remotevtep ): + #app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + delete_entry_pst( + db, + "VXLAN_REMOTE_VNI_TABLE", "%s:%s" % (vlan_id, remotevtep), + ) + +def get_vxlan_p2p_tunnel_bp(db, remote_ip): + tnl_id = None + bp = None + print("remote_ip = " + remote_ip) + attributes = [("SAI_TUNNEL_ATTR_TYPE", "SAI_TUNNEL_TYPE_VXLAN"), + ("SAI_TUNNEL_ATTR_ENCAP_DST_IP", remote_ip) + ] + tbl = swsscommon.Table(db, "ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL") + keys = tbl.getKeys() + for key in keys: + status, fvs = tbl.get(key) + assert status, "Error reading from table ASIC_STATE:SAI_OBJECT_TYPE_TUNNEL" + attrs = dict(attributes) + num_match = 0 + for k, v in fvs: + print("attr:value="+str(k)+":"+str(v)) + if k in attrs and attrs[k] == v: + num_match += 1 + if num_match == len(attributes): + tnl_id = str(key) + break + else: + tnl_id = None + + print("tnl_id = "+str(tnl_id)) + if tnl_id != None: + tbl = swsscommon.Table(db, "ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT") + keys = tbl.getKeys() + for key in keys: + status, fvs = tbl.get(key) + assert status, "Error reading from table ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT" + for k, v in fvs: + print("attr:value="+str(k)+":"+str(v)) + if k == "SAI_BRIDGE_PORT_ATTR_TUNNEL_ID" and tnl_id == v: + bp = key + break + if bp != None: + break + else: + pass + print("bp = "+str(bp)) + return bp + + +def test_evpnFdb(dvs, testlog): + dvs.setup_db() + + dvs.runcmd("sonic-clear fdb all") + time.sleep(2) + + #Find switch_id + switch_id = dvs.getSwitchOid() + print("Switch_id="+str(switch_id)) + + vlan_before = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN") + + # create vlan + print("Creating Vlan3") + #dvs.runcmd("config vlan add 3") + dvs.create_vlan("3") + time.sleep(2) + + vlan_after = how_many_entries_exist(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN") + assert vlan_after - vlan_before == 1, "The Vlan3 wasn't created" + print("Vlan3 is created") + + # Find the vlan_oid to be used in DB communications + vlan_oid_3 = dvs.getVlanOid("3") + assert vlan_oid_3 is not None, "Could not find Vlan_oid" + print("Vlan-3 vlan_oid="+str(vlan_oid_3)) + + 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") + + print("Making Ethernet0 as a member of Vlan3") + #dvs.runcmd("config vlan member add 3 Ethernet0") + dvs.create_vlan_member("3", "Ethernet0") + time.sleep(2) + + # check that the vlan information was propagated + 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 bp_after - bp_before == 1, "The bridge port wasn't created" + assert vm_after - vm_before == 1, "The vlan member wasn't added" + print("Ethernet0 is a member of Vlan3") + + # Get mapping between interface name and its bridge port_id + iface_2_bridge_port_id = dvs.get_map_iface_bridge_port_id(dvs.adb) + + #create SIP side of tunnel + source_tnl_name = "source_vtep_name" + source_tnl_ip = "7.7.7.7" + create_vxlan_tunnel(dvs.cdb, source_tnl_name, source_tnl_ip) + time.sleep(1) + + + nvo_name = "evpn_nvo" + create_evpn_nvo(dvs.cdb, nvo_name, source_tnl_name) + time.sleep(1) + + + map_name_vlan_3 = "map_3_3" + create_vxlan_tunnel_map(dvs.cdb, source_tnl_name, map_name_vlan_3, "3", "Vlan3") + time.sleep(1) + + + remote_ip_6 = "6.6.6.6" + create_evpn_remote_vni(dvs.pdb, "Vlan3", remote_ip_6, "3") + remote_ip_8 = "8.8.8.8" + create_evpn_remote_vni(dvs.pdb, "Vlan3", remote_ip_8, "3") + time.sleep(1) + + #UT-1 Evpn Mac add from remote when tunnels are already created + mac = "52:54:00:25:06:E9" + print("Creating Evpn FDB Vlan3:"+mac.lower()+":6.6.6.6 in APP-DB") + create_entry_pst( + dvs.pdb, + "VXLAN_FDB_TABLE", "Vlan3:"+mac.lower(), + [ + ("remote_vtep", remote_ip_6), + ("type", "dynamic"), + ("vni", "3") + ] + ) + time.sleep(1) + + tnl_bp_oid_6 = get_vxlan_p2p_tunnel_bp(dvs.adb, remote_ip_6) + + # check that the FDB entry is inserted into ASIC DB + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", mac), ("bvid", vlan_oid_3)], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), + ("SAI_FDB_ENTRY_ATTR_ENDPOINT_IP", remote_ip_6), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", str(tnl_bp_oid_6)), + ] + ) + assert ok == True, str(extra) + print("EVPN FDB Vlan3:"+mac.lower()+":"+remote_ip_6+" is created in ASIC-DB") + + time.sleep(1) + + #UT-2 Evpn Mac del from remote + mac = "52:54:00:25:06:E9" + print("Deleting Evpn FDB Vlan3:"+mac.lower()+":6.6.6.6 in APP-DB") + delete_entry_pst( + dvs.pdb, + "VXLAN_FDB_TABLE", "Vlan3:"+mac.lower() + ) + time.sleep(1) + + # check that the FDB entry is deleted from ASIC DB + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", mac), ("bvid", vlan_oid_3)], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), + ("SAI_FDB_ENTRY_ATTR_ENDPOINT_IP", remote_ip_6), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", str(tnl_bp_oid_6)), + ] + ) + assert ok == False, str(extra) + print("EVPN FDB Vlan3:"+mac.lower()+":"+remote_ip_6+" is deleted from ASIC-DB") + + time.sleep(1) + + #UT-3 Evpn Mac add from remote when local mac is already present + mac = "52:54:00:25:06:E9" + + print("Creating Local dynamic FDB Vlan3:"+mac.lower()+":Ethernet0 in APP-DB") + # Create Dynamic MAC entry in APP DB + create_entry_pst( + dvs.pdb, + "FDB_TABLE", "Vlan3:"+mac.lower(), + [ + ("port", "Ethernet0"), + ("type", "dynamic"), + ] + ) + + time.sleep(1) + #raw_input("Check ASIC_DB.........") + + # check that the FDB entry was added in ASIC DB + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", mac), ("bvid", vlan_oid_3)], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC"), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", iface_2_bridge_port_id["Ethernet0"])] + ) + assert ok, str(extra) + print("Dynamic FDB Vlan3:"+mac.lower()+":Ethernet0 is created in Asic-DB") + + # check that the FDB entry was added in STATE DB + mac1_found, extra = dvs.is_table_entry_exists(dvs.sdb, "FDB_TABLE", + "Vlan3:"+mac.lower(), + [("port", "Ethernet0"), + ("type", "dynamic"), + ] + ) + assert mac1_found, str(extra) + print("FDB Vlan3:"+mac+":Ethernet0 is created in STATE-DB") + + print("Creating Evpn FDB Vlan3:"+mac.lower()+":6.6.6.6 in APP-DB") + create_entry_pst( + dvs.pdb, + "VXLAN_FDB_TABLE", "Vlan3:"+mac.lower(), + [ + ("remote_vtep", remote_ip_6), + ("type", "dynamic"), + ("vni", "3") + ] + ) + time.sleep(1) + + + # check that the FDB entry is inserted into ASIC DB + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", mac), ("bvid", str(dvs.getVlanOid("3")))], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), + ("SAI_FDB_ENTRY_ATTR_ENDPOINT_IP", remote_ip_6), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", str(tnl_bp_oid_6)), + ] + ) + assert ok, str(extra) + print("EVPN FDB Vlan3:"+mac.lower()+":"+remote_ip_6+" is created in ASIC-DB") + + # check that the Local FDB entry is deleted from STATE DB + mac1_found, extra = dvs.is_table_entry_exists(dvs.sdb, "FDB_TABLE", + "Vlan3:"+mac.lower(), + [("port", "Ethernet0"), + ("type", "dynamic"), + ] + ) + assert mac1_found == False, str(extra) + print("FDB Vlan3:"+mac+":Ethernet0 is deleted from STATE-DB") + + time.sleep(1) + + + #UT-4 Evpn Sticky Mac add from remote + mac = "52:54:00:25:06:E9" + print("Creating Evpn Sticky FDB Vlan3:"+mac.lower()+":6.6.6.6 in APP-DB") + create_entry_pst( + dvs.pdb, + "VXLAN_FDB_TABLE", "Vlan3:"+mac.lower(), + [ + ("remote_vtep", remote_ip_6), + ("type", "static"), + ("vni", "3") + ] + ) + time.sleep(1) + + + # check that the FDB entry is inserted into ASIC DB + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", mac), ("bvid", str(dvs.getVlanOid("3")))], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_ENDPOINT_IP", remote_ip_6), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", str(tnl_bp_oid_6)), + ] + ) + assert ok, str(extra) + print("EVPN Sticky FDB Vlan3:"+mac.lower()+":"+remote_ip_6+" is created in ASIC-DB") + + #raw_input("Check ASIC_DB.........") + + #UT-8 Evpn Mac add from remote when tunnels are already created + mac = "52:54:00:25:06:E9" + print("Creating Evpn FDB Vlan3:"+mac.lower()+":6.6.6.6 in APP-DB") + create_entry_pst( + dvs.pdb, + "VXLAN_FDB_TABLE", "Vlan3:"+mac.lower(), + [ + ("remote_vtep", remote_ip_6), + ("type", "dynamic"), + ("vni", "3") + ] + ) + time.sleep(1) + + #raw_input("Check ASIC_DB.........") + + # check that the FDB entry is inserted into ASIC DB + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", mac), ("bvid", vlan_oid_3)], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), + ("SAI_FDB_ENTRY_ATTR_ENDPOINT_IP", remote_ip_6), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", str(tnl_bp_oid_6)), + ] + ) + assert ok == True, str(extra) + print("EVPN FDB Vlan3:"+mac.lower()+":"+remote_ip_6+" is created in ASIC-DB") + + time.sleep(1) + + tnl_bp_oid_8 = get_vxlan_p2p_tunnel_bp(dvs.adb, remote_ip_8) + + print("Creating Evpn FDB Vlan3:"+mac.lower()+":8.8.8.8 in APP-DB") + create_entry_pst( + dvs.pdb, + "VXLAN_FDB_TABLE", "Vlan3:"+mac.lower(), + [ + ("remote_vtep", remote_ip_8), + ("type", "dynamic"), + ("vni", "3") + ] + ) + time.sleep(1) + + #raw_input("Check ASIC_DB.........") + + # check that the FDB entry is inserted into ASIC DB + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", mac), ("bvid", vlan_oid_3)], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_STATIC"), + ("SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE", "true"), + ("SAI_FDB_ENTRY_ATTR_ENDPOINT_IP", remote_ip_8), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", str(tnl_bp_oid_8)), + ] + ) + assert ok == True, str(extra) + print("EVPN FDB Vlan3:"+mac.lower()+":"+remote_ip_8+" is created in ASIC-DB") + + time.sleep(1) + + #UT-9 Local mac move (delete and learn) when remote is already added + mac = "52:54:00:25:06:E9" + print("Deleting FDB Vlan3:52-54-00-25-06-E9:8.8.8.8 in ASIC-DB") + delete_entry_tbl(dvs.adb, "ASIC_STATE", "SAI_OBJECT_TYPE_FDB_ENTRY:{\"bvid\":\""+vlan_oid_3+"\",\"mac\":\""+mac+"\",\"switch_id\":\""+switch_id+"\"}") + + ntf = swsscommon.NotificationProducer(dvs.adb, "NOTIFICATIONS") + fvp = swsscommon.FieldValuePairs() + ntf_data = "[{\"fdb_entry\":\"{\\\"bvid\\\":\\\""+vlan_oid_3+"\\\",\\\"mac\\\":\\\""+mac+"\\\",\\\"switch_id\\\":\\\""+switch_id+"\\\"}\",\"fdb_event\":\"SAI_FDB_EVENT_AGED\",\"list\":[{\"id\":\"SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID\",\"value\":\""+str(tnl_bp_oid_8)+"\"}]}]" + ntf.send("fdb_event", ntf_data, fvp) + + time.sleep(2) + + #raw_input("Check ASIC_DB.........") + + print("Creating FDB Vlan3:52-54-00-25-06-E9:Ethernet0 in ASIC-DB") + create_entry_tbl( + dvs.adb, + "ASIC_STATE", "SAI_OBJECT_TYPE_FDB_ENTRY:{\"bvid\":\""+vlan_oid_3+"\",\"mac\":\"52:54:00:25:06:E9\",\"switch_id\":\""+switch_id+"\"}", + [ + ("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC"), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", iface_2_bridge_port_id["Ethernet0"]), + ] + ) + + ntf = swsscommon.NotificationProducer(dvs.adb, "NOTIFICATIONS") + fvp = swsscommon.FieldValuePairs() + ntf_data = "[{\"fdb_entry\":\"{\\\"bvid\\\":\\\""+vlan_oid_3+"\\\",\\\"mac\\\":\\\"52:54:00:25:06:E9\\\",\\\"switch_id\\\":\\\""+switch_id+"\\\"}\",\"fdb_event\":\"SAI_FDB_EVENT_LEARNED\",\"list\":[{\"id\":\"SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID\",\"value\":\""+iface_2_bridge_port_id["Ethernet0"]+"\"}]}]" + ntf.send("fdb_event", ntf_data, fvp) + + time.sleep(2) + + #raw_input("Check ASIC_DB.........") + + # check that the FDB entry was added in ASIC DB + ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", + [("mac", "52:54:00:25:06:E9"), ("bvid", vlan_oid_3)], + [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC"), + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", iface_2_bridge_port_id["Ethernet0"])] + ) + assert ok, str(extra) + print("FDB Vlan3:52-54-00-25-06-E9:Ethernet0 is created in ASIC-DB") + + # check that the FDB entry was added in STATE DB + mac1_found, extra = dvs.is_table_entry_exists(dvs.sdb, "FDB_TABLE", + "Vlan3:52:54:00:25:06:e9", + [("port", "Ethernet0"), + ("type", "dynamic"), + ] + ) + assert mac1_found, str(extra) + print("FDB Vlan3:52-54-00-25-06-E9:Ethernet0 is created in STATE-DB") + + + dvs.remove_vlan_member("3", "Ethernet0") + dvs.remove_vlan("3") diff --git a/tests/test_fdb.py b/tests/test_fdb.py index 1f46727f0d..9893a4e3b0 100644 --- a/tests/test_fdb.py +++ b/tests/test_fdb.py @@ -374,9 +374,7 @@ def test_FdbAddedAfterMemberCreated(self, dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "52:54:00:25:06:E9"), ("bvid", bvid)], [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC"), - ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", iface_2_bridge_port_id["Ethernet0"]), - ('SAI_FDB_ENTRY_ATTR_PACKET_ACTION', 'SAI_PACKET_ACTION_FORWARD')] - ) + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", iface_2_bridge_port_id["Ethernet0"])]) assert ok, str(extra) dvs.runcmd("sonic-clear fdb all") diff --git a/tests/test_fdb_update.py b/tests/test_fdb_update.py index 2c8e9b0c8e..5daf27804e 100644 --- a/tests/test_fdb_update.py +++ b/tests/test_fdb_update.py @@ -117,8 +117,7 @@ def test_FDBAddedAndUpdated(self, dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "52:54:00:25:06:E9"), ("bvid", bvid)], [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC"), - ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", iface_2_bridge_port_id["Ethernet0"]), - ('SAI_FDB_ENTRY_ATTR_PACKET_ACTION', 'SAI_PACKET_ACTION_FORWARD')]) + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", iface_2_bridge_port_id["Ethernet0"])]) assert ok, str(extra) # create vlan member entry in Config DB @@ -146,8 +145,7 @@ def test_FDBAddedAndUpdated(self, dvs, testlog): ok, extra = dvs.is_fdb_entry_exists(dvs.adb, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY", [("mac", "52:54:00:25:06:E9"), ("bvid", bvid)], [("SAI_FDB_ENTRY_ATTR_TYPE", "SAI_FDB_ENTRY_TYPE_DYNAMIC"), - ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", iface_2_bridge_port_id["Ethernet4"]), - ('SAI_FDB_ENTRY_ATTR_PACKET_ACTION', 'SAI_PACKET_ACTION_FORWARD')]) + ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", iface_2_bridge_port_id["Ethernet4"])]) assert ok, str(extra) # remove FDB entry from Application DB diff --git a/tests/test_fdbsync.py b/tests/test_fdbsync.py index ee86c8616d..8d85e8458e 100644 --- a/tests/test_fdbsync.py +++ b/tests/test_fdbsync.py @@ -58,7 +58,7 @@ def set_admin_status(dvs, interface, status): local_intf = 'Ethernet8' local_intf2 = 'Ethernet12' tunnel_name_nvo = 'nvo' -app_fdb_name = '_VXLAN_FDB_TABLE:' +app_fdb_name = 'VXLAN_FDB_TABLE:' tunnel_remote_imet = '00:00:00:00:00:00' tunnel_remote_imet_type = 'permanent' app_imet_name = 'VXLAN_REMOTE_VNI_TABLE:'