diff --git a/cfgmgr/vlanmgr.cpp b/cfgmgr/vlanmgr.cpp index 7d7a59abeb..509fbea47e 100644 --- a/cfgmgr/vlanmgr.cpp +++ b/cfgmgr/vlanmgr.cpp @@ -13,10 +13,12 @@ using namespace swss; #define DOT1Q_BRIDGE_NAME "Bridge" #define VLAN_PREFIX "Vlan" +#define SWITCH_STR "switch" #define LAG_PREFIX "PortChannel" #define DEFAULT_VLAN_ID "1" #define DEFAULT_MTU_STR "9100" #define VLAN_HLEN 4 +#define MAX_VLAN_ID 4095 extern MacAddress gMacAddress; @@ -28,6 +30,8 @@ VlanMgr::VlanMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, c m_stateLagTable(stateDb, STATE_LAG_TABLE_NAME), m_stateVlanTable(stateDb, STATE_VLAN_TABLE_NAME), m_stateVlanMemberTable(stateDb, STATE_VLAN_MEMBER_TABLE_NAME), + m_appFdbTableProducer(appDb, APP_FDB_TABLE_NAME), + m_appSwitchTableProducer(appDb, APP_SWITCH_TABLE_NAME), m_appVlanTableProducer(appDb, APP_VLAN_TABLE_NAME), m_appVlanMemberTableProducer(appDb, APP_VLAN_MEMBER_TABLE_NAME) { @@ -88,6 +92,10 @@ VlanMgr::VlanMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, c EXEC_WITH_ERROR_THROW(echo_cmd_backup, res); } + /* vlan state notification from portsorch */ + m_VlanStateNotificationConsumer = new swss::NotificationConsumer(appDb, "VLANSTATE"); + auto vlanStatusNotificatier = new Notifier(m_VlanStateNotificationConsumer, this, "VLANSTATE"); + Orch::addExecutor(vlanStatusNotificatier); } bool VlanMgr::addHostVlan(int vlan_id) @@ -101,7 +109,7 @@ bool VlanMgr::addHostVlan(int vlan_id) + BASH_CMD + " -c \"" + BRIDGE_CMD + " vlan add vid " + std::to_string(vlan_id) + " dev " + DOT1Q_BRIDGE_NAME + " self && " + IP_CMD + " link add link " + DOT1Q_BRIDGE_NAME - + " up" + + " down" + " name " + VLAN_PREFIX + std::to_string(vlan_id) + " address " + gMacAddress.to_string() + " type vlan id " + std::to_string(vlan_id) + "\""; @@ -179,14 +187,29 @@ bool VlanMgr::addHostVlanMember(int vlan_id, const string &port_alias, const str // /bin/bash -c "/sbin/ip link set {{port_alias}} master Bridge && // /sbin/bridge vlan del vid 1 dev {{ port_alias }} && // /sbin/bridge vlan add vid {{vlan_id}} dev {{port_alias}} {{tagging_mode}}" - ostringstream cmds, inner; - inner << IP_CMD " link set " << shellquote(port_alias) << " master " DOT1Q_BRIDGE_NAME " && " - BRIDGE_CMD " vlan del vid " DEFAULT_VLAN_ID " dev " << shellquote(port_alias) << " && " - BRIDGE_CMD " vlan add vid " + std::to_string(vlan_id) + " dev " << shellquote(port_alias) << " " + tagging_cmd; - cmds << BASH_CMD " -c " << shellquote(inner.str()); + + const std::string key = std::string("") + "Vlan1|" + port_alias; - std::string res; - EXEC_WITH_ERROR_THROW(cmds.str(), res); + if (isVlanMemberStateOk(key)) { + ostringstream cmds, inner; + inner << IP_CMD " link set " << shellquote(port_alias) << " master " DOT1Q_BRIDGE_NAME " && " + BRIDGE_CMD " vlan add vid " + std::to_string(vlan_id) + " dev " << shellquote(port_alias) << " " + tagging_cmd; + cmds << BASH_CMD " -c " << shellquote(inner.str()); + + std::string res; + EXEC_WITH_ERROR_THROW(cmds.str(), res); + } + else + { + ostringstream cmds, inner; + inner << IP_CMD " link set " << shellquote(port_alias) << " master " DOT1Q_BRIDGE_NAME " && " + BRIDGE_CMD " vlan del vid " DEFAULT_VLAN_ID " dev " << shellquote(port_alias) << " && " + BRIDGE_CMD " vlan add vid " + std::to_string(vlan_id) + " dev " << shellquote(port_alias) << " " + tagging_cmd; + cmds << BASH_CMD " -c " << shellquote(inner.str()); + + std::string res; + EXEC_WITH_ERROR_THROW(cmds.str(), res); + } return true; } @@ -224,6 +247,137 @@ bool VlanMgr::isVlanMacOk() return !!gMacAddress; } +void VlanMgr::doSwitchTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + auto it = consumer.m_toSync.begin(); + + while (it != consumer.m_toSync.end()) + { + KeyOpFieldsValuesTuple t = it->second; + + string key = kfvKey(t); + string op = kfvOp(t); + + /* Ensure the key starts with "switch" otherwise ignore */ + if (key != SWITCH_STR) + { + SWSS_LOG_NOTICE("Ignoring SWITCH key %s", key.c_str()); + it = consumer.m_toSync.erase(it); + continue; + } + + SWSS_LOG_DEBUG("key:switch"); + + for (auto i : kfvFieldsValues(t)) + { + if (fvField(i) == "fdb_aging_time") + { + long agingTime = 0; + SWSS_LOG_DEBUG("attribute:fdb_aging_time"); + if (op == SET_COMMAND) + { + SWSS_LOG_DEBUG("operation:set"); + agingTime = strtol(fvValue(i).c_str(), NULL, 0); + if (agingTime < 0) + { + SWSS_LOG_ERROR("Invalid fdb_aging_time %s", fvValue(i).c_str()); + break; + } + SWSS_LOG_DEBUG("value:%s",fvValue(i).c_str()); + } + else if (op == DEL_COMMAND) + { + SWSS_LOG_DEBUG("operation:del"); + agingTime = 0; + } + else + { + SWSS_LOG_ERROR("Unknown operation type %s", op.c_str()); + break; + } + + vector fvVector; + FieldValueTuple aging_time("fdb_aging_time", to_string(agingTime)); + fvVector.push_back(aging_time); + m_appSwitchTableProducer.set(key, fvVector); + break; + } + } + + it = consumer.m_toSync.erase(it); + } +} + +void VlanMgr::doFdbTask(Consumer &consumer) +{ + auto it = consumer.m_toSync.begin(); + + while (it != consumer.m_toSync.end()) + { + KeyOpFieldsValuesTuple t = it->second; + + /* format: | */ + vector keys = tokenize(kfvKey(t), config_db_key_delimiter, 1); + /* keys[0] is vlan as (Vlan10) and keys[1] is mac as (00-00-00-00-00-00) */ + string op = kfvOp(t); + + /* Ensure the key starts with "Vlan" otherwise ignore */ + if (strncmp(keys[0].c_str(), VLAN_PREFIX, 4)) + { + SWSS_LOG_ERROR("Invalid key format. No 'Vlan' prefix: %s", keys[0].c_str()); + it = consumer.m_toSync.erase(it); + continue; + } + + unsigned long vlan_id; + vlan_id = strtoul(keys[0].substr(strlen(VLAN_PREFIX)).c_str(), NULL, 0); + + if ((vlan_id <= 0) || (vlan_id > MAX_VLAN_ID)) + { + SWSS_LOG_ERROR("Invalid key format. Vlan is out of range: %s", keys[0].c_str()); + it = consumer.m_toSync.erase(it); + continue; + } + + MacAddress mac = MacAddress(keys[1]); + + string key = VLAN_PREFIX + to_string(vlan_id); + key += DEFAULT_KEY_SEPARATOR; + key += mac.to_string(); + + if (op == SET_COMMAND) + { + string port; + for (auto i : kfvFieldsValues(t)) + { + if (fvField(i) == "port") + { + port = fvValue(i); + break; + } + } + + vector fvVector; + FieldValueTuple p("port", port); + fvVector.push_back(p); + FieldValueTuple t("type", "static"); + fvVector.push_back(t); + + m_appFdbTableProducer.set(key, fvVector); + } + else if (op == DEL_COMMAND) + { + m_appFdbTableProducer.del(key); + } + else + { + SWSS_LOG_ERROR("Unknown operation type %s", op.c_str()); + } + it = consumer.m_toSync.erase(it); + } +} + void VlanMgr::doVlanTask(Consumer &consumer) { if (!isVlanMacOk()) @@ -296,12 +450,12 @@ void VlanMgr::doVlanTask(Consumer &consumer) { /* Set vlan admin status */ if (fvField(i) == "admin_status") - { - admin_status = fvValue(i); - setHostVlanAdminState(vlan_id, admin_status); - fvVector.push_back(i); - } - /* Set vlan mtu */ + { + admin_status = fvValue(i); + setHostVlanAdminState(vlan_id, admin_status); + fvVector.push_back(i); + } + /* Set vlan mtu */ else if (fvField(i) == "mtu") { mtu = fvValue(i); @@ -593,9 +747,47 @@ void VlanMgr::doTask(Consumer &consumer) { doVlanMemberTask(consumer); } + else if (table_name == CFG_FDB_TABLE_NAME) + { + doFdbTask(consumer); + } + else if (table_name == CFG_SWITCH_TABLE_NAME) + { + SWSS_LOG_DEBUG("Table:SWITCH"); + doSwitchTask(consumer); + } else { SWSS_LOG_ERROR("Unknown config table %s ", table_name.c_str()); throw runtime_error("VlanMgr doTask failure."); } } + +void VlanMgr::doTask(NotificationConsumer &consumer) +{ + std::string op; + std::string data; + std::vector values; + + if (&consumer != m_VlanStateNotificationConsumer) + { + SWSS_LOG_WARN("received incorrect notification message"); + return; + } + + consumer.pop(op, data, values); + + unsigned long vlan_id = strtoul(data.substr(strlen(VLAN_PREFIX)).c_str(), NULL, 0); + + SWSS_LOG_NOTICE("vlanmgr received port status notification state %s vlan %s", + op.c_str(), data.c_str()); + + if (isVlanStateOk(data)) + { + setHostVlanAdminState((int)vlan_id, op); + } + else + { + SWSS_LOG_ERROR("received state update for vlan %s not existing", data.c_str()); + } +} diff --git a/cfgmgr/vlanmgr.h b/cfgmgr/vlanmgr.h index 469f16ccaf..861254e36c 100644 --- a/cfgmgr/vlanmgr.h +++ b/cfgmgr/vlanmgr.h @@ -4,6 +4,7 @@ #include "dbconnector.h" #include "producerstatetable.h" #include "orch.h" +#include "notifier.h" #include #include @@ -19,14 +20,20 @@ class VlanMgr : public Orch private: ProducerStateTable m_appVlanTableProducer, m_appVlanMemberTableProducer; + ProducerStateTable m_appFdbTableProducer; + ProducerStateTable m_appSwitchTableProducer; Table m_cfgVlanTable, m_cfgVlanMemberTable; Table m_statePortTable, m_stateLagTable; Table m_stateVlanTable, m_stateVlanMemberTable; std::set m_vlans; + NotificationConsumer* m_VlanStateNotificationConsumer; void doTask(Consumer &consumer); + void doTask(NotificationConsumer &consumer); void doVlanTask(Consumer &consumer); void doVlanMemberTask(Consumer &consumer); + void doFdbTask(Consumer &consumer); + void doSwitchTask(Consumer &consumer); void processUntaggedVlanMembers(std::string vlan, const std::string &members); bool addHostVlan(int vlan_id); diff --git a/cfgmgr/vlanmgrd.cpp b/cfgmgr/vlanmgrd.cpp index 88e4745758..23d25df819 100644 --- a/cfgmgr/vlanmgrd.cpp +++ b/cfgmgr/vlanmgrd.cpp @@ -51,6 +51,8 @@ int main(int argc, char **argv) vector cfg_vlan_tables = { CFG_VLAN_TABLE_NAME, CFG_VLAN_MEMBER_TABLE_NAME, + CFG_FDB_TABLE_NAME, + CFG_SWITCH_TABLE_NAME, }; DBConnector cfgDb("CONFIG_DB", 0); diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index 00301d511e..4321d1965b 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -469,7 +469,7 @@ bool FdbOrch::getPort(const MacAddress& mac, uint16_t vlan, Port& port) 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%" PRIx64, bridge_port_id); return false; } @@ -866,7 +866,7 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const attr.id = SAI_FDB_ENTRY_ATTR_TYPE; if (origin == FDB_ORIGIN_VXLAN_ADVERTIZED) { - 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 { @@ -874,6 +874,13 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const } attrs.push_back(attr); + if ((origin == FDB_ORIGIN_VXLAN_ADVERTIZED) && (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); @@ -896,7 +903,9 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const attr.value.ipaddr = ipaddr; attrs.push_back(attr); } - else if(macUpdate && (oldOrigin == FDB_ORIGIN_VXLAN_ADVERTIZED) && (origin != oldOrigin)) + else if(macUpdate + && (oldOrigin == FDB_ORIGIN_VXLAN_ADVERTIZED) + && (origin != oldOrigin)) { /* origin is changed from Remote-advertized to Local-provisioned * Remove the end-point ip attribute from fdb entry @@ -909,7 +918,16 @@ bool FdbOrch::addFdbEntry(const FdbEntry& entry, const string& port_name, const attrs.push_back(attr); } - string key = "Vlan" + to_string(vlan.m_vlan_info.vlan_id) + ":" + entry.mac.to_string(); + if(macUpdate && (oldOrigin == FDB_ORIGIN_VXLAN_ADVERTIZED)) + { + if((origin != oldOrigin) + || ((oldType == "dynamic") && (oldType != type))) + { + attr.id = SAI_FDB_ENTRY_ATTR_ALLOW_MAC_MOVE; + attr.value.booldata = false; + attrs.push_back(attr); + } + } if(macUpdate) diff --git a/orchagent/port.h b/orchagent/port.h index 74f805ddec..26d0bcc4c8 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; }; @@ -82,6 +83,7 @@ class Port sai_port_fec_mode_t m_fec_mode = SAI_PORT_FEC_MODE_NONE; VlanInfo m_vlan_info; 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; @@ -102,6 +104,9 @@ class Port uint8_t m_pfc_bitmask = 0; uint32_t m_nat_zone_id = 0; + uint32_t m_fdb_count = 0; + uint32_t m_up_member_count = 0; + /* * Following two bit vectors are used to lock * the PG/queue from being changed in BufferOrch. diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 5ceed76760..bfffa4614e 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -25,6 +25,7 @@ #include "crmorch.h" #include "countercheckorch.h" #include "notifier.h" +#include "fdborch.h" #include "redisclient.h" extern sai_switch_api_t *sai_switch_api; @@ -41,6 +42,8 @@ extern IntfsOrch *gIntfsOrch; extern NeighOrch *gNeighOrch; extern CrmOrch *gCrmOrch; extern BufferOrch *gBufferOrch; +extern FdbOrch *gFdbOrch; + #define VLAN_PREFIX "Vlan" #define DEFAULT_VLAN_ID 1 @@ -202,15 +205,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")); @@ -231,6 +234,7 @@ PortsOrch::PortsOrch(DBConnector *db, vector &tableNames) m_flexCounterGroupTable = unique_ptr(new ProducerTable(m_flex_db.get(), FLEX_COUNTER_GROUP_TABLE)); initGearbox(); + notifications = new swss::NotificationProducer(db, "VLANSTATE"); string queueWmSha, pgWmSha; string queueWmPluginName = "watermark_queue.lua"; @@ -365,7 +369,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(); @@ -387,7 +403,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); @@ -546,34 +562,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 = m_portOidToName.find(id); + if (itr == m_portOidToName.end()) + return false; + else { + getPort(itr->second, port); + return true; } return false; @@ -595,13 +589,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 = m_portOidToName.find(bridge_port_id); + if (itr == m_portOidToName.end()) + return false; + else { + getPort(itr->second, port); + return true; } return false; @@ -1735,6 +1728,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(); @@ -1838,8 +1846,9 @@ bool PortsOrch::initPort(const string &alias, const int index, const set &l /* Add port to port list */ m_portList[alias] = p; - m_port_ref_count[alias] = 0; m_portOidToIndex[id] = index; + m_portOidToName[id] = alias; + m_port_ref_count[alias] = 0; /* Add port name map to counter table */ FieldValueTuple tuple(p.m_alias, sai_serialize_object_id(p.m_port_id)); @@ -2767,24 +2776,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) && port.m_vlan_members.empty()) + { + ret = removeBridgePort(port); + } + if (ret) + { it = consumer.m_toSync.erase(it); + } + else + { + it++; + } } else { @@ -2810,6 +2818,7 @@ void PortsOrch::doLagTask(Consumer &consumer) { // Retrieve attributes uint32_t mtu = 0; + string learn_mode; bool operation_status_changed = false; string operation_status; @@ -2846,15 +2855,7 @@ void PortsOrch::doLagTask(Consumer &consumer) } } - // Create a new LAG when the new alias comes - if (m_portList.find(alias) == m_portList.end()) - { - if (!addLag(alias)) - { - it++; - continue; - } - } + auto status = addLag(alias); // Process attributes Port l; @@ -2864,7 +2865,6 @@ void PortsOrch::doLagTask(Consumer &consumer) } else { - if (!operation_status.empty()) { l.m_oper_status = string_oper_status.at(operation_status); @@ -2877,7 +2877,7 @@ void PortsOrch::doLagTask(Consumer &consumer) update.operStatus = string_oper_status.at(operation_status); notify(SUBJECT_TYPE_PORT_OPER_STATE_CHANGE, static_cast(&update)); } - if (mtu != 0) + if ((mtu != 0) && (mtu != l.m_mtu)) { l.m_mtu = mtu; m_portList[alias] = l; @@ -2887,6 +2887,9 @@ void PortsOrch::doLagTask(Consumer &consumer) } } + sai_port_oper_status_t status = (operation_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) @@ -2913,8 +2916,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) { @@ -3336,8 +3346,44 @@ 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 (port.m_vlan_members.empty()) + { + if (port.m_fdb_count > 0) + { + return false; + } + 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; } @@ -3390,6 +3436,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)) { @@ -3398,11 +3451,13 @@ bool PortsOrch::addBridgePort(Port &port) return false; } m_portList[port.m_alias] = port; + m_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(); @@ -3411,34 +3466,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; } /* 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; } + m_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()); @@ -3491,7 +3557,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) { @@ -3506,6 +3582,7 @@ bool PortsOrch::addVlan(string vlan_alias) vlan.m_vlan_info.vlan_id = vlan_id; vlan.m_members = set(); m_portList[vlan_alias] = vlan; + m_portOidToName[vlan_oid] = vlan_alias; m_port_ref_count[vlan_alias] = 0; return true; @@ -3514,6 +3591,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", @@ -3521,6 +3599,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) @@ -3529,12 +3613,16 @@ bool PortsOrch::removeVlan(Port vlan) 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; + } } removeAclTableGroup(vlan); @@ -3542,6 +3630,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); + m_portOidToName.erase(vlan.m_vlan_info.vlan_oid); m_portList.erase(vlan.m_alias); m_port_ref_count.erase(vlan.m_alias); @@ -3612,10 +3701,19 @@ 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); + 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 }; @@ -3651,7 +3749,7 @@ bool PortsOrch::removeVlanMember(Port &vlan, Port &port) /* 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; } @@ -3659,6 +3757,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 }; @@ -3671,6 +3777,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_portList[lag_alias].m_vlan_members.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); @@ -3686,16 +3803,18 @@ bool PortsOrch::addLag(string lag_alias) lag.m_lag_id = lag_id; lag.m_members = set(); m_portList[lag_alias] = lag; + m_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; } @@ -3722,6 +3841,10 @@ bool PortsOrch::removeLag(Port lag) 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) @@ -3730,8 +3853,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); + m_portOidToName.erase(lag.m_lag_id); m_portList.erase(lag.m_alias); m_port_ref_count.erase(lag.m_alias); @@ -4102,6 +4227,25 @@ void PortsOrch::updatePortOperStatus(Port &port, sai_port_oper_status_t status) port.m_oper_status = status; bool isUp = status == SAI_PORT_OPER_STATUS_UP; + + for(auto vlan_member: port.m_vlan_members) + { + 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)) { SWSS_LOG_ERROR("Failed to set host interface %s operational status %s", port.m_alias.c_str(), @@ -4116,6 +4260,41 @@ void PortsOrch::updatePortOperStatus(Port &port, sai_port_oper_status_t status) notify(SUBJECT_TYPE_PORT_OPER_STATE_CHANGE, static_cast(&update)); } +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: port.m_vlan_members) + { + 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; + } +} + /* * sync up orchagent with libsai/ASIC for port state. * diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index 936f1ff07e..d89899cdd5 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,12 +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 getVlanByVlanId(sai_vlan_id_t vlan_id, Port &vlan); bool getAclBindPortId(string alias, sai_object_id_t &port_id); 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, @@ -132,6 +136,7 @@ class PortsOrch : public Orch, public Subject unique_ptr
m_counterLagTable; unique_ptr
m_portTable; unique_ptr
m_gearboxTable; + unique_ptr
m_vlanTable; unique_ptr
m_queueTable; unique_ptr
m_queuePortTable; unique_ptr
m_queueIndexTable; @@ -141,6 +146,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); @@ -159,7 +165,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 { @@ -188,6 +195,14 @@ class PortsOrch : public Orch, public Subject map, tuple> m_lanesAliasSpeedMap; map m_portList; unordered_map m_portOidToIndex; + + /* mapping from SAI object ID to Name for faster + retrieval of Port/VLAN from object ID for events + + coming from SAI + */ + unordered_map m_portOidToName; + map m_port_ref_count; unordered_set m_pendingPortSet; @@ -273,6 +288,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/conftest.py b/tests/conftest.py index 8793c086e3..8ea0bef694 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1019,6 +1019,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 + def getCrmCounterValue(self, key, counter): counters_db = swsscommon.DBConnector(swsscommon.COUNTERS_DB, self.redis_sock, 0) crm_stats_table = swsscommon.Table(counters_db, 'CRM') diff --git a/tests/mock_tests/aclorch_ut.cpp b/tests/mock_tests/aclorch_ut.cpp index cc0ca8941f..2058018aff 100644 --- a/tests/mock_tests/aclorch_ut.cpp +++ b/tests/mock_tests/aclorch_ut.cpp @@ -318,11 +318,15 @@ namespace aclorch_test ASSERT_EQ(gRouteOrch, nullptr); gRouteOrch = new RouteOrch(m_app_db.get(), APP_ROUTE_TABLE_NAME, gSwitchOrch, gNeighOrch, gIntfsOrch, gVrfOrch); - TableConnector applDbFdb(m_app_db.get(), APP_FDB_TABLE_NAME); + vector app_fdb_tables = { + { APP_FDB_TABLE_NAME, FdbOrch::fdborch_pri}, + { APP_VXLAN_FDB_TABLE_NAME, FdbOrch::fdborch_pri} + }; + TableConnector stateDbFdb(m_state_db.get(), STATE_FDB_TABLE_NAME); ASSERT_EQ(gFdbOrch, nullptr); - gFdbOrch = new FdbOrch(applDbFdb, stateDbFdb, gPortsOrch); + gFdbOrch = new FdbOrch(m_app_db.get(), app_fdb_tables, stateDbFdb, gPortsOrch); PolicerOrch *policer_orch = new PolicerOrch(m_config_db.get(), "POLICER"); diff --git a/tests/test_evpn_fdb.py b/tests/test_evpn_fdb.py index 469494a279..0091b19b5b 100644 --- a/tests/test_evpn_fdb.py +++ b/tests/test_evpn_fdb.py @@ -48,13 +48,13 @@ def create_evpn_nvo(db, nvoname, tnlname): # create the VXLAN tunnel Term entry in Config DB create_entry_tbl( db, - "EVPN_NVO", nvoname, + "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,"EVPN_NVO", nvoname,) + 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) @@ -112,7 +112,7 @@ 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, - "EVPN_REMOTE_VNI_TABLE", "%s:%s" % (vlan_id, remotevtep), + "VXLAN_REMOTE_VNI_TABLE", "%s:%s" % (vlan_id, remotevtep), [ ("vni", vnid), ], @@ -122,31 +122,29 @@ def remove_evpn_remote_vni(db, vlan_id, remotevtep ): #app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) delete_entry_pst( db, - "EVPN_REMOTE_VNI_TABLE", "%s:%s" % (vlan_id, remotevtep), + "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_TERM_TABLE_ENTRY_ATTR_TYPE", "SAI_TUNNEL_TERM_TABLE_ENTRY_TYPE_P2P"), - ("SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_TUNNEL_TYPE", "SAI_TUNNEL_TYPE_VXLAN"), - ("SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_SRC_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_TERM_TABLE_ENTRY") + 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_TERM_TABLE_ENTRY" + 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 k == "SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_ACTION_TUNNEL_ID": - tnl_id = v if num_match == len(attributes): + tnl_id = str(key) break else: tnl_id = None @@ -223,14 +221,17 @@ def test_evpnFdb(dvs, testlog): 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" @@ -254,10 +255,13 @@ def test_evpnFdb(dvs, testlog): tnl_bp_oid_6 = get_vxlan_p2p_tunnel_bp(dvs.adb, remote_ip_6) tnl_bp_oid_8 = get_vxlan_p2p_tunnel_bp(dvs.adb, remote_ip_8) + + # 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_MACMOVE"), + [("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)), ] @@ -279,7 +283,8 @@ def test_evpnFdb(dvs, testlog): # 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_MACMOVE"), + [("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)), ] @@ -337,12 +342,12 @@ def test_evpnFdb(dvs, testlog): ) 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", str(dvs.getVlanOid("3")))], - [("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_ENDPOINT_IP", remote_ip_6), ("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID", str(tnl_bp_oid_6)), ] @@ -362,6 +367,7 @@ def test_evpnFdb(dvs, testlog): 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") @@ -376,7 +382,6 @@ def test_evpnFdb(dvs, testlog): ) 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", @@ -399,6 +404,7 @@ def test_evpnFdb(dvs, testlog): "FDB", "Vlan3|"+mac.lower(), [ ("port", "Ethernet0"), + ("type", "static"), ] ) time.sleep(2) @@ -488,7 +494,8 @@ def test_evpnFdb(dvs, testlog): # check that the FDB entry is not 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_MACMOVE"), + [("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)), ] @@ -584,7 +591,8 @@ def test_evpnFdb(dvs, testlog): # 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_MACMOVE"), + [("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)), ] @@ -613,7 +621,8 @@ def test_evpnFdb(dvs, testlog): # 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_MACMOVE"), + [("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)), ] @@ -628,7 +637,7 @@ def test_evpnFdb(dvs, testlog): 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, "FDB_NOTIFICATIONS") + 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) @@ -647,7 +656,7 @@ def test_evpnFdb(dvs, testlog): ] ) - ntf = swsscommon.NotificationProducer(dvs.adb, "FDB_NOTIFICATIONS") + 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) 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