From 4c319e0e92f761d029a913355ac6018b002cbe1d Mon Sep 17 00:00:00 2001 From: vedganes Date: Tue, 15 Dec 2020 19:26:37 -0500 Subject: [PATCH 1/2] [systemlag] VOQ System lag implementation Signed-off-by: vedganes Changes for voq system lag implementation (1) Portsorch changes for allocating unique lag id from chassis ap pdb and sending the id in system port aggregator id attribute while creating lag local LAG (2) Portsorch changes to synd local LAG and local LAG members to chassis app db. The sync-ing includes the allocated unique system lag id (3) Portsorch changes to process remote system lag from chassis app db and create lag entry in local asic db with received system lag id (4) Interface orch changes to identify local or remote interfaces (for both port and lag) (5) Orchdaemon changes in orchagent intialization to get hostname and asic_name attributes from DEVICE_METATDATA. These are used for unique system lag name derivation --- orchagent/Makefile.am | 6 +- orchagent/intfsorch.cpp | 41 +++- orchagent/main.cpp | 30 +++ orchagent/neighorch.cpp | 35 +++- orchagent/orchdaemon.cpp | 2 +- orchagent/port.h | 8 + orchagent/portsorch.cpp | 239 ++++++++++++++++++++++- orchagent/portsorch.h | 14 +- tests/mock_tests/Makefile.am | 3 +- tests/mock_tests/aclorch_ut.cpp | 2 +- tests/mock_tests/mock_orchagent_main.cpp | 5 +- tests/mock_tests/portsorch_ut.cpp | 11 +- 12 files changed, 363 insertions(+), 33 deletions(-) diff --git a/orchagent/Makefile.am b/orchagent/Makefile.am index 2aa0337448..ec09bf86a1 100644 --- a/orchagent/Makefile.am +++ b/orchagent/Makefile.am @@ -15,7 +15,8 @@ dist_swss_DATA = \ port_rates.lua \ watermark_queue.lua \ watermark_pg.lua \ - watermark_bufferpool.lua + watermark_bufferpool.lua \ + lagids.lua bin_PROGRAMS = orchagent routeresync orchagent_restart_check @@ -60,7 +61,8 @@ orchagent_SOURCES = \ sfloworch.cpp \ chassisorch.cpp \ debugcounterorch.cpp \ - natorch.cpp + natorch.cpp \ + lagid.cpp orchagent_SOURCES += flex_counter/flex_counter_manager.cpp flex_counter/flex_counter_stat_manager.cpp orchagent_SOURCES += debug_counter/debug_counter.cpp debug_counter/drop_counter.cpp diff --git a/orchagent/intfsorch.cpp b/orchagent/intfsorch.cpp index eb47332c79..dd4aec0dc1 100644 --- a/orchagent/intfsorch.cpp +++ b/orchagent/intfsorch.cpp @@ -35,6 +35,7 @@ extern BufferOrch *gBufferOrch; extern bool gIsNatSupported; extern NeighOrch *gNeighOrch; extern string gMySwitchType; +extern int32_t gVoqMySwitchId; const int intfsorch_pri = 35; @@ -1363,9 +1364,13 @@ bool IntfsOrch::isRemoteSystemPortIntf(string alias) Port port; if(gPortsOrch->getPort(alias, port)) { + + if (port.m_type == Port::LAG) + return(port.m_system_lag_info.switch_id != gVoqMySwitchId); + return(port.m_system_port_info.type == SAI_SYSTEM_PORT_TYPE_REMOTE); } - //Given alias is system port alias of the local port + //Given alias is system port alias of the local port/LAG return false; } @@ -1376,11 +1381,22 @@ void IntfsOrch::voqSyncAddIntf(string &alias) Port port; if(gPortsOrch->getPort(alias, port)) { - if(port.m_system_port_info.type == SAI_SYSTEM_PORT_TYPE_REMOTE) + if (port.m_type == Port::LAG) + { + if (port.m_system_lag_info.switch_id != gVoqMySwitchId) + { + return; + } + alias = port.m_system_lag_info.alias; + } + else { - return; + if(port.m_system_port_info.type == SAI_SYSTEM_PORT_TYPE_REMOTE) + { + return; + } + alias = port.m_system_port_info.alias; } - alias = port.m_system_port_info.alias; } else { @@ -1402,11 +1418,22 @@ void IntfsOrch::voqSyncDelIntf(string &alias) Port port; if(gPortsOrch->getPort(alias, port)) { - if(port.m_system_port_info.type == SAI_SYSTEM_PORT_TYPE_REMOTE) + if (port.m_type == Port::LAG) + { + if (port.m_system_lag_info.switch_id != gVoqMySwitchId) + { + return; + } + alias = port.m_system_lag_info.alias; + } + else { - return; + if(port.m_system_port_info.type == SAI_SYSTEM_PORT_TYPE_REMOTE) + { + return; + } + alias = port.m_system_port_info.alias; } - alias = port.m_system_port_info.alias; } else { diff --git a/orchagent/main.cpp b/orchagent/main.cpp index c6958ea30b..d1fa85b008 100644 --- a/orchagent/main.cpp +++ b/orchagent/main.cpp @@ -66,6 +66,8 @@ string gMySwitchType = ""; int32_t gVoqMySwitchId = -1; int32_t gVoqMaxCores = 0; uint32_t gCfgSystemPorts = 0; +string gMyHostName = ""; +string gMyAsicName = ""; void usage() { @@ -208,6 +210,34 @@ bool getSystemPortConfigList(DBConnector *cfgDb, DBConnector *appDb, vector spKeys; cfgSystemPortTable.getKeys(spKeys); diff --git a/orchagent/neighorch.cpp b/orchagent/neighorch.cpp index a98a1be8fd..c2ac945d82 100644 --- a/orchagent/neighorch.cpp +++ b/orchagent/neighorch.cpp @@ -15,6 +15,7 @@ extern CrmOrch *gCrmOrch; extern RouteOrch *gRouteOrch; extern FgNhgOrch *gFgNhgOrch; extern string gMySwitchType; +extern int32_t gVoqMySwitchId; const int neighorch_pri = 30; @@ -1136,11 +1137,22 @@ void NeighOrch::voqSyncAddNeigh(string &alias, IpAddress &ip_address, const MacA Port port; if(gPortsOrch->getPort(alias, port)) { - if(port.m_system_port_info.type == SAI_SYSTEM_PORT_TYPE_REMOTE) + if (port.m_type == Port::LAG) { - return; + if (port.m_system_lag_info.switch_id != gVoqMySwitchId) + { + return; + } + alias = port.m_system_lag_info.alias; + } + else + { + if(port.m_system_port_info.type == SAI_SYSTEM_PORT_TYPE_REMOTE) + { + return; + } + alias = port.m_system_port_info.alias; } - alias = port.m_system_port_info.alias; } else { @@ -1182,11 +1194,22 @@ void NeighOrch::voqSyncDelNeigh(string &alias, IpAddress &ip_address) Port port; if(gPortsOrch->getPort(alias, port)) { - if(port.m_system_port_info.type == SAI_SYSTEM_PORT_TYPE_REMOTE) + if (port.m_type == Port::LAG) { - return; + if (port.m_system_lag_info.switch_id != gVoqMySwitchId) + { + return; + } + alias = port.m_system_lag_info.alias; + } + else + { + if(port.m_system_port_info.type == SAI_SYSTEM_PORT_TYPE_REMOTE) + { + return; + } + alias = port.m_system_port_info.alias; } - alias = port.m_system_port_info.alias; } else { diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index f062ffcf1f..a4c1dde8f0 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -88,7 +88,7 @@ bool OrchDaemon::init() }; gCrmOrch = new CrmOrch(m_configDb, CFG_CRM_TABLE_NAME); - gPortsOrch = new PortsOrch(m_applDb, ports_tables); + gPortsOrch = new PortsOrch(m_applDb, ports_tables, m_chassisAppDb); TableConnector applDbFdb(m_applDb, APP_FDB_TABLE_NAME); TableConnector stateDbFdb(m_stateDb, STATE_FDB_TABLE_NAME); gFdbOrch = new FdbOrch(applDbFdb, stateDbFdb, gPortsOrch); diff --git a/orchagent/port.h b/orchagent/port.h index a088867e24..5864918d98 100644 --- a/orchagent/port.h +++ b/orchagent/port.h @@ -51,6 +51,13 @@ struct SystemPortInfo uint32_t num_voq = 8; }; +struct SystemLagInfo +{ + std::string alias = ""; + int32_t switch_id = -1; + int32_t spa_id = 0; +}; + class Port { public: @@ -139,6 +146,7 @@ class Port sai_object_id_t m_system_port_oid = 0; SystemPortInfo m_system_port_info; + SystemLagInfo m_system_lag_info; }; diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 25f0c34121..6ed6294079 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -28,6 +28,7 @@ #include "countercheckorch.h" #include "notifier.h" #include "fdborch.h" +#include "subscriberstatetable.h" extern sai_switch_api_t *sai_switch_api; extern sai_bridge_api_t *sai_bridge_api; @@ -46,6 +47,10 @@ extern BufferOrch *gBufferOrch; extern FdbOrch *gFdbOrch; extern Directory gDirectory; extern sai_system_port_api_t *sai_system_port_api; +extern string gMySwitchType; +extern int32_t gVoqMySwitchId; +extern string gMyHostName; +extern string gMyAsicName; #define DEFAULT_SYSTEM_PORT_MTU 9100 #define VLAN_PREFIX "Vlan" @@ -197,7 +202,7 @@ static char* hostif_vlan_tag[] = { * bridge. By design, SONiC switch starts with all bridge ports removed from * default VLAN and all ports removed from .1Q bridge. */ -PortsOrch::PortsOrch(DBConnector *db, vector &tableNames) : +PortsOrch::PortsOrch(DBConnector *db, vector &tableNames, DBConnector *chassisAppDb) : Orch(db, tableNames), port_stat_manager(PORT_STAT_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, PORT_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS, true), port_buffer_drop_stat_manager(PORT_BUFFER_DROP_STAT_FLEX_COUNTER_GROUP, StatsMode::READ, PORT_BUFFER_DROP_STAT_POLLING_INTERVAL_MS, true), @@ -384,6 +389,22 @@ PortsOrch::PortsOrch(DBConnector *db, vector &tableNames) m_portStatusNotificationConsumer = new swss::NotificationConsumer(notificationsDb, "NOTIFICATIONS"); auto portStatusNotificatier = new Notifier(m_portStatusNotificationConsumer, this, "PORT_STATUS_NOTIFICATIONS"); Orch::addExecutor(portStatusNotificatier); + + if (gMySwitchType == "voq") + { + string tableName; + //Add subscriber to process system LAG (System PortChannel) table + tableName = CHASSIS_APP_LAG_TABLE_NAME; + Orch::addExecutor(new Consumer(new SubscriberStateTable(chassisAppDb, tableName, TableConsumable::DEFAULT_POP_BATCH_SIZE, 0), this, tableName)); + m_tableVoqSystemLagTable = unique_ptr(new Table(chassisAppDb, CHASSIS_APP_LAG_TABLE_NAME)); + + //Add subscriber to process system LAG member (System PortChannelMember) table + tableName = CHASSIS_APP_LAG_MEMBER_TABLE_NAME; + Orch::addExecutor(new Consumer(new SubscriberStateTable(chassisAppDb, tableName, TableConsumable::DEFAULT_POP_BATCH_SIZE, 0), this, tableName)); + m_tableVoqSystemLagMemberTable = unique_ptr
(new Table(chassisAppDb, CHASSIS_APP_LAG_MEMBER_TABLE_NAME)); + + m_lagIdAllocator = unique_ptr (new LagIdAllocator(chassisAppDb)); + } } void PortsOrch::removeDefaultVlanMembers() @@ -2830,6 +2851,8 @@ void PortsOrch::doLagTask(Consumer &consumer) { SWSS_LOG_ENTER(); + string table_name = consumer.getTableName(); + auto it = consumer.m_toSync.begin(); while (it != consumer.m_toSync.end()) { @@ -2844,6 +2867,8 @@ void PortsOrch::doLagTask(Consumer &consumer) uint32_t mtu = 0; string learn_mode; string operation_status; + uint32_t lag_id = 0; + int32_t switch_id = -1; for (auto i : kfvFieldsValues(t)) { @@ -2865,12 +2890,37 @@ void PortsOrch::doLagTask(Consumer &consumer) continue; } } + else if (fvField(i) == "lag_id") + { + lag_id = (uint32_t)stoul(fvValue(i)); + } + else if (fvField(i) == "switch_id") + { + switch_id = stoi(fvValue(i)); + } + } + + if (table_name == CHASSIS_APP_LAG_TABLE_NAME) + { + if (switch_id == gVoqMySwitchId) + { + //Already created, syncd local lag from CHASSIS_APP_DB. Skip + it = consumer.m_toSync.erase(it); + continue; + } + } + else + { + // For local portchannel + + lag_id = 0; + switch_id = -1; } // Create a new LAG when the new alias comes if (m_portList.find(alias) == m_portList.end()) { - if (!addLag(alias)) + if (!addLag(alias, lag_id, switch_id)) { it++; continue; @@ -2960,6 +3010,8 @@ void PortsOrch::doLagMemberTask(Consumer &consumer) { SWSS_LOG_ENTER(); + string table_name = consumer.getTableName(); + auto it = consumer.m_toSync.begin(); while (it != consumer.m_toSync.end()) { @@ -2994,6 +3046,27 @@ void PortsOrch::doLagMemberTask(Consumer &consumer) continue; } + if (table_name == CHASSIS_APP_LAG_MEMBER_TABLE_NAME) + { + int32_t lag_switch_id = lag.m_system_lag_info.switch_id; + if (lag_switch_id == gVoqMySwitchId) + { + //Synced local member addition to local lag. Skip + it = consumer.m_toSync.erase(it); + continue; + } + + //Sanity check: The switch id-s of lag and member must match + int32_t port_switch_id = port.m_system_port_info.switch_id; + if (port_switch_id != lag_switch_id) + { + SWSS_LOG_ERROR("System lag switch id mismatch. Lag %s switch id: %d, Member %s switch id: %d", + lag_alias.c_str(), lag_switch_id, port_alias.c_str(), port_switch_id); + it = consumer.m_toSync.erase(it); + continue; + } + } + /* Update a LAG member */ if (op == SET_COMMAND) { @@ -3136,11 +3209,11 @@ void PortsOrch::doTask(Consumer &consumer) { doVlanMemberTask(consumer); } - else if (table_name == APP_LAG_TABLE_NAME) + else if (table_name == APP_LAG_TABLE_NAME || table_name == CHASSIS_APP_LAG_TABLE_NAME) { doLagTask(consumer); } - else if (table_name == APP_LAG_MEMBER_TABLE_NAME) + else if (table_name == APP_LAG_MEMBER_TABLE_NAME || table_name == CHASSIS_APP_LAG_MEMBER_TABLE_NAME) { doLagMemberTask(consumer); } @@ -3725,12 +3798,43 @@ bool PortsOrch::isVlanMember(Port &vlan, Port &port) return true; } -bool PortsOrch::addLag(string lag_alias) +bool PortsOrch::addLag(string lag_alias, uint32_t spa_id, int32_t switch_id) { SWSS_LOG_ENTER(); + vector lag_attrs; + string system_lag_alias = lag_alias; + + if (gMySwitchType == "voq") + { + if (switch_id < 0) + { + // Local PortChannel. Allocate unique lag id from central CHASSIS_APP_DB + // Use the chassis wide unique system lag name. + + // Get the local switch id and derive the system lag name. + + switch_id = gVoqMySwitchId; + system_lag_alias = gMyHostName + "|" + gMyAsicName + "|" + lag_alias; + + // Allocate unique lag id + spa_id = m_lagIdAllocator->lagIdAdd(system_lag_alias, 0); + + if ((int32_t)spa_id <= 0) + { + SWSS_LOG_ERROR("Failed to allocate unique LAG id for local lag %s rv:%d", lag_alias.c_str(), spa_id); + return false; + } + } + + sai_attribute_t attr; + attr.id = SAI_LAG_ATTR_SYSTEM_PORT_AGGREGATE_ID; + attr.value.u32 = spa_id; + lag_attrs.push_back(attr); + } + sai_object_id_t lag_id; - sai_status_t status = sai_lag_api->create_lag(&lag_id, gSwitchId, 0, NULL); + sai_status_t status = sai_lag_api->create_lag(&lag_id, gSwitchId, static_cast(lag_attrs.size()), lag_attrs.data()); if (status != SAI_STATUS_SUCCESS) { @@ -3754,6 +3858,24 @@ bool PortsOrch::addLag(string lag_alias) fields.push_back(tuple); m_counterLagTable->set("", fields); + if (gMySwitchType == "voq") + { + // If this is voq switch, record system lag info + + lag.m_system_lag_info.alias = system_lag_alias; + lag.m_system_lag_info.switch_id = switch_id; + lag.m_system_lag_info.spa_id = spa_id; + + // This will update port list with local port channel name for local port channels + // and with system lag name for the system lags received from chassis app db + + m_portList[lag_alias] = lag; + + // Sync to SYSTEM_LAG_TABLE of CHASSIS_APP_DB + + voqSyncAddLag(lag); + } + return true; } @@ -3798,6 +3920,20 @@ bool PortsOrch::removeLag(Port lag) m_counterLagTable->hdel("", lag.m_alias); + if (gMySwitchType == "voq") + { + // Free the lag id, if this is local LAG + + if (lag.m_system_lag_info.switch_id == gVoqMySwitchId) + { + m_lagIdAllocator->lagIdDel(lag.m_system_lag_info.alias); + } + + // Sync to SYSTEM_LAG_TABLE of CHASSIS_APP_DB + + voqSyncDelLag(lag); + } + return true; } @@ -3837,7 +3973,7 @@ bool PortsOrch::addLagMember(Port &lag, Port &port, bool enableForwarding) attr.value.oid = port.m_port_id; attrs.push_back(attr); - if (!enableForwarding) + if (!enableForwarding && port.m_type != Port::SYSTEM) { attr.id = SAI_LAG_MEMBER_ATTR_EGRESS_DISABLE; attr.value.booldata = true; @@ -3881,6 +4017,12 @@ bool PortsOrch::addLagMember(Port &lag, Port &port, bool enableForwarding) LagMemberUpdate update = { lag, port, true }; notify(SUBJECT_TYPE_LAG_MEMBER_CHANGE, static_cast(&update)); + if (gMySwitchType == "voq") + { + //Sync to SYSTEM_LAG_MEMBER_TABLE of CHASSIS_APP_DB + voqSyncAddLagMember(lag, port); + } + return true; } @@ -3916,6 +4058,12 @@ bool PortsOrch::removeLagMember(Port &lag, Port &port) LagMemberUpdate update = { lag, port, false }; notify(SUBJECT_TYPE_LAG_MEMBER_CHANGE, static_cast(&update)); + if (gMySwitchType == "voq") + { + //Sync to SYSTEM_LAG_MEMBER_TABLE of CHASSIS_APP_DB + voqSyncDelLagMember(lag, port); + } + return true; } @@ -3924,6 +4072,12 @@ bool PortsOrch::setCollectionOnLagMember(Port &lagMember, bool enableCollection) /* Port must be LAG member */ assert(lagMember.m_lag_member_id); + // Collection is not applicable for system port lag members (i.e, members of remote LAGs) + if (lagMember.m_type == Port::SYSTEM) + { + return true; + } + sai_status_t status = SAI_STATUS_FAILURE; sai_attribute_t attr {}; @@ -3951,6 +4105,12 @@ bool PortsOrch::setDistributionOnLagMember(Port &lagMember, bool enableDistribut /* Port must be LAG member */ assert(lagMember.m_lag_member_id); + // Distribution is not applicable for system port lag members (i.e, members of remote LAGs) + if (lagMember.m_type == Port::SYSTEM) + { + return true; + } + sai_status_t status = SAI_STATUS_FAILURE; sai_attribute_t attr {}; @@ -4880,4 +5040,69 @@ bool PortsOrch::setVoqInbandIntf(string &alias, string &type) return true; } +void PortsOrch::voqSyncAddLag (Port &lag) +{ + int32_t switch_id = lag.m_system_lag_info.switch_id; + + // Sync only local lag add to CHASSIS_APP_DB + + if (switch_id != gVoqMySwitchId) + { + return; + } + + uint32_t spa_id = lag.m_system_lag_info.spa_id; + + vector attrs; + + FieldValueTuple li ("lag_id", to_string(spa_id)); + attrs.push_back(li); + + FieldValueTuple si ("switch_id", to_string(switch_id)); + attrs.push_back(si); + + string key = lag.m_system_lag_info.alias; + + m_tableVoqSystemLagTable->set(key, attrs); +} + +void PortsOrch::voqSyncDelLag(Port &lag) +{ + // Sync only local lag del to CHASSIS_APP_DB + if (lag.m_system_lag_info.switch_id != gVoqMySwitchId) + { + return; + } + + string key = lag.m_system_lag_info.alias; + + m_tableVoqSystemLagTable->del(key); +} +void PortsOrch::voqSyncAddLagMember(Port &lag, Port &port) +{ + // Sync only local lag's member add to CHASSIS_APP_DB + if (lag.m_system_lag_info.switch_id != gVoqMySwitchId) + { + return; + } + + vector attrs; + FieldValueTuple nullFv ("NULL", "NULL"); + attrs.push_back(nullFv); + + string key = lag.m_system_lag_info.alias + ":" + port.m_system_port_info.alias; + m_tableVoqSystemLagMemberTable->set(key, attrs); +} + +void PortsOrch::voqSyncDelLagMember(Port &lag, Port &port) +{ + // Sync only local lag's member del to CHASSIS_APP_DB + if (lag.m_system_lag_info.switch_id != gVoqMySwitchId) + { + return; + } + + string key = lag.m_system_lag_info.alias + ":" + port.m_system_port_info.alias; + m_tableVoqSystemLagMemberTable->del(key); +} diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index c85783bcc3..af78a2119b 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -12,6 +12,7 @@ #include "flex_counter_manager.h" #include "gearboxutils.h" #include "saihelper.h" +#include "lagid.h" #define FCS_LEN 4 @@ -73,7 +74,7 @@ struct VlanMemberUpdate class PortsOrch : public Orch, public Subject { public: - PortsOrch(DBConnector *db, vector &tableNames); + PortsOrch(DBConnector *db, vector &tableNames, DBConnector *chassisAppDb); bool allPortsReady(); bool isInitDone(); @@ -234,7 +235,7 @@ class PortsOrch : public Orch, public Subject bool addVlan(string vlan); bool removeVlan(Port vlan); - bool addLag(string lag); + bool addLag(string lag, uint32_t spa_id, int32_t switch_id); bool removeLag(Port lag); bool addLagMember(Port &lag, Port &port, bool enableForwarding); bool removeLagMember(Port &lag, Port &port); @@ -293,7 +294,14 @@ class PortsOrch : public Orch, public Subject sai_uint32_t m_systemPortCount; bool getSystemPorts(); bool addSystemPorts(); - + unique_ptr
m_tableVoqSystemLagTable; + unique_ptr
m_tableVoqSystemLagMemberTable; + void voqSyncAddLag(Port &lag); + void voqSyncDelLag(Port &lag); + void voqSyncAddLagMember(Port &lag, Port &port); + void voqSyncDelLagMember(Port &lag, Port &port); + unique_ptr m_lagIdAllocator; + }; #endif /* SWSS_PORTSORCH_H */ diff --git a/tests/mock_tests/Makefile.am b/tests/mock_tests/Makefile.am index 40cbbb4fce..874a24527d 100644 --- a/tests/mock_tests/Makefile.am +++ b/tests/mock_tests/Makefile.am @@ -64,7 +64,8 @@ tests_SOURCES = aclorch_ut.cpp \ $(top_srcdir)/orchagent/chassisorch.cpp \ $(top_srcdir)/orchagent/sfloworch.cpp \ $(top_srcdir)/orchagent/debugcounterorch.cpp \ - $(top_srcdir)/orchagent/natorch.cpp + $(top_srcdir)/orchagent/natorch.cpp \ + $(top_srcdir)/orchagent/lagid.cpp tests_SOURCES += $(FLEX_CTR_DIR)/flex_counter_manager.cpp $(FLEX_CTR_DIR)/flex_counter_stat_manager.cpp tests_SOURCES += $(DEBUG_CTR_DIR)/debug_counter.cpp $(DEBUG_CTR_DIR)/drop_counter.cpp diff --git a/tests/mock_tests/aclorch_ut.cpp b/tests/mock_tests/aclorch_ut.cpp index 83e648d9ad..8ac4d1a98f 100644 --- a/tests/mock_tests/aclorch_ut.cpp +++ b/tests/mock_tests/aclorch_ut.cpp @@ -306,7 +306,7 @@ namespace aclorch_test }; ASSERT_EQ(gPortsOrch, nullptr); - gPortsOrch = new PortsOrch(m_app_db.get(), ports_tables); + gPortsOrch = new PortsOrch(m_app_db.get(), ports_tables, m_chassis_app_db.get()); ASSERT_EQ(gCrmOrch, nullptr); gCrmOrch = new CrmOrch(m_config_db.get(), CFG_CRM_TABLE_NAME); diff --git a/tests/mock_tests/mock_orchagent_main.cpp b/tests/mock_tests/mock_orchagent_main.cpp index 17055e02fd..a98a3a79c0 100644 --- a/tests/mock_tests/mock_orchagent_main.cpp +++ b/tests/mock_tests/mock_orchagent_main.cpp @@ -21,7 +21,10 @@ bool gLogRotate = false; bool gSaiRedisLogRotate = false; ofstream gRecordOfs; string gRecordFile; -string gMySwitchType = "voq"; +string gMySwitchType = "switch"; +int32_t gVoqMySwitchId = 0; +string gMyHostName = "Linecard1"; +string gMyAsicName = "Asic0"; MirrorOrch *gMirrorOrch; VRFOrch *gVrfOrch; diff --git a/tests/mock_tests/portsorch_ut.cpp b/tests/mock_tests/portsorch_ut.cpp index 297216a497..ed8c9774b6 100644 --- a/tests/mock_tests/portsorch_ut.cpp +++ b/tests/mock_tests/portsorch_ut.cpp @@ -16,6 +16,7 @@ namespace portsorch_test shared_ptr m_config_db; shared_ptr m_state_db; shared_ptr m_counters_db; + shared_ptr m_chassis_app_db; PortsOrchTest() { @@ -28,6 +29,8 @@ namespace portsorch_test "CONFIG_DB", 0); m_state_db = make_shared( "STATE_DB", 0); + m_chassis_app_db = make_shared( + "CHASSIS_APP_DB", 0); } virtual void SetUp() override @@ -139,7 +142,7 @@ namespace portsorch_test }; ASSERT_EQ(gPortsOrch, nullptr); - gPortsOrch = new PortsOrch(m_app_db.get(), ports_tables); + gPortsOrch = new PortsOrch(m_app_db.get(), ports_tables, m_chassis_app_db.get()); vector buffer_tables = { CFG_BUFFER_POOL_TABLE_NAME, CFG_BUFFER_PROFILE_TABLE_NAME, CFG_BUFFER_QUEUE_TABLE_NAME, @@ -268,7 +271,7 @@ namespace portsorch_test }; ASSERT_EQ(gPortsOrch, nullptr); - gPortsOrch = new PortsOrch(m_app_db.get(), ports_tables); + gPortsOrch = new PortsOrch(m_app_db.get(), ports_tables, m_chassis_app_db.get()); vector buffer_tables = { CFG_BUFFER_POOL_TABLE_NAME, CFG_BUFFER_PROFILE_TABLE_NAME, CFG_BUFFER_QUEUE_TABLE_NAME, @@ -338,7 +341,7 @@ namespace portsorch_test }; ASSERT_EQ(gPortsOrch, nullptr); - gPortsOrch = new PortsOrch(m_app_db.get(), ports_tables); + gPortsOrch = new PortsOrch(m_app_db.get(), ports_tables, m_chassis_app_db.get()); vector buffer_tables = { CFG_BUFFER_POOL_TABLE_NAME, CFG_BUFFER_PROFILE_TABLE_NAME, CFG_BUFFER_QUEUE_TABLE_NAME, @@ -483,7 +486,7 @@ namespace portsorch_test }; ASSERT_EQ(gPortsOrch, nullptr); - gPortsOrch = new PortsOrch(m_app_db.get(), ports_tables); + gPortsOrch = new PortsOrch(m_app_db.get(), ports_tables, m_chassis_app_db.get()); vector buffer_tables = { CFG_BUFFER_POOL_TABLE_NAME, CFG_BUFFER_PROFILE_TABLE_NAME, CFG_BUFFER_QUEUE_TABLE_NAME, From bf4362d0cc06dbd7159a8406a7e2087c9e9f1d7f Mon Sep 17 00:00:00 2001 From: vedganes Date: Fri, 18 Dec 2020 10:39:49 -0500 Subject: [PATCH 2/2] [systemlag] VS test for system lag Signed-off-by: vedganes Test case added for testing system lag --- tests/test_virtual_chassis.py | 176 +++++++++++++++++++- tests/virtual_chassis/1/default_config.json | 1 + tests/virtual_chassis/2/default_config.json | 1 + tests/virtual_chassis/3/default_config.json | 1 + 4 files changed, 175 insertions(+), 4 deletions(-) diff --git a/tests/test_virtual_chassis.py b/tests/test_virtual_chassis.py index 84ff3510e0..156f6d5eaa 100644 --- a/tests/test_virtual_chassis.py +++ b/tests/test_virtual_chassis.py @@ -2,6 +2,7 @@ from swsscommon import swsscommon from dvslib.dvs_database import DVSDatabase import ast +import time class TestVirtualChassis(object): @@ -38,6 +39,25 @@ def del_inbandif_port(self, vct, ibport): if cfg_switch_type == "voq": config_db.delete_entry("VOQ_INBAND_INTERFACE", f"{ibport}") + def set_lag_id_boundaries(self, vct): + """This functions sets lag id boundaries in the chassis app db. + + In VOQ systems the lag id boundaries need to be set before configuring any PortChannels. + The lag id boundaries are used by lag id allocator while adding a PortChannel to the asic db. + Note: + In real systems, the lag id boundries are taken from a platform specific file. For testing + we assume the chassis capability with maximum 512 lags. + """ + + dvss = vct.dvss + for name in dvss.keys(): + if name.startswith("supervisor"): + dvs = dvss[name] + chassis_app_db = DVSDatabase(swsscommon.CHASSIS_APP_DB, dvs.redis_chassis_sock) + chassis_app_db.db_connection.set("SYSTEM_LAG_ID_START", "1") + chassis_app_db.db_connection.set("SYSTEM_LAG_ID_END", "512") + break + def test_connectivity(self, vct): if vct is None: return @@ -71,6 +91,9 @@ def test_voq_switch(self, vct): configured system ports are avaiable in the asic db by checking the count. """ + if vct is None: + return + dvss = vct.dvss for name in dvss.keys(): dvs = dvss[name] @@ -121,7 +144,10 @@ def test_chassis_app_db_sync(self, vct): supervisor card. An interface entry is used as sample database entry for verification of syncing mechanism. """ - + + if vct is None: + return + dvss = vct.dvss for name in dvss.keys(): if name.startswith("supervisor"): @@ -139,7 +165,10 @@ def test_chassis_system_interface(self, vct): and checking that the switch id of that remote system port does not match the local asic switch id. """ - + + if vct is None: + return + dvss = vct.dvss for name in dvss.keys(): dvs = dvss[name] @@ -191,6 +220,9 @@ def test_chassis_system_neigh(self, vct): (ii) Local neighbor is synced to chassis ap db with assigned encap index (iii) Remote neighbor entry is created in ASIC_DB with received encap index """ + + if vct is None: + return # We use Ethernet0 as inband port in each line card. In real hardware, this will be a # special port used for inband. For testing purpose, we need port record and rif record @@ -248,7 +280,6 @@ def test_chassis_system_neigh(self, vct): break # Verify neighbor record syncing with encap index - dvss = vct.dvss for name in dvss.keys(): if name.startswith("supervisor"): dvs = dvss[name] @@ -278,7 +309,6 @@ def test_chassis_system_neigh(self, vct): # neigh in the kernel for the remote neighbor. The neighbor created in linecard 1 will be a # remote neighbor in other linecards. Verity existence of the test neighbor in linecards other # than linecard 1 - dvss = vct.dvss for name in dvss.keys(): dvs = dvss[name] @@ -345,6 +375,144 @@ def test_chassis_system_neigh(self, vct): # Cleanup self.del_inbandif_port(vct, inband_port) + + def test_chassis_system_lag(self, vct): + """Test portchannel in VOQ based chassis systems. + + This test validates that + (i) PortChannel is created in local asic with system port aggregator id (system lag id) + - Unique lag id is allocated from chassis app db in supervisor card + - The unique lag id is sent in system port aggregator id attribute + (ii) PortChannel members are successfully added in the PortChannel created + (iii) Local PortChannel is synced in chassis app db + (iv) PortChannel members addition is synced in the chassis app db + (v) System LAG is created for the remote PortChannel with system lag id. + (vi) System LAG of remote Portchannel has members with system port id + """ + + if vct is None: + return + + test_lag_name = "PortChannel0001" + test_lag_member = "Ethernet4" + + # Set the lag id boundaries in the chassis ap db + self.set_lag_id_boundaries(vct) + + # Create a PortChannel in a line card 1 (owner line card) + dvss = vct.dvss + for name in dvss.keys(): + dvs = dvss[name] + + config_db = dvs.get_config_db() + metatbl = config_db.get_entry("DEVICE_METADATA", "localhost") + + # Get the host name and asic name for the system lag alias verification + cfg_hostname = metatbl.get("hostname") + assert cfg_hostname != "", "Got error in getting hostname from CONFIG_DB DEVICE_METADATA" + + cfg_asic_name = metatbl.get("asic_name") + assert cfg_asic_name != "", "Got error in getting asic_name from CONFIG_DB DEVICE_METADATA" + + cfg_switch_type = metatbl.get("switch_type") + + # Neighbor record verifiation done in line card + if cfg_switch_type == "voq": + lc_switch_id = metatbl.get("switch_id") + assert lc_switch_id != "", "Got error in getting switch_id from CONFIG_DB DEVICE_METADATA" + if lc_switch_id == "0": + + # Create PortChannel + app_db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + psTbl_lag = swsscommon.ProducerStateTable(app_db, "LAG_TABLE") + fvs = swsscommon.FieldValuePairs([("admin", "up"), ("mtu", "9100")]) + psTbl_lag.set(f"{test_lag_name}", fvs) + + time.sleep(1) + + # Add port channel member + psTbl_lagMember = swsscommon.ProducerStateTable(app_db, "LAG_MEMBER_TABLE") + fvs = swsscommon.FieldValuePairs([("status", "enabled")]) + psTbl_lagMember.set(f"{test_lag_name}:{test_lag_member}", fvs) + + time.sleep(1) + + # Verify creation of the PorChannel with voq system port aggregator id in asic db + asic_db = dvs.get_asic_db() + lagkeys = asic_db.get_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG") + assert len(lagkeys) == 1, "The LAG entry for configured portchannel is not available in asic db" + + # Check for the presence of voq system port aggregate id attribute + lag_entry = asic_db.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_LAG", lagkeys[0]) + spa_id = lag_entry.get("SAI_LAG_ATTR_SYSTEM_PORT_AGGREGATE_ID") + assert spa_id != "", "VOQ System port aggregate id not present for the LAG" + + # Check for presence of lag member added + lagmemberkeys = asic_db.get_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER") + assert len(lagmemberkeys) == 1, "The LAG member for configured portchannel is not available in asic db" + + break + + # Check syncing of the PortChannel and PortChannel member in chasiss app db + for name in dvss.keys(): + if name.startswith("supervisor"): + dvs = dvss[name] + chassis_app_db = DVSDatabase(swsscommon.CHASSIS_APP_DB, dvs.redis_chassis_sock) + syslagkeys = chassis_app_db.get_keys("SYSTEM_LAG_TABLE") + assert len(syslagkeys) == 1, "System lag entry is not available in chassis app db" + + # system lag alias (key) should be unique across chassis. To ensure such uniqueness, + # the system lag name is derived from hostname, asic_name and portchannel name + # Verify for correct name + assert f"{cfg_hostname}|{cfg_asic_name}|{test_lag_name}" in syslagkeys[0], "Invalid unique system lag name" + + # Verify lag id of the system lag in chassis app db + syslag_entry = chassis_app_db.get_entry("SYSTEM_LAG_TABLE", syslagkeys[0]) + remote_lag_id = syslag_entry.get("lag_id") + assert remote_lag_id != "", "Lag id is not present in the sytem lag table in chassis app db" + # This id must be same as the id allocated in owner linecard. + assert remote_lag_id == spa_id, "System lag id in chassis app db is not same as allocated lag id" + + syslagmemberkeys = chassis_app_db.get_keys("SYSTEM_LAG_MEMBER_TABLE") + assert len(syslagmemberkeys) == 1, "No system lag member entries in chassis app db" + + break + + # Verify programming of remote system lag with received system lag id in non-owner line card + # Verify programming of lag menbers with system port id in non-owner line card + for name in dvss.keys(): + dvs = dvss[name] + + config_db = dvs.get_config_db() + metatbl = config_db.get_entry("DEVICE_METADATA", "localhost") + + cfg_switch_type = metatbl.get("switch_type") + + # System LAG info verifiation done in non-owner line card + if cfg_switch_type == "voq": + lc_switch_id = metatbl.get("switch_id") + assert lc_switch_id != "", "Got error in getting switch_id from CONFIG_DB DEVICE_METADATA" + if lc_switch_id != "0": + # Linecard other than linecard 1 (owner line card) + asic_db = dvs.get_asic_db() + remotesyslagkeys = asic_db.get_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG") + assert len(remotesyslagkeys) == 1, "No remote system lag entries in ASIC_DB" + + remotesyslag_entry = asic_db.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_LAG", remotesyslagkeys[0]) + remote_lag_id = remotesyslag_entry.get("SAI_LAG_ATTR_SYSTEM_PORT_AGGREGATE_ID") + assert remote_lag_id != "", "Lag id not present in the remote syslag entry in asic db" + assert remote_lag_id == spa_id, "Remote system lag programmed with wrong lag id" + + # Verify remote system lag has system port as member + lagmemberkeys = asic_db.get_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER") + assert len(lagmemberkeys) == 1, "The LAG member for remote system lag is not available in asic db" + + remotelagmember_entry = asic_db.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", lagmemberkeys[0]) + member_port_id = remotelagmember_entry.get("SAI_LAG_MEMBER_ATTR_PORT_ID") + #Verify that the member is a system port + assert "oid:0x5d" in member_port_id, "System LAG member is not system port" + + break # Add Dummy always-pass test at end as workaroud # for issue when Flaky fail on final test it invokes module tear-down before retrying diff --git a/tests/virtual_chassis/1/default_config.json b/tests/virtual_chassis/1/default_config.json index ed899d0724..3e0c3fce72 100644 --- a/tests/virtual_chassis/1/default_config.json +++ b/tests/virtual_chassis/1/default_config.json @@ -2,6 +2,7 @@ "DEVICE_METADATA": { "localhost": { "hostname" : "lc1", + "asic_name" : "Asic0", "instance_name": "Linecard1", "connect_to_chassis_db" : 1, "chassis_db_address" : "10.8.1.200", diff --git a/tests/virtual_chassis/2/default_config.json b/tests/virtual_chassis/2/default_config.json index 7fee336f5a..d306c30ea3 100644 --- a/tests/virtual_chassis/2/default_config.json +++ b/tests/virtual_chassis/2/default_config.json @@ -2,6 +2,7 @@ "DEVICE_METADATA": { "localhost": { "hostname" : "lc2", + "asic_name" : "Asic0", "instance_name": "Linecard2", "connect_to_chassis_db" : 1, "chassis_db_address" : "10.8.1.200", diff --git a/tests/virtual_chassis/3/default_config.json b/tests/virtual_chassis/3/default_config.json index d42441ad4b..4579733d35 100644 --- a/tests/virtual_chassis/3/default_config.json +++ b/tests/virtual_chassis/3/default_config.json @@ -2,6 +2,7 @@ "DEVICE_METADATA": { "localhost": { "hostname" : "lc3", + "asic_name" : "Asic0", "instance_name": "Linecard3", "connect_to_chassis_db" : 1, "chassis_db_address" : "10.8.1.200",