diff --git a/README.md b/README.md index 4a23c5e1711..e1641405e1e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -Broadcom[![Broadcom](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/sonic-swss-build/badge/icon)](https://sonic-jenkins.westus.cloudapp.azure.com/job/broadcom/job/sonic-swss-build/) -Cavium[![Cavium](https://sonic-jenkins.westus2.cloudapp.azure.com/job/cavium/job/sonic-swss-build/badge/icon)](https://sonic-jenkins.westus.cloudapp.azure.com/job/cavium/job/sonic-swss-build/) -Mellanox[![Mellanox](https://sonic-jenkins.westus2.cloudapp.azure.com/job/mellanox/job/sonic-swss-build/badge/icon)](https://sonic-jenkins.westus.cloudapp.azure.com/job/mellanox/job/sonic-swss-build/) -P4[![P4](https://sonic-jenkins.westus2.cloudapp.azure.com/job/p4/job/sonic-swss-build/badge/icon)](https://sonic-jenkins.westus.cloudapp.azure.com/job/p4/job/sonic-swss-build/) +Broadcom[![Broadcom](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/sonic-swss-build/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/broadcom/job/sonic-swss-build/) +Cavium[![Cavium](https://sonic-jenkins.westus2.cloudapp.azure.com/job/cavium/job/sonic-swss-build/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/cavium/job/sonic-swss-build/) +Mellanox[![Mellanox](https://sonic-jenkins.westus2.cloudapp.azure.com/job/mellanox/job/sonic-swss-build/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/mellanox/job/sonic-swss-build/) +P4[![P4](https://sonic-jenkins.westus2.cloudapp.azure.com/job/p4/job/sonic-swss-build/badge/icon)](https://sonic-jenkins.westus2.cloudapp.azure.com/job/p4/job/sonic-swss-build/) # SONiC - SWitch State Service - SWSS diff --git a/cfgmgr/buffermgr.cpp b/cfgmgr/buffermgr.cpp index 89b01970bce..48976404cb1 100644 --- a/cfgmgr/buffermgr.cpp +++ b/cfgmgr/buffermgr.cpp @@ -31,9 +31,12 @@ void BufferMgr::readPgProfileLookupFile(string file) { SWSS_LOG_NOTICE("Read lookup configuration file..."); + m_pgfile_processed = false; + ifstream infile(file); if (!infile.is_open()) { + SWSS_LOG_WARN("PG profile lookup file: %s is not readable", file.c_str()); return; } @@ -69,6 +72,7 @@ void BufferMgr::readPgProfileLookupFile(string file) ); } + m_pgfile_processed = true; infile.close(); } @@ -211,7 +215,7 @@ void BufferMgr::doTask(Consumer &consumer) task_status = doCableTask(fvField(i), fvValue(i)); } // In case of PORT table update, Buffer Manager is interested in speed update only - if (table_name == CFG_PORT_TABLE_NAME && fvField(i) == "speed") + if (m_pgfile_processed && table_name == CFG_PORT_TABLE_NAME && fvField(i) == "speed") { // create/update profile for port task_status = doSpeedUpdateTask(port, fvValue(i)); diff --git a/cfgmgr/buffermgr.h b/cfgmgr/buffermgr.h index 3c00988e65a..c497802167c 100644 --- a/cfgmgr/buffermgr.h +++ b/cfgmgr/buffermgr.h @@ -39,6 +39,7 @@ class BufferMgr : public Orch Table m_cfgBufferProfileTable; Table m_cfgBufferPgTable; Table m_cfgLosslessPgPoolTable; + bool m_pgfile_processed; pg_profile_lookup_t m_pgProfileLookup; port_cable_length_t m_cableLenLookup; diff --git a/orchagent/Makefile.am b/orchagent/Makefile.am index 4764a8f09e0..e2bd73ff4e9 100644 --- a/orchagent/Makefile.am +++ b/orchagent/Makefile.am @@ -43,6 +43,7 @@ orchagent_SOURCES = \ vrforch.cpp \ countercheckorch.cpp \ dtelorch.cpp \ + flexcounterorch.cpp\ acltable.h \ aclorch.h \ bufferorch.h \ @@ -69,7 +70,8 @@ orchagent_SOURCES = \ request_parser.h \ vrforch.h \ dtelorch.h \ - countercheckorch.h + countercheckorch.h \ + flexcounterorch.h orchagent_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) orchagent_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) diff --git a/orchagent/aclorch.cpp b/orchagent/aclorch.cpp index 6c6f2324fc4..817051c7b36 100644 --- a/orchagent/aclorch.cpp +++ b/orchagent/aclorch.cpp @@ -999,7 +999,7 @@ bool AclTable::validate() { // Control plane ACLs are handled by a separate process if (type == ACL_TABLE_UNKNOWN || type == ACL_TABLE_CTRLPLANE) return false; - if (ports.empty()) return false; + if (portSet.empty()) return false; return true; } @@ -1121,10 +1121,6 @@ bool AclTable::create() attr.value.booldata = true; table_attrs.push_back(attr); - attr.id = SAI_ACL_TABLE_ATTR_FIELD_TC; - attr.value.booldata = true; - table_attrs.push_back(attr); - if(stage == ACL_STAGE_INGRESS) { attr.id = SAI_ACL_TABLE_ATTR_FIELD_ACL_RANGE_TYPE; @@ -1694,7 +1690,7 @@ bool AclRange::remove() return true; } -void AclOrch::init(DBConnector *db, vector tableNames, PortsOrch *portOrch, MirrorOrch *mirrorOrch, NeighOrch *neighOrch, RouteOrch *routeOrch) +void AclOrch::init(vector& connectors, PortsOrch *portOrch, MirrorOrch *mirrorOrch, NeighOrch *neighOrch, RouteOrch *routeOrch) { SWSS_LOG_ENTER(); @@ -1725,8 +1721,8 @@ void AclOrch::init(DBConnector *db, vector tableNames, PortsOrch *portOr timer->start(); } -AclOrch::AclOrch(DBConnector *db, vector tableNames, PortsOrch *portOrch, MirrorOrch *mirrorOrch, NeighOrch *neighOrch, RouteOrch *routeOrch) : - Orch(db, tableNames), +AclOrch::AclOrch(vector& connectors, PortsOrch *portOrch, MirrorOrch *mirrorOrch, NeighOrch *neighOrch, RouteOrch *routeOrch) : + Orch(connectors), m_mirrorOrch(mirrorOrch), m_neighOrch(neighOrch), m_routeOrch(routeOrch), @@ -1734,11 +1730,11 @@ AclOrch::AclOrch(DBConnector *db, vector tableNames, PortsOrch *portOrch { SWSS_LOG_ENTER(); - init(db, tableNames, portOrch, mirrorOrch, neighOrch, routeOrch); + init(connectors, portOrch, mirrorOrch, neighOrch, routeOrch); } -AclOrch::AclOrch(DBConnector *db, vector tableNames, PortsOrch *portOrch, MirrorOrch *mirrorOrch, NeighOrch *neighOrch, RouteOrch *routeOrch, DTelOrch *dtelOrch) : - Orch(db, tableNames), +AclOrch::AclOrch(vector& connectors, PortsOrch *portOrch, MirrorOrch *mirrorOrch, NeighOrch *neighOrch, RouteOrch *routeOrch, DTelOrch *dtelOrch) : + Orch(connectors), m_mirrorOrch(mirrorOrch), m_neighOrch(neighOrch), m_routeOrch(routeOrch), @@ -1746,7 +1742,7 @@ AclOrch::AclOrch(DBConnector *db, vector tableNames, PortsOrch *portOrch { SWSS_LOG_ENTER(); - init(db, tableNames, portOrch, mirrorOrch, neighOrch, routeOrch); + init(connectors, portOrch, mirrorOrch, neighOrch, routeOrch); if (m_dTelOrch) { @@ -1812,6 +1808,11 @@ void AclOrch::doTask(Consumer &consumer) unique_lock lock(m_countersMutex); doAclRuleTask(consumer); } + else if (table_name == STATE_LAG_TABLE_NAME) + { + unique_lock lock(m_countersMutex); + doAclTablePortUpdateTask(consumer); + } else { SWSS_LOG_ERROR("Invalid table %s", table_name.c_str()); @@ -1912,7 +1913,7 @@ void AclOrch::doAclTableTask(Consumer &consumer) { KeyOpFieldsValuesTuple t = it->second; string key = kfvKey(t); - size_t found = key.find('|'); + size_t found = key.find(consumer.getConsumerTable()->getTableNameSeparator().c_str()); string table_id = key.substr(0, found); string op = kfvOp(t); @@ -1947,7 +1948,7 @@ void AclOrch::doAclTableTask(Consumer &consumer) } else if (attr_name == TABLE_PORTS) { - bool suc = processPorts(attr_value, [&](sai_object_id_t portOid) { + bool suc = processPorts(newTable, attr_value, [&](sai_object_id_t portOid) { newTable.link(portOid); }); @@ -2012,7 +2013,7 @@ void AclOrch::doAclRuleTask(Consumer &consumer) { KeyOpFieldsValuesTuple t = it->second; string key = kfvKey(t); - size_t found = key.find('|'); + size_t found = key.find(consumer.getConsumerTable()->getTableNameSeparator().c_str()); string table_id = key.substr(0, found); string rule_id = key.substr(found + 1); string op = kfvOp(t); @@ -2092,17 +2093,79 @@ void AclOrch::doAclRuleTask(Consumer &consumer) } } -bool AclOrch::processPorts(string portsList, std::function inserter) +void AclOrch::doAclTablePortUpdateTask(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); + size_t found = key.find(consumer.getConsumerTable()->getTableNameSeparator().c_str()); + string port_alias = key.substr(0, found); + string op = kfvOp(t); + + SWSS_LOG_INFO("doAclTablePortUpdateTask: OP: %s, port_alias: %s", op.c_str(), port_alias.c_str()); + + if (op == SET_COMMAND) + { + for (auto itmap : m_AclTables) + { + auto table = itmap.second; + if (table.pendingPortSet.find(port_alias) != table.pendingPortSet.end()) + { + SWSS_LOG_INFO("found the port: %s in ACL table: %s pending port list, bind it to ACL table.", port_alias.c_str(), table.description.c_str()); + + bool suc = processPendingPort(table, port_alias, [&](sai_object_id_t portOid) { + table.link(portOid); + }); + + if (!suc) + { + SWSS_LOG_ERROR("Failed to bind the ACL table: %s to port: %s", table.description.c_str(), port_alias.c_str()); + } + else + { + table.pendingPortSet.erase(port_alias); + SWSS_LOG_DEBUG("port: %s bound to ACL table table: %s, remove it from pending list", port_alias.c_str(), table.description.c_str()); + } + } + } + } + else if (op == DEL_COMMAND) + { + for (auto itmap : m_AclTables) + { + auto table = itmap.second; + if (table.portSet.find(port_alias) != table.portSet.end()) + { + /*TODO: update the ACL table after port/lag deleted*/ + table.pendingPortSet.emplace(port_alias); + SWSS_LOG_INFO("Add deleted port: %s to the pending list of ACL table: %s", port_alias.c_str(), table.description.c_str()); + } + } + } + else + { + SWSS_LOG_ERROR("Unknown operation type %s", op.c_str()); + } + it = consumer.m_toSync.erase(it); + } +} + +bool AclOrch::processPorts(AclTable &aclTable, string portsList, std::function inserter) { SWSS_LOG_ENTER(); vector strList; - SWSS_LOG_INFO("Processing ACL table port list %s", portsList.c_str()); + SWSS_LOG_DEBUG("Processing ACL table port list %s", portsList.c_str()); split(portsList, strList, ','); set strSet(strList.begin(), strList.end()); + aclTable.portSet = strSet; if (strList.size() != strSet.size()) { @@ -2118,33 +2181,52 @@ bool AclOrch::processPorts(string portsList, std::functiongetPort(alias, port)) { - SWSS_LOG_ERROR("Failed to process port. Port %s doesn't exist", alias.c_str()); - return false; + SWSS_LOG_INFO("Port %s not configured yet, add it to ACL table %s pending list", alias.c_str(), aclTable.description.c_str()); + aclTable.pendingPortSet.emplace(alias); + continue; } - switch (port.m_type) + if (gPortsOrch->getAclBindPortId(alias, port_id)) { - case Port::PHY: - if (port.m_lag_member_id != SAI_NULL_OBJECT_ID) - { - SWSS_LOG_ERROR("Failed to process port. Bind table to LAG member %s is not allowed", alias.c_str()); - return false; - } - inserter(port.m_port_id); - break; - case Port::LAG: - inserter(port.m_lag_id); - break; - case Port::VLAN: - inserter(port.m_vlan_info.vlan_oid); - break; - default: - SWSS_LOG_ERROR("Failed to process port. Incorrect port %s type %d", alias.c_str(), port.m_type); - return false; - } + inserter(port_id); + } + else + { + return false; + } + } + + return true; +} + +bool AclOrch::processPendingPort(AclTable &aclTable, string portAlias, std::function inserter) +{ + SWSS_LOG_ENTER(); + + SWSS_LOG_DEBUG("Processing ACL table port %s", portAlias.c_str()); + + sai_object_id_t port_id; + + Port port; + if (!gPortsOrch->getPort(portAlias, port)) + { + SWSS_LOG_INFO("Port %s not configured yet, add it to ACL table %s pending list", portAlias.c_str(), aclTable.description.c_str()); + aclTable.pendingPortSet.insert(portAlias); + return true; + } + + if (gPortsOrch->getAclBindPortId(portAlias, port_id)) + { + inserter(port_id); + aclTable.bind(port_id); + } + else + { + return false; } return true; @@ -2261,18 +2343,14 @@ sai_status_t AclOrch::bindAclTable(sai_object_id_t table_oid, AclTable &aclTable sai_status_t status = SAI_STATUS_SUCCESS; SWSS_LOG_INFO("%s table %s to ports", bind ? "Bind" : "Unbind", aclTable.id.c_str()); - + if (aclTable.ports.empty()) { if (bind) { - SWSS_LOG_ERROR("Port list is not configured for %s table", aclTable.id.c_str()); - return SAI_STATUS_FAILURE; - } - else - { - return SAI_STATUS_SUCCESS; + SWSS_LOG_WARN("Binding port list is empty for %s table", aclTable.id.c_str()); } + return SAI_STATUS_SUCCESS; } if (bind) diff --git a/orchagent/aclorch.h b/orchagent/aclorch.h index 64bb6cc486d..b587dbed2e6 100644 --- a/orchagent/aclorch.h +++ b/orchagent/aclorch.h @@ -302,6 +302,10 @@ struct AclTable { std::map ports; // Map rule name to rule data map> rules; + // Set to store the ACL table port alias + set portSet; + // Set to store the not cofigured ACL table port alias + set pendingPortSet; AclTable() : type(ACL_TABLE_UNKNOWN) @@ -348,8 +352,8 @@ inline void split(string str, Iterable& out, char delim = ' ') class AclOrch : public Orch, public Observer { public: - AclOrch(DBConnector *db, vector tableNames, PortsOrch *portOrch, MirrorOrch *mirrorOrch, NeighOrch *neighOrch, RouteOrch *routeOrch); - AclOrch(DBConnector *db, vector tableNames, PortsOrch *portOrch, MirrorOrch *mirrorOrch, NeighOrch *neighOrch, RouteOrch *routeOrch, DTelOrch *m_dTelOrch); + AclOrch(vector& connectors, PortsOrch *portOrch, MirrorOrch *mirrorOrch, NeighOrch *neighOrch, RouteOrch *routeOrch); + AclOrch(vector& connectors, PortsOrch *portOrch, MirrorOrch *mirrorOrch, NeighOrch *neighOrch, RouteOrch *routeOrch, DTelOrch *m_dTelOrch); ~AclOrch(); void update(SubjectType, void *); @@ -375,8 +379,9 @@ class AclOrch : public Orch, public Observer void doTask(Consumer &consumer); void doAclTableTask(Consumer &consumer); void doAclRuleTask(Consumer &consumer); + void doAclTablePortUpdateTask(Consumer &consumer); void doTask(SelectableTimer &timer); - void init(DBConnector *db, vector tableNames, PortsOrch *portOrch, MirrorOrch *mirrorOrch, NeighOrch *neighOrch, RouteOrch *routeOrch); + void init(vector& connectors, PortsOrch *portOrch, MirrorOrch *mirrorOrch, NeighOrch *neighOrch, RouteOrch *routeOrch); static void collectCountersThread(AclOrch *pAclOrch); @@ -386,7 +391,8 @@ class AclOrch : public Orch, public Observer bool processAclTableType(string type, acl_table_type_t &table_type); bool processAclTableStage(string stage, acl_stage_type_t &acl_stage); - bool processPorts(string portsList, std::function inserter); + bool processPorts(AclTable &aclTable, string portsList, std::function inserter); + bool processPendingPort(AclTable &aclTable, string portAlias, std::function inserter); bool validateAclTable(AclTable &aclTable); sai_status_t createDTelWatchListTables(); sai_status_t deleteDTelWatchListTables(); diff --git a/orchagent/bufferorch.cpp b/orchagent/bufferorch.cpp index 170fa178b60..ef77aa862af 100644 --- a/orchagent/bufferorch.cpp +++ b/orchagent/bufferorch.cpp @@ -29,6 +29,7 @@ BufferOrch::BufferOrch(DBConnector *db, vector &tableNames) : Orch(db, t { SWSS_LOG_ENTER(); initTableHandlers(); + initBufferReadyLists(db); }; void BufferOrch::initTableHandlers() @@ -42,6 +43,78 @@ void BufferOrch::initTableHandlers() m_bufferHandlerMap.insert(buffer_handler_pair(CFG_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME, &BufferOrch::processEgressBufferProfileList)); } +void BufferOrch::initBufferReadyLists(DBConnector *db) +{ + SWSS_LOG_ENTER(); + + Table pg_table(db, CFG_BUFFER_PG_TABLE_NAME); + initBufferReadyList(pg_table); + + Table queue_table(db, CFG_BUFFER_QUEUE_TABLE_NAME); + initBufferReadyList(queue_table); +} + +void BufferOrch::initBufferReadyList(Table& table) +{ + SWSS_LOG_ENTER(); + + // init all ports with an empty list + for (const auto& it: gPortsOrch->getAllPorts()) + { + if (it.second.m_type == Port::PHY) + { + const auto& port_name = it.first; + m_port_ready_list_ref[port_name] = {}; + } + } + + std::vector keys; + table.getKeys(keys); + + // populate the lists with buffer configuration information + for (const auto& key: keys) + { + m_ready_list[key] = false; + + auto tokens = tokenize(key, config_db_key_delimiter); + if (tokens.size() != 2) + { + SWSS_LOG_ERROR("Wrong format of a table '%s' key '%s'. Skip it", table.getTableName().c_str(), key.c_str()); + continue; + } + + auto port_names = tokenize(tokens[0], list_item_delimiter); + + for(const auto& port_name: port_names) + { + m_port_ready_list_ref[port_name].push_back(key); + } + } +} + +bool BufferOrch::isPortReady(const std::string& port_name) const +{ + SWSS_LOG_ENTER(); + + const auto it = m_port_ready_list_ref.find(port_name); + if (it == m_port_ready_list_ref.cend()) + { + // we got a port name which wasn't in our gPortsOrch->getAllPorts() list + // so make the port ready, because we don't have any buffer configuration for it + return true; + } + + const auto& list_of_keys = it->second; + + bool result = true; + for (const auto& key: list_of_keys) + { + result = result && m_ready_list.at(key); + } + + return result; +} + task_process_status BufferOrch::processBufferPool(Consumer &consumer) { SWSS_LOG_ENTER(); @@ -315,7 +388,7 @@ task_process_status BufferOrch::processQueue(Consumer &consumer) auto it = consumer.m_toSync.begin(); KeyOpFieldsValuesTuple tuple = it->second; sai_object_id_t sai_buffer_profile; - string key = kfvKey(tuple); + const string key = kfvKey(tuple); string op = kfvOp(tuple); vector tokens; sai_uint32_t range_low, range_high; @@ -374,6 +447,16 @@ task_process_status BufferOrch::processQueue(Consumer &consumer) } } } + + if (m_ready_list.find(key) != m_ready_list.end()) + { + m_ready_list[key] = true; + } + else + { + SWSS_LOG_ERROR("Queue profile '%s' was inserted after BufferOrch init", key.c_str()); + } + return task_process_status::task_success; } @@ -386,7 +469,7 @@ task_process_status BufferOrch::processPriorityGroup(Consumer &consumer) auto it = consumer.m_toSync.begin(); KeyOpFieldsValuesTuple tuple = it->second; sai_object_id_t sai_buffer_profile; - string key = kfvKey(tuple); + const string key = kfvKey(tuple); string op = kfvOp(tuple); vector tokens; sai_uint32_t range_low, range_high; @@ -451,6 +534,16 @@ task_process_status BufferOrch::processPriorityGroup(Consumer &consumer) } } } + + if (m_ready_list.find(key) != m_ready_list.end()) + { + m_ready_list[key] = true; + } + else + { + SWSS_LOG_ERROR("PG profile '%s' was inserted after BufferOrch init", key.c_str()); + } + return task_process_status::task_success; } diff --git a/orchagent/bufferorch.h b/orchagent/bufferorch.h index f05f8071aa0..23f56e61474 100644 --- a/orchagent/bufferorch.h +++ b/orchagent/bufferorch.h @@ -1,7 +1,9 @@ #ifndef SWSS_BUFFORCH_H #define SWSS_BUFFORCH_H +#include #include +#include #include "orch.h" #include "portsorch.h" @@ -26,6 +28,7 @@ class BufferOrch : public Orch { public: BufferOrch(DBConnector *db, vector &tableNames); + bool isPortReady(const std::string& port_name) const; static type_map m_buffer_type_maps; private: typedef task_process_status (BufferOrch::*buffer_table_handler)(Consumer& consumer); @@ -34,6 +37,8 @@ class BufferOrch : public Orch virtual void doTask(Consumer& consumer); void initTableHandlers(); + void initBufferReadyLists(DBConnector *db); + void initBufferReadyList(Table& table); task_process_status processBufferPool(Consumer &consumer); task_process_status processBufferProfile(Consumer &consumer); task_process_status processQueue(Consumer &consumer); @@ -42,6 +47,8 @@ class BufferOrch : public Orch task_process_status processEgressBufferProfileList(Consumer &consumer); buffer_table_handler_map m_bufferHandlerMap; + std::unordered_map m_ready_list; + std::unordered_map> m_port_ready_list_ref; }; #endif /* SWSS_BUFFORCH_H */ diff --git a/orchagent/crmorch.cpp b/orchagent/crmorch.cpp index 976d915a4ae..e7e89eac836 100644 --- a/orchagent/crmorch.cpp +++ b/orchagent/crmorch.cpp @@ -12,6 +12,7 @@ #define CRM_THRESHOLD_LOW_DEFAULT 70 #define CRM_THRESHOLD_HIGH_DEFAULT 85 #define CRM_EXCEEDED_MSG_MAX 10 +#define CRM_ACL_RESOURCE_COUNT 256 extern sai_object_id_t gSwitchId; extern sai_switch_api_t *sai_switch_api; @@ -436,20 +437,18 @@ void CrmOrch::getResAvailableCounters() case SAI_SWITCH_ATTR_AVAILABLE_ACL_TABLE: case SAI_SWITCH_ATTR_AVAILABLE_ACL_TABLE_GROUP: { - attr.value.aclresource.count = 0; - attr.value.aclresource.list = NULL; + vector resources(CRM_ACL_RESOURCE_COUNT); + attr.value.aclresource.count = CRM_ACL_RESOURCE_COUNT; + attr.value.aclresource.list = resources.data(); sai_status_t status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); - if ((status != SAI_STATUS_SUCCESS) && (status != SAI_STATUS_BUFFER_OVERFLOW)) + if (status == SAI_STATUS_BUFFER_OVERFLOW) { - SWSS_LOG_ERROR("Failed to get switch attribute %u , rv:%d", attr.id, status); - break; + resources.resize(attr.value.aclresource.count); + attr.value.aclresource.list = resources.data(); + status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); } - vector resources(attr.value.aclresource.count); - attr.value.aclresource.list = resources.data(); - - status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to get switch attribute %u , rv:%d", attr.id, status); diff --git a/orchagent/fdborch.cpp b/orchagent/fdborch.cpp index cffdbdb5481..7d265d35377 100644 --- a/orchagent/fdborch.cpp +++ b/orchagent/fdborch.cpp @@ -352,9 +352,9 @@ void FdbOrch::doTask(NotificationConsumer& consumer) } this->update(fdbevent[i].event_type, &fdbevent[i].fdb_entry, oid); - - sai_deserialize_free_fdb_event_ntf(count, fdbevent); } + + sai_deserialize_free_fdb_event_ntf(count, fdbevent); } } diff --git a/orchagent/flexcounterorch.cpp b/orchagent/flexcounterorch.cpp new file mode 100644 index 00000000000..5aaec6b986b --- /dev/null +++ b/orchagent/flexcounterorch.cpp @@ -0,0 +1,92 @@ +#include +#include "flexcounterorch.h" +#include "portsorch.h" +#include "select.h" +#include "notifier.h" +#include "redisclient.h" +#include "sai_serialize.h" +#include "pfcwdorch.h" + +extern sai_port_api_t *sai_port_api; + +extern PortsOrch *gPortsOrch; + +unordered_map flexCounterGroupMap = +{ + {"PORT", PORT_STAT_COUNTER_FLEX_COUNTER_GROUP}, + {"QUEUE", QUEUE_STAT_COUNTER_FLEX_COUNTER_GROUP}, + {"PFCWD", PFC_WD_FLEX_COUNTER_GROUP}, +}; + + +FlexCounterOrch::FlexCounterOrch(DBConnector *db, vector &tableNames): + Orch(db, tableNames), + m_flexCounterDb(new DBConnector(FLEX_COUNTER_DB, DBConnector::DEFAULT_UNIXSOCKET, 0)), + m_flexCounterGroupTable(new ProducerTable(m_flexCounterDb.get(), FLEX_COUNTER_GROUP_TABLE)) +{ + SWSS_LOG_ENTER(); +} + +FlexCounterOrch::~FlexCounterOrch(void) +{ + SWSS_LOG_ENTER(); +} + +void FlexCounterOrch::doTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + + if (!gPortsOrch->isInitDone()) + { + return; + } + + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + KeyOpFieldsValuesTuple t = it->second; + + string key = kfvKey(t); + string op = kfvOp(t); + auto data = kfvFieldsValues(t); + + if (!flexCounterGroupMap.count(key)) + { + SWSS_LOG_NOTICE("Invalid flex counter group input, %s", key.c_str()); + consumer.m_toSync.erase(it++); + continue; + } + + if (op == SET_COMMAND) + { + for (auto valuePair:data) + { + const auto &field = fvField(valuePair); + const auto &value = fvValue(valuePair); + + if (field == POLL_INTERVAL_FIELD) + { + vector fieldValues; + fieldValues.emplace_back(POLL_INTERVAL_FIELD, value); + m_flexCounterGroupTable->set(flexCounterGroupMap[key], fieldValues); + } + else if(field == FLEX_COUNTER_STATUS_FIELD) + { + // Currently the counters are disabled by default + // The queue maps will be generated as soon as counters are enabled + gPortsOrch->generateQueueMap(); + + vector fieldValues; + fieldValues.emplace_back(FLEX_COUNTER_STATUS_FIELD, value); + m_flexCounterGroupTable->set(flexCounterGroupMap[key], fieldValues); + } + else + { + SWSS_LOG_NOTICE("Unsupported field %s", field.c_str()); + } + } + } + + consumer.m_toSync.erase(it++); + } +} diff --git a/orchagent/flexcounterorch.h b/orchagent/flexcounterorch.h new file mode 100644 index 00000000000..c651a49d386 --- /dev/null +++ b/orchagent/flexcounterorch.h @@ -0,0 +1,24 @@ +#ifndef FLEXCOUNTER_ORCH_H +#define FLEXCOUNTER_ORCH_H + +#include "orch.h" +#include "port.h" +#include "producertable.h" + +extern "C" { +#include "sai.h" +} + +class FlexCounterOrch: public Orch +{ +public: + void doTask(Consumer &consumer); + FlexCounterOrch(DBConnector *db, vector &tableNames); + virtual ~FlexCounterOrch(void); + +private: + shared_ptr m_flexCounterDb = nullptr; + shared_ptr m_flexCounterGroupTable = nullptr; +}; + +#endif diff --git a/orchagent/main.cpp b/orchagent/main.cpp index f88ad3589b7..530fa016eb7 100644 --- a/orchagent/main.cpp +++ b/orchagent/main.cpp @@ -247,13 +247,15 @@ int main(int argc, char **argv) SWSS_LOG_NOTICE("Created underlay router interface ID %lx", gUnderlayIfId); /* Initialize orchestration components */ - DBConnector *appl_db = new DBConnector(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - DBConnector *config_db = new DBConnector(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + DBConnector appl_db(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + DBConnector config_db(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + DBConnector state_db(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); - OrchDaemon *orchDaemon = new OrchDaemon(appl_db, config_db); + OrchDaemon *orchDaemon = new OrchDaemon(&appl_db, &config_db, &state_db); if (!orchDaemon->init()) { SWSS_LOG_ERROR("Failed to initialize orchstration daemon"); + delete orchDaemon; exit(EXIT_FAILURE); } @@ -268,6 +270,7 @@ int main(int argc, char **argv) if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("Failed to notify syncd APPLY_VIEW %d", status); + delete orchDaemon; exit(EXIT_FAILURE); } @@ -282,5 +285,6 @@ int main(int argc, char **argv) SWSS_LOG_ERROR("Failed due to exception: %s", e.what()); } + delete orchDaemon; return 0; } diff --git a/orchagent/orch.cpp b/orchagent/orch.cpp index ce6258e5430..235b4661d1d 100644 --- a/orchagent/orch.cpp +++ b/orchagent/orch.cpp @@ -360,7 +360,7 @@ bool Orch::parseIndexRange(const string &input, sai_uint32_t &range_low, sai_uin void Orch::addConsumer(DBConnector *db, string tableName, int pri) { - if (db->getDbId() == CONFIG_DB) + if (db->getDbId() == CONFIG_DB || db->getDbId() == STATE_DB) { addExecutor(tableName, new Consumer(new SubscriberStateTable(db, tableName, TableConsumable::DEFAULT_POP_BATCH_SIZE, pri), this)); } diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 007b14e8695..672eb1ec64b 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -26,10 +26,12 @@ NeighOrch *gNeighOrch; RouteOrch *gRouteOrch; AclOrch *gAclOrch; CrmOrch *gCrmOrch; +BufferOrch *gBufferOrch; -OrchDaemon::OrchDaemon(DBConnector *applDb, DBConnector *configDb) : +OrchDaemon::OrchDaemon(DBConnector *applDb, DBConnector *configDb, DBConnector *stateDb) : m_applDb(applDb), - m_configDb(configDb) + m_configDb(configDb), + m_stateDb(stateDb) { SWSS_LOG_ENTER(); } @@ -39,9 +41,6 @@ OrchDaemon::~OrchDaemon() SWSS_LOG_ENTER(); for (Orch *o : m_orchList) delete(o); - - delete(m_configDb); - delete(m_applDb); } bool OrchDaemon::init() @@ -58,7 +57,7 @@ bool OrchDaemon::init() { APP_PORT_TABLE_NAME, portsorch_base_pri + 5 }, { APP_VLAN_TABLE_NAME, portsorch_base_pri + 2 }, { APP_VLAN_MEMBER_TABLE_NAME, portsorch_base_pri }, - { APP_LAG_TABLE_NAME, portsorch_base_pri + 2 }, + { APP_LAG_TABLE_NAME, portsorch_base_pri + 4 }, { APP_LAG_MEMBER_TABLE_NAME, portsorch_base_pri } }; @@ -92,16 +91,21 @@ bool OrchDaemon::init() CFG_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME, CFG_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME }; - BufferOrch *buffer_orch = new BufferOrch(m_configDb, buffer_tables); + gBufferOrch = new BufferOrch(m_configDb, buffer_tables); TableConnector appDbMirrorSession(m_applDb, APP_MIRROR_SESSION_TABLE_NAME); TableConnector confDbMirrorSession(m_configDb, CFG_MIRROR_SESSION_TABLE_NAME); MirrorOrch *mirror_orch = new MirrorOrch(appDbMirrorSession, confDbMirrorSession, gPortsOrch, gRouteOrch, gNeighOrch, gFdbOrch); VRFOrch *vrf_orch = new VRFOrch(m_configDb, CFG_VRF_TABLE_NAME); - vector acl_tables = { - CFG_ACL_TABLE_NAME, - CFG_ACL_RULE_TABLE_NAME + TableConnector confDbAclTable(m_configDb, CFG_ACL_TABLE_NAME); + TableConnector confDbAclRuleTable(m_configDb, CFG_ACL_RULE_TABLE_NAME); + TableConnector stateDbLagTable(m_stateDb, STATE_LAG_TABLE_NAME); + + vector acl_table_connectors = { + confDbAclTable, + confDbAclRuleTable, + stateDbLagTable }; vector dtel_tables = { @@ -112,7 +116,7 @@ bool OrchDaemon::init() CFG_DTEL_EVENT_TABLE_NAME }; - m_orchList = { switch_orch, gCrmOrch, gPortsOrch, intfs_orch, gNeighOrch, gRouteOrch, copp_orch, tunnel_decap_orch, qos_orch, buffer_orch, mirror_orch }; + m_orchList = { switch_orch, gCrmOrch, gPortsOrch, intfs_orch, gNeighOrch, gRouteOrch, copp_orch, tunnel_decap_orch, qos_orch, gBufferOrch, mirror_orch }; bool initialize_dtel = false; if (platform == BFN_PLATFORM_SUBSTRING) @@ -143,9 +147,9 @@ bool OrchDaemon::init() { dtel_orch = new DTelOrch(m_configDb, dtel_tables, gPortsOrch); m_orchList.push_back(dtel_orch); - gAclOrch = new AclOrch(m_configDb, acl_tables, gPortsOrch, mirror_orch, gNeighOrch, gRouteOrch, dtel_orch); + gAclOrch = new AclOrch(acl_table_connectors, gPortsOrch, mirror_orch, gNeighOrch, gRouteOrch, dtel_orch); } else { - gAclOrch = new AclOrch(m_configDb, acl_tables, gPortsOrch, mirror_orch, gNeighOrch, gRouteOrch); + gAclOrch = new AclOrch(acl_table_connectors, gPortsOrch, mirror_orch, gNeighOrch, gRouteOrch); } m_orchList.push_back(gAclOrch); @@ -154,6 +158,13 @@ bool OrchDaemon::init() m_select = new Select(); + + vector flex_counter_tables = { + CFG_FLEX_COUNTER_TABLE_NAME + }; + + m_orchList.push_back(new FlexCounterOrch(m_configDb, flex_counter_tables)); + vector pfc_wd_tables = { CFG_PFC_WD_TABLE_NAME }; diff --git a/orchagent/orchdaemon.h b/orchagent/orchdaemon.h index c7a96a2b0bb..0213c246749 100644 --- a/orchagent/orchdaemon.h +++ b/orchagent/orchdaemon.h @@ -22,13 +22,14 @@ #include "crmorch.h" #include "vrforch.h" #include "countercheckorch.h" +#include "flexcounterorch.h" using namespace swss; class OrchDaemon { public: - OrchDaemon(DBConnector *, DBConnector *); + OrchDaemon(DBConnector *, DBConnector *, DBConnector *); ~OrchDaemon(); bool init(); @@ -36,6 +37,7 @@ class OrchDaemon private: DBConnector *m_applDb; DBConnector *m_configDb; + DBConnector *m_stateDb; std::vector m_orchList; Select *m_select; diff --git a/orchagent/pfcwdorch.cpp b/orchagent/pfcwdorch.cpp index 065bfc4d03a..5278d76bc73 100644 --- a/orchagent/pfcwdorch.cpp +++ b/orchagent/pfcwdorch.cpp @@ -9,7 +9,6 @@ #include "notifier.h" #include "redisclient.h" -#define PFC_WD_FLEX_COUNTER_GROUP "PFC_WD" #define PFC_WD_GLOBAL "GLOBAL" #define PFC_WD_ACTION "action" #define PFC_WD_DETECTION_TIME "detection_time" diff --git a/orchagent/pfcwdorch.h b/orchagent/pfcwdorch.h index fada3676893..631b3e57402 100644 --- a/orchagent/pfcwdorch.h +++ b/orchagent/pfcwdorch.h @@ -12,6 +12,8 @@ extern "C" { #include "sai.h" } +#define PFC_WD_FLEX_COUNTER_GROUP "PFC_WD" + enum class PfcWdAction { PFC_WD_ACTION_UNKNOWN, diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 8c4fe950c5d..9ebed7ee61c 100644 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -18,6 +18,7 @@ #include "sai_serialize.h" #include "crmorch.h" #include "countercheckorch.h" +#include "bufferorch.h" #include "notifier.h" extern sai_switch_api_t *sai_switch_api; @@ -31,13 +32,12 @@ extern sai_queue_api_t *sai_queue_api; extern sai_object_id_t gSwitchId; extern NeighOrch *gNeighOrch; extern CrmOrch *gCrmOrch; +extern BufferOrch *gBufferOrch; #define VLAN_PREFIX "Vlan" #define DEFAULT_VLAN_ID 1 #define PORT_FLEX_STAT_COUNTER_POLL_MSECS "1000" #define QUEUE_FLEX_STAT_COUNTER_POLL_MSECS "10000" -#define PORT_STAT_COUNTER_FLEX_COUNTER_GROUP "PORT_STAT_COUNTER" -#define QUEUE_STAT_COUNTER_FLEX_COUNTER_GROUP "QUEUE_STAT_COUNTER" static map fec_mode_map = { @@ -95,8 +95,6 @@ static const vector queueStatIds = SAI_QUEUE_STAT_BYTES, SAI_QUEUE_STAT_DROPPED_PACKETS, SAI_QUEUE_STAT_DROPPED_BYTES, - SAI_QUEUE_STAT_CURR_OCCUPANCY_BYTES, - SAI_QUEUE_STAT_WATERMARK_BYTES, }; static char* hostif_vlan_tag[] = { @@ -406,6 +404,45 @@ bool PortsOrch::getPortByBridgePortId(sai_object_id_t bridge_port_id, Port &port return false; } +bool PortsOrch::getAclBindPortId(string alias, sai_object_id_t &port_id) +{ + SWSS_LOG_ENTER(); + + Port port; + if (getPort(alias, port)) + { + switch (port.m_type) + { + case Port::PHY: + if (port.m_lag_member_id != SAI_NULL_OBJECT_ID) + { + SWSS_LOG_WARN("Invalid configuration. Bind table to LAG member %s is not allowed", alias.c_str()); + return false; + } + else + { + port_id = port.m_port_id; + } + break; + case Port::LAG: + port_id = port.m_lag_id; + break; + case Port::VLAN: + port_id = port.m_vlan_info.vlan_oid; + break; + default: + SWSS_LOG_ERROR("Failed to process port. Incorrect port %s type %d", alias.c_str(), port.m_type); + return false; + } + + return true; + } + else + { + return false; + } +} + void PortsOrch::setPort(string alias, Port p) { m_portList[alias] = p; @@ -565,7 +602,7 @@ bool PortsOrch::bindAclTable(sai_object_id_t id, sai_object_id_t table_oid, sai_ port.m_egress_acl_table_group_id = groupOid; } - gCrmOrch->incCrmAclUsedCounter(CrmResourceType::CRM_ACL_GROUP, (sai_acl_stage_t) group_attr.value.s32, SAI_ACL_BIND_POINT_TYPE_PORT); + gCrmOrch->incCrmAclUsedCounter(CrmResourceType::CRM_ACL_GROUP, ingress ? SAI_ACL_STAGE_INGRESS : SAI_ACL_STAGE_EGRESS, SAI_ACL_BIND_POINT_TYPE_PORT); switch (port.m_type) { @@ -757,8 +794,12 @@ bool PortsOrch::setHostIntfsStripTag(Port &port, sai_hostif_vlan_tag_t strip) return true; } -bool PortsOrch::validatePortSpeed(sai_object_id_t port_id, sai_uint32_t speed) +bool PortsOrch::isSpeedSupported(const std::string& alias, sai_object_id_t port_id, sai_uint32_t speed) { + // This method will return false iff we get a list of supported speeds and the requested speed + // is not supported + // Otherwise the method will return true (even if we received errors) + sai_attribute_t attr; sai_status_t status; @@ -766,45 +807,67 @@ bool PortsOrch::validatePortSpeed(sai_object_id_t port_id, sai_uint32_t speed) // Once received the list will be stored in m_portSupportedSpeeds if (!m_portSupportedSpeeds.count(port_id)) { - attr.id = SAI_PORT_ATTR_SUPPORTED_SPEED; - attr.value.u32list.count = 0; - attr.value.u32list.list = NULL; + const auto size_guess = 25; // Guess the size which could be enough - status = sai_port_api->get_port_attribute(port_id, 1, &attr); - if (status == SAI_STATUS_BUFFER_OVERFLOW) - { - std::vector speeds(attr.value.u32list.count); + std::vector speeds(size_guess); + + for (int attempt = 0; attempt < 2; ++attempt) // two attempts to get our value + { // first with the guess, + // other with the returned value + attr.id = SAI_PORT_ATTR_SUPPORTED_SPEED; + attr.value.u32list.count = static_cast(speeds.size()); attr.value.u32list.list = speeds.data(); + status = sai_port_api->get_port_attribute(port_id, 1, &attr); - if (status == SAI_STATUS_SUCCESS) - { - m_portSupportedSpeeds[port_id] = speeds; - } - else + if (status != SAI_STATUS_BUFFER_OVERFLOW) { - SWSS_LOG_ERROR("Failed to get supported speed list for port %lx", port_id); - return false; + break; } + + speeds.resize(attr.value.u32list.count); // if our guess was wrong + // retry with the correct value } - // TODO: change to macro SAI_STATUS_IS_ATTR_NOT_SUPPORTED once it is fixed in SAI - // https://github.com/opencomputeproject/SAI/pull/710 - else if ((((status) & (~0xFFFF)) == SAI_STATUS_ATTR_NOT_SUPPORTED_0) || - (((status) & (~0xFFFF)) == SAI_STATUS_ATTR_NOT_IMPLEMENTED_0) || - (status == SAI_STATUS_NOT_IMPLEMENTED)) + + if (status == SAI_STATUS_SUCCESS) { - // unable to validate speed if attribute is not supported on platform - // assuming input value is correct - SWSS_LOG_WARN("Unable to validate speed for port %lx. Not supported by platform", port_id); - return true; + speeds.resize(attr.value.u32list.count); + m_portSupportedSpeeds[port_id] = speeds; } else { - SWSS_LOG_ERROR("Failed to get number of supported speeds for port %lx", port_id); - return false; + if (status == SAI_STATUS_BUFFER_OVERFLOW) + { + // something went wrong in SAI implementation + SWSS_LOG_ERROR("Failed to get supported speed list for port %s id=%lx. Not enough container size", + alias.c_str(), port_id); + } + else if (SAI_STATUS_IS_ATTR_NOT_SUPPORTED(status) || + SAI_STATUS_IS_ATTR_NOT_IMPLEMENTED(status) || + status == SAI_STATUS_NOT_IMPLEMENTED) + { + // unable to validate speed if attribute is not supported on platform + // assuming input value is correct + SWSS_LOG_WARN("Unable to validate speed for port %s id=%lx. Not supported by platform", + alias.c_str(), port_id); + } + else + { + SWSS_LOG_ERROR("Failed to get a list of supported speeds for port %s id=%lx. Error=%d", + alias.c_str(), port_id, status); + } + m_portSupportedSpeeds[port_id] = {}; // use an empty list, + // we don't want to get the port speed for this port again + return true; // we can't check if the speed is valid, so return true to change the speed } + } - PortSupportedSpeeds &supp_speeds = m_portSupportedSpeeds[port_id]; + const PortSupportedSpeeds &supp_speeds = m_portSupportedSpeeds[port_id]; + if (supp_speeds.size() == 0) + { + // we don't have the list for this port, so return true to change speed anyway + return true; + } return std::find(supp_speeds.begin(), supp_speeds.end(), speed) != supp_speeds.end(); } @@ -1274,8 +1337,15 @@ void PortsOrch::doPortTask(Consumer &consumer) continue; } + if (alias != "PortConfigDone" && !gBufferOrch->isPortReady(alias)) + { + // buffer configuration hasn't been applied yet. save it for future retry + it++; + continue; + } + Port p; - if (!getPort(alias, p)) + if (!getPort(alias, p) && alias != "PortConfigDone") { SWSS_LOG_ERROR("Failed to get port id by alias:%s", alias.c_str()); } @@ -1291,9 +1361,8 @@ void PortsOrch::doPortTask(Consumer &consumer) { sai_uint32_t current_speed; - if (!validatePortSpeed(p.m_port_id, speed)) + if (!isSpeedSupported(alias, p.m_port_id, speed)) { - SWSS_LOG_ERROR("Failed to set speed %u for port %s. The value is not supported", speed, alias.c_str()); it++; continue; } @@ -1327,31 +1396,31 @@ void PortsOrch::doPortTask(Consumer &consumer) } } - if (admin_status != "") + if (mtu != 0) { - if (setPortAdminStatus(p.m_port_id, admin_status == "up")) + if (setPortMtu(p.m_port_id, mtu)) { - SWSS_LOG_NOTICE("Set port %s admin status to %s", alias.c_str(), admin_status.c_str()); + p.m_mtu = mtu; + m_portList[alias] = p; + SWSS_LOG_NOTICE("Set port %s MTU to %u", alias.c_str(), mtu); } else { - SWSS_LOG_ERROR("Failed to set port %s admin status to %s", alias.c_str(), admin_status.c_str()); + SWSS_LOG_ERROR("Failed to set port %s MTU to %u", alias.c_str(), mtu); it++; continue; } } - if (mtu != 0) + if (admin_status != "") { - if (setPortMtu(p.m_port_id, mtu)) + if (setPortAdminStatus(p.m_port_id, admin_status == "up")) { - p.m_mtu = mtu; - m_portList[alias] = p; - SWSS_LOG_NOTICE("Set port %s MTU to %u", alias.c_str(), mtu); + SWSS_LOG_NOTICE("Set port %s admin status to %s", alias.c_str(), admin_status.c_str()); } else { - SWSS_LOG_ERROR("Failed to set port %s MTU to %u", alias.c_str(), mtu); + SWSS_LOG_ERROR("Failed to set port %s admin status to %s", alias.c_str(), admin_status.c_str()); it++; continue; } @@ -1402,7 +1471,9 @@ void PortsOrch::doPortTask(Consumer &consumer) } } else + { SWSS_LOG_ERROR("Unknown operation type %s", op.c_str()); + } it = consumer.m_toSync.erase(it); } @@ -1816,61 +1887,6 @@ void PortsOrch::initializeQueues(Port &port) } SWSS_LOG_INFO("Get queues for port %s", port.m_alias.c_str()); - - /* Create the Queue map in the Counter DB */ - /* Add stat counters to flex_counter */ - vector queueVector; - vector queuePortVector; - vector queueIndexVector; - vector queueTypeVector; - - for (size_t queueIndex = 0; queueIndex < port.m_queue_ids.size(); ++queueIndex) - { - std::ostringstream name; - name << port.m_alias << ":" << queueIndex; - FieldValueTuple tuple(name.str(), sai_serialize_object_id(port.m_queue_ids[queueIndex])); - queueVector.push_back(tuple); - - FieldValueTuple queuePortTuple( - sai_serialize_object_id(port.m_queue_ids[queueIndex]), - sai_serialize_object_id(port.m_port_id)); - queuePortVector.push_back(queuePortTuple); - - FieldValueTuple queueIndexTuple( - sai_serialize_object_id(port.m_queue_ids[queueIndex]), - to_string(queueIndex)); - queueIndexVector.push_back(queueIndexTuple); - - - string queueType; - if (getQueueType(port.m_queue_ids[queueIndex], queueType)) - { - FieldValueTuple queueTypeTuple( - sai_serialize_object_id(port.m_queue_ids[queueIndex]), - queueType); - queueTypeVector.push_back(queueTypeTuple); - } - - string key = getQueueFlexCounterTableKey(sai_serialize_object_id(port.m_queue_ids[queueIndex])); - - std::string delimiter = ""; - std::ostringstream counters_stream; - for (auto it = queueStatIds.begin(); it != queueStatIds.end(); it++) - { - counters_stream << delimiter << sai_serialize_queue_stat(*it); - delimiter = ","; - } - - vector fieldValues; - fieldValues.emplace_back(QUEUE_COUNTER_ID_LIST, counters_stream.str()); - - m_flexCounterTable->set(key, fieldValues); - } - - m_queueTable->set("", queueVector); - m_queuePortTable->set("", queuePortVector); - m_queueIndexTable->set("", queueIndexVector); - m_queueTypeTable->set("", queueTypeVector); } void PortsOrch::initializePriorityGroups(Port &port) @@ -1942,8 +1958,6 @@ bool PortsOrch::initializePort(Port &p) vector.push_back(tuple); m_portTable->set(p.m_alias, vector); - CounterCheckOrch::getInstance().addPort(p); - return true; } @@ -2419,6 +2433,74 @@ bool PortsOrch::removeLagMember(Port &lag, Port &port) return true; } +void PortsOrch::generateQueueMap() +{ + if (m_isQueueMapGenerated) + { + return; + } + + for (const auto& it: m_portList) + { + if (it.second.m_type == Port::PHY) + { + generateQueueMapPerPort(it.second); + } + } + + m_isQueueMapGenerated = true; +} + +void PortsOrch::generateQueueMapPerPort(const Port& port) +{ + /* Create the Queue map in the Counter DB */ + /* Add stat counters to flex_counter */ + vector queueVector; + vector queuePortVector; + vector queueIndexVector; + vector queueTypeVector; + + for (size_t queueIndex = 0; queueIndex < port.m_queue_ids.size(); ++queueIndex) + { + std::ostringstream name; + name << port.m_alias << ":" << queueIndex; + + const auto id = sai_serialize_object_id(port.m_queue_ids[queueIndex]); + + queueVector.emplace_back(name.str(), id); + queuePortVector.emplace_back(id, sai_serialize_object_id(port.m_port_id)); + queueIndexVector.emplace_back(id, to_string(queueIndex)); + + string queueType; + if (getQueueType(port.m_queue_ids[queueIndex], queueType)) + { + queueTypeVector.emplace_back(id, queueType); + } + + string key = getQueueFlexCounterTableKey(id); + + std::string delimiter = ""; + std::ostringstream counters_stream; + for (const auto& it: queueStatIds) + { + counters_stream << delimiter << sai_serialize_queue_stat(it); + delimiter = ","; + } + + vector fieldValues; + fieldValues.emplace_back(QUEUE_COUNTER_ID_LIST, counters_stream.str()); + + m_flexCounterTable->set(key, fieldValues); + } + + m_queueTable->set("", queueVector); + m_queuePortTable->set("", queuePortVector); + m_queueIndexTable->set("", queueIndexVector); + m_queueTypeTable->set("", queueTypeVector); + + CounterCheckOrch::getInstance().addPort(port); +} + void PortsOrch::doTask(NotificationConsumer &consumer) { SWSS_LOG_ENTER(); diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index bbe2497bf91..0741f5f2b82 100644 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -12,6 +12,9 @@ #define FCS_LEN 4 #define VLAN_TAG_LEN 4 +#define PORT_STAT_COUNTER_FLEX_COUNTER_GROUP "PORT_STAT_COUNTER" +#define QUEUE_STAT_COUNTER_FLEX_COUNTER_GROUP "QUEUE_STAT_COUNTER" + typedef std::vector PortSupportedSpeeds; @@ -60,10 +63,13 @@ class PortsOrch : public Orch, public Subject void setPort(string alias, Port port); 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(sai_object_id_t id, bool up); void updateDbPortOperStatus(sai_object_id_t id, sai_port_oper_status_t status); bool bindAclTable(sai_object_id_t id, sai_object_id_t table_oid, sai_object_id_t &group_member_oid, acl_stage_type_t acl_stage = ACL_STAGE_INGRESS); + + void generateQueueMap(); private: unique_ptr m_counterTable; unique_ptr
m_portTable; @@ -141,7 +147,7 @@ class PortsOrch : public Orch, public Subject bool setBridgePortAdminStatus(sai_object_id_t id, bool up); - bool validatePortSpeed(sai_object_id_t port_id, sai_uint32_t speed); + bool isSpeedSupported(const std::string& alias, sai_object_id_t port_id, sai_uint32_t speed); bool setPortSpeed(sai_object_id_t port_id, sai_uint32_t speed); bool getPortSpeed(sai_object_id_t port_id, sai_uint32_t &speed); @@ -149,6 +155,8 @@ class PortsOrch : public Orch, public Subject bool setPortAutoNeg(sai_object_id_t id, int an); bool setPortFecMode(sai_object_id_t id, int fec); + bool m_isQueueMapGenerated = false; + void generateQueueMapPerPort(const Port& port); }; #endif /* SWSS_PORTSORCH_H */ diff --git a/tests/README.md b/tests/README.md index 7c5ef03a685..bef66361196 100644 --- a/tests/README.md +++ b/tests/README.md @@ -43,7 +43,7 @@ persists. - Create virtual switch container (name:vs). ```create_vnet.sh``` can be found at [here](https://github.com/Azure/sonic-buildimage/blob/master/platform/vs/create_vnet.sh). ``` - docker run -id --name sw debian bash + docker run --privileged -id --name sw debian bash sudo ./create_vnet.sh sw docker run --privileged -v /var/run/redis-vs:/var/run/redis --network container:sw -d --name vs docker-sonic-vs ``` diff --git a/tests/test_acl.py b/tests/test_acl.py index 4ab939fe49a..794162ede63 100644 --- a/tests/test_acl.py +++ b/tests/test_acl.py @@ -9,73 +9,97 @@ def get_acl_table_id(self, dvs, adb): keys = atbl.getKeys() assert dvs.asicdb.default_acl_table in keys acl_tables = [k for k in keys if k not in dvs.asicdb.default_acl_table] - + assert len(acl_tables) == 1 return acl_tables[0] - - def test_AclTableCreation(self, dvs): - - db = swsscommon.DBConnector(4, dvs.redis_sock, 0) + + def verify_if_any_acl_table_created(self, dvs, adb): + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE") + keys = atbl.getKeys() + assert dvs.asicdb.default_acl_table in keys + acl_tables = [k for k in keys if k not in dvs.asicdb.default_acl_table] + + if (len(acl_tables) != 0): + return True + else: + return False + + def clean_up_left_over(self, dvs): adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) - - bind_ports = ["Ethernet0", "Ethernet4"] - # create ACL_TABLE in config db - tbl = swsscommon.Table(db, "ACL_TABLE") - fvs = swsscommon.FieldValuePairs([("policy_desc", "test"), ("type", "L3"), ("ports", ",".join(bind_ports))]) - tbl.set("test", fvs) - - time.sleep(1) - - # check acl table in asic db - test_acl_table_id = self.get_acl_table_id(dvs, adb) - - # check acl table group in asic db + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP") + keys = atbl.getKeys() + for key in keys: + atbl._del(key) + + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP") + keys = atbl.getKeys() + assert len(keys) == 0 + + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER") + keys = atbl.getKeys() + for key in keys: + atbl._del(key) + + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER") + keys = atbl.getKeys() + assert len(keys) == 0 + + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_LAG") + keys = atbl.getKeys() + for key in keys: + atbl._del(key) + + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_LAG") + keys = atbl.getKeys() + assert len(keys) == 0 + + def verify_acl_group_num(self, adb, expt): atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP") acl_table_groups = atbl.getKeys() - assert len(acl_table_groups) == 2 - + assert len(acl_table_groups) == expt + for k in acl_table_groups: (status, fvs) = atbl.get(k) assert status == True - for fv in fvs: if fv[0] == "SAI_ACL_TABLE_GROUP_ATTR_ACL_STAGE": assert fv[1] == "SAI_ACL_STAGE_INGRESS" elif fv[0] == "SAI_ACL_TABLE_GROUP_ATTR_ACL_BIND_POINT_TYPE_LIST": - assert fv[1] == "1:SAI_ACL_BIND_POINT_TYPE_PORT" + assert (fv[1] == "1:SAI_ACL_BIND_POINT_TYPE_PORT" or fv[1] == "1:SAI_ACL_BIND_POINT_TYPE_LAG") elif fv[0] == "SAI_ACL_TABLE_GROUP_ATTR_TYPE": assert fv[1] == "SAI_ACL_TABLE_GROUP_TYPE_PARALLEL" else: assert False - - # check acl table group member + + def verify_acl_group_member(self, adb, acl_group_ids, acl_table_id): atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER") keys = atbl.getKeys() - assert len(keys) == 2 - + member_groups = [] for k in keys: (status, fvs) = atbl.get(k) assert status == True - assert len(fvs) == 3 for fv in fvs: if fv[0] == "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_GROUP_ID": - assert fv[1] in acl_table_groups + assert fv[1] in acl_group_ids member_groups.append(fv[1]) elif fv[0] == "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_ID": - assert fv[1] == test_acl_table_id + assert fv[1] == acl_table_id elif fv[0] == "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_PRIORITY": assert True else: assert False - - assert set(member_groups) == set(acl_table_groups) - - # check port binding + + assert set(member_groups) == set(acl_group_ids) + + def verify_acl_port_binding(self, dvs, adb, bind_ports): + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP") + acl_table_groups = atbl.getKeys() + assert len(acl_table_groups) == len(bind_ports) + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_PORT") - port_groups = [] for p in [dvs.asicdb.portnamemap[portname] for portname in bind_ports]: (status, fvs) = atbl.get(p) @@ -83,9 +107,55 @@ def test_AclTableCreation(self, dvs): if fv[0] == "SAI_PORT_ATTR_INGRESS_ACL": assert fv[1] in acl_table_groups port_groups.append(fv[1]) - + + assert len(port_groups) == len(bind_ports) assert set(port_groups) == set(acl_table_groups) - + + def verify_acl_lag_binding(self, adb, lag_ids): + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP") + acl_table_groups = atbl.getKeys() + assert len(acl_table_groups) == len(lag_ids) + + atbl_lag = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_LAG") + port_groups = [] + for lag_id in lag_ids: + (status, lagfvs) = atbl_lag.get(lag_id) + for lagfv in lagfvs: + if lagfv[0] == "SAI_LAG_ATTR_INGRESS_ACL": + assert lagfv[1] in acl_table_groups + port_groups.append(lagfv[1]) + + assert len(port_groups) == len(lag_ids) + assert set(port_groups) == set(acl_table_groups) + + def test_AclTableCreation(self, dvs): + db = swsscommon.DBConnector(4, dvs.redis_sock, 0) + adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) + + # create ACL_TABLE in config db + bind_ports = ["Ethernet0", "Ethernet4"] + tbl = swsscommon.Table(db, "ACL_TABLE") + fvs = swsscommon.FieldValuePairs([("policy_desc", "test"), ("type", "L3"), ("ports", ",".join(bind_ports))]) + tbl.set("test", fvs) + time.sleep(1) + + # check acl table in asic db + test_acl_table_id = self.get_acl_table_id(dvs, adb) + + # check acl table group in asic db + self.verify_acl_group_num(adb, 2) + + # get acl table group ids and verify the id numbers + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP") + acl_group_ids = atbl.getKeys() + assert len(acl_group_ids) == 2 + + # check acl table group member + self.verify_acl_group_member(adb, acl_group_ids, test_acl_table_id) + + # check port binding + self.verify_acl_port_binding(dvs, adb, bind_ports) + def test_AclRuleL4SrcPort(self, dvs): """ hmset ACL_RULE|test|acl_test_rule priority 55 PACKET_ACTION FORWARD L4_SRC_PORT 65000 @@ -152,7 +222,7 @@ def test_AclTableDeletion(self, dvs): keys = atbl.getKeys() # only the default table was left assert len(keys) == 1 - + def test_V6AclTableCreation(self, dvs): db = swsscommon.DBConnector(4, dvs.redis_sock, 0) @@ -779,3 +849,358 @@ def test_V6AclTableDeletion(self, dvs): keys = atbl.getKeys() # only the default table was left assert len(keys) == 1 + + #helper function to verify if rule exists + def check_rule_existence(self, entry, rules, verifs): + for rule in rules: + ruleD = dict(rule) + #find the rule to match with based on priority + if ruleD["PRIORITY"] == entry['SAI_ACL_ENTRY_ATTR_PRIORITY']: + ruleIndex = rules.index(rule) + #use verification dictionary to match entry to rule + for key in verifs[ruleIndex]: + assert verifs[ruleIndex][key] == entry[key] + #found the rule + return True + #did not find the rule + return False + + def test_InsertAclRuleBetweenPriorities(self, dvs): + db = swsscommon.DBConnector(4, dvs.redis_sock, 0) + adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) + + bind_ports = ["Ethernet0", "Ethernet4"] + # create ACL_TABLE in config db + tbl = swsscommon.Table(db, "ACL_TABLE") + fvs = swsscommon.FieldValuePairs([("policy_desc", "test"), ("type", "L3"), ("ports", ",".join(bind_ports))]) + tbl.set("test_insert", fvs) + + time.sleep(2) + + num_rules = 0 + #create ACL rules + tbl = swsscommon.Table(db, "ACL_RULE") + rules = [ [("PRIORITY", "10"), ("PACKET_ACTION", "DROP"), ("SRC_IP", "10.0.0.0/32")], + [("PRIORITY", "20"), ("PACKET_ACTION", "DROP"), ("DST_IP", "104.44.94.0/23")], + [("PRIORITY", "30"), ("PACKET_ACTION", "DROP"), ("DST_IP", "192.168.0.16/32")], + [("PRIORITY", "40"), ("PACKET_ACTION", "FORWARD"), ("DST_IP", "100.64.0.0/10")] ] + #used to verify how ACL rules are programmed in ASICDB + verifs = [ {'SAI_ACL_ENTRY_ATTR_PRIORITY': '10', + 'SAI_ACL_ENTRY_ATTR_FIELD_SRC_IP': '10.0.0.0&mask:255.255.255.255', + 'SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION': 'SAI_PACKET_ACTION_DROP'}, + {'SAI_ACL_ENTRY_ATTR_PRIORITY': '20', + 'SAI_ACL_ENTRY_ATTR_FIELD_DST_IP': '104.44.94.0&mask:255.255.254.0', + 'SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION': 'SAI_PACKET_ACTION_DROP'}, + {'SAI_ACL_ENTRY_ATTR_PRIORITY': '30', + 'SAI_ACL_ENTRY_ATTR_FIELD_DST_IP': '192.168.0.16&mask:255.255.255.255', + 'SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION': 'SAI_PACKET_ACTION_DROP'}, + {'SAI_ACL_ENTRY_ATTR_PRIORITY': '40', + 'SAI_ACL_ENTRY_ATTR_FIELD_DST_IP': '100.64.0.0&mask:255.192.0.0', + 'SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION': 'SAI_PACKET_ACTION_FORWARD'} ] + #insert rules + for rule in rules: + fvs = swsscommon.FieldValuePairs(rule) + num_rules += 1 + tbl.set( "test_insert|acl_test_rule%s" % num_rules, fvs) + + time.sleep(1) + + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY") + keys = atbl.getKeys() + + #assert that first set of rules are programmed + acl_entry = [k for k in keys if k not in dvs.asicdb.default_acl_entries] + assert len(acl_entry) == num_rules + + #insert new rule with odd priority + tbl = swsscommon.Table(db, "ACL_RULE") + insertrule = [("PRIORITY", "21"), ("PACKET_ACTION", "DROP"), ("ETHER_TYPE", "4660")] + #create verification for that rule + verifs.append({'SAI_ACL_ENTRY_ATTR_PRIORITY': '21', + 'SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE': '4660&mask:0xffff', + 'SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION': 'SAI_PACKET_ACTION_DROP'}) + rules.append(insertrule) + fvs = swsscommon.FieldValuePairs(insertrule) + num_rules += 1 + tbl.set("test_insert|acl_test_rule%s" % num_rules, fvs) + + time.sleep(1) + + #assert all rules are programmed + keys = atbl.getKeys() + acl_entry = [k for k in keys if k not in dvs.asicdb.default_acl_entries] + assert len(acl_entry) == num_rules + + #match each entry to its corresponding verification + matched_rules = 0 + for entry in acl_entry: + (status, fvs) = atbl.get(entry) + assert status == True + assert len(fvs) == 6 + #helper function + if self.check_rule_existence(dict(fvs), rules, verifs): + matched_rules += 1 + + assert num_rules == matched_rules + + #cleanup + while num_rules > 0: + tbl._del("test_insert|acl_test_rule%s" % num_rules) + num_rules -= 1 + + time.sleep(1) + + (status, fvs) = atbl.get(acl_entry[0]) + assert status == False + + tbl = swsscommon.Table(db, "ACL_TABLE") + tbl._del("test_insert") + + time.sleep(1) + + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE") + keys = atbl.getKeys() + # only the default table was left + assert len(keys) == 1 + + def test_RulesWithDiffMaskLengths(self, dvs): + db = swsscommon.DBConnector(4, dvs.redis_sock, 0) + adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) + + bind_ports = ["Ethernet0", "Ethernet4"] + # create ACL_TABLE in config db + tbl = swsscommon.Table(db, "ACL_TABLE") + fvs = swsscommon.FieldValuePairs([("policy_desc", "test"), ("type", "L3"), ("ports", ",".join(bind_ports))]) + tbl.set("test_subnet", fvs) + + time.sleep(2) + + subnet_mask_rules = 0 + #create ACL rules + tbl = swsscommon.Table(db, "ACL_RULE") + rules = [ [("PRIORITY", "10"), ("PACKET_ACTION", "FORWARD"), ("SRC_IP", "23.103.0.0/18")], + [("PRIORITY", "20"), ("PACKET_ACTION", "FORWARD"), ("SRC_IP", "104.44.94.0/23")], + [("PRIORITY", "30"), ("PACKET_ACTION", "FORWARD"), ("DST_IP", "172.16.0.0/12")], + [("PRIORITY", "40"), ("PACKET_ACTION", "FORWARD"), ("DST_IP", "100.64.0.0/10")], + [("PRIORITY", "50"), ("PACKET_ACTION", "FORWARD"), ("DST_IP", "104.146.32.0/19")], + [("PRIORITY", "60"), ("PACKET_ACTION", "FORWARD"), ("SRC_IP", "21.0.0.0/8")] ] + #used to verify how ACL rules are programmed in ASICDB + #order must match the list of rules + verifs = [ {'SAI_ACL_ENTRY_ATTR_PRIORITY': '10', + 'SAI_ACL_ENTRY_ATTR_FIELD_SRC_IP': '23.103.0.0&mask:255.255.192.0', + 'SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION': 'SAI_PACKET_ACTION_FORWARD'}, + {'SAI_ACL_ENTRY_ATTR_PRIORITY': '20', + 'SAI_ACL_ENTRY_ATTR_FIELD_SRC_IP': '104.44.94.0&mask:255.255.254.0', + 'SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION': 'SAI_PACKET_ACTION_FORWARD'}, + {'SAI_ACL_ENTRY_ATTR_PRIORITY': '30', + 'SAI_ACL_ENTRY_ATTR_FIELD_DST_IP': '172.16.0.0&mask:255.240.0.0', + 'SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION': 'SAI_PACKET_ACTION_FORWARD'}, + {'SAI_ACL_ENTRY_ATTR_PRIORITY': '40', + 'SAI_ACL_ENTRY_ATTR_FIELD_DST_IP': '100.64.0.0&mask:255.192.0.0', + 'SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION': 'SAI_PACKET_ACTION_FORWARD'}, + {'SAI_ACL_ENTRY_ATTR_PRIORITY': '50', + 'SAI_ACL_ENTRY_ATTR_FIELD_DST_IP': '104.146.32.0&mask:255.255.224.0', + 'SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION': 'SAI_PACKET_ACTION_FORWARD'}, + {'SAI_ACL_ENTRY_ATTR_PRIORITY': '60', + 'SAI_ACL_ENTRY_ATTR_FIELD_SRC_IP': '21.0.0.0&mask:255.0.0.0', + 'SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION': 'SAI_PACKET_ACTION_FORWARD'} ] + #insert rules + for rule in rules: + fvs = swsscommon.FieldValuePairs(rule) + subnet_mask_rules += 1 + tbl.set( "test_subnet|acl_test_rule%s" % subnet_mask_rules, fvs ) + + time.sleep(1) + + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY") + keys = atbl.getKeys() + + acl_entry = [k for k in keys if k not in dvs.asicdb.default_acl_entries] + assert len(acl_entry) == subnet_mask_rules + + #match each entry to its corresponding verification + matched_masks = 0 + for entry in acl_entry: + (status, fvs) = atbl.get(entry) + assert status == True + assert len(fvs) == 6 + #helper function + if self.check_rule_existence(dict(fvs), rules, verifs): + matched_masks += 1 + + assert matched_masks == subnet_mask_rules + + while subnet_mask_rules > 0: + tbl._del("test_subnet|acl_test_rule%s" % subnet_mask_rules) + subnet_mask_rules -= 1 + + time.sleep(1) + + (status, fvs) = atbl.get(acl_entry[0]) + assert status == False + + tbl = swsscommon.Table(db, "ACL_TABLE") + tbl._del("test_subnet") + + time.sleep(1) + + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE") + keys = atbl.getKeys() + assert len(keys) == 1 + + def test_AclTableCreationOnLAGMember(self, dvs): + # prepare db and tables + self.clean_up_left_over(dvs) + db = swsscommon.DBConnector(4, dvs.redis_sock, 0) + adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) + apldb = swsscommon.DBConnector(0, dvs.redis_sock, 0) + + # create port channel + ps = swsscommon.ProducerStateTable(apldb, "LAG_TABLE") + fvs = swsscommon.FieldValuePairs([("admin", "up"), ("mtu", "1500")]) + ps.set("PortChannel0001", fvs) + + # create port channel member + ps = swsscommon.ProducerStateTable(apldb, "LAG_MEMBER_TABLE") + fvs = swsscommon.FieldValuePairs([("status", "enabled")]) + ps.set("PortChannel0001:Ethernet12", fvs) + time.sleep(1) + + # create acl table + tbl = swsscommon.Table(db, "ACL_TABLE") + bind_ports = ["Ethernet12"] + fvs = swsscommon.FieldValuePairs([("policy_desc", "test_negative"), ("type", "L3"), ("ports", ",".join(bind_ports))]) + tbl.set("test_negative", fvs) + time.sleep(1) + + # verify test result - ACL table creation should fail + assert self.verify_if_any_acl_table_created(dvs, adb) == False + + def test_AclTableCreationOnLAG(self, dvs): + # prepare db and tables + self.clean_up_left_over(dvs) + db = swsscommon.DBConnector(4, dvs.redis_sock, 0) + adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) + apldb = swsscommon.DBConnector(0, dvs.redis_sock, 0) + + #create port channel + ps = swsscommon.ProducerStateTable(apldb, "LAG_TABLE") + fvs = swsscommon.FieldValuePairs([("admin", "up"), ("mtu", "1500")]) + ps.set("PortChannel0002", fvs) + + # create port channel member + ps = swsscommon.ProducerStateTable(apldb, "LAG_MEMBER_TABLE") + fvs = swsscommon.FieldValuePairs([("status", "enabled")]) + ps.set("PortChannel0002:Ethernet16", fvs) + time.sleep(1) + + # create acl table + tbl = swsscommon.Table(db, "ACL_TABLE") + bind_ports = ["PortChannel0002"] + fvs = swsscommon.FieldValuePairs([("policy_desc", "test_negative"), ("type", "L3"), ("ports", ",".join(bind_ports))]) + tbl.set("test_LAG", fvs) + time.sleep(1) + + # check acl table in asic db + test_acl_table_id = self.get_acl_table_id(dvs, adb) + + # check acl table group in asic db + self.verify_acl_group_num(adb, 1) + + # get acl table group ids and verify the id numbers + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP") + acl_group_ids = atbl.getKeys() + assert len(acl_group_ids) == 1 + + # check acl table group member + self.verify_acl_group_member(adb, acl_group_ids, test_acl_table_id) + + # get lad ids + atbl_lag = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_LAG") + lag_ids = atbl_lag.getKeys(); + assert len(lag_ids) == 1 + + # check lag binding + self.verify_acl_lag_binding(adb, lag_ids) + + tbl = swsscommon.Table(db, "ACL_TABLE") + tbl._del("test_LAG") + + def test_AclTableCreationBeforeLAG(self, dvs): + # prepare db and tables + self.clean_up_left_over(dvs) + db = swsscommon.DBConnector(4, dvs.redis_sock, 0) + adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) + apldb = swsscommon.DBConnector(0, dvs.redis_sock, 0) + + # create acl table + tbl = swsscommon.Table(db, "ACL_TABLE") + bind_ports = ["PortChannel0003"] + fvs = swsscommon.FieldValuePairs([("policy_desc", "test_negative"), ("type", "L3"), ("ports", ",".join(bind_ports))]) + tbl.set("test_LAG_2", fvs) + time.sleep(1) + + # check acl table in asic db + test_acl_table_id = self.get_acl_table_id(dvs, adb) + + # check acl table group in asic db + self.verify_acl_group_num(adb, 0) + + # get acl table group ids and verify the id numbers + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP") + acl_group_ids = atbl.getKeys() + assert len(acl_group_ids) == 0 + + # check acl table group member + self.verify_acl_group_member(adb, acl_group_ids, test_acl_table_id) + + # get lad ids + atbl_lag = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_LAG") + lag_ids = atbl_lag.getKeys() + assert len(lag_ids) == 0 + + # check port binding + self.verify_acl_lag_binding(adb, lag_ids) + + # create port channel + ps = swsscommon.ProducerStateTable(apldb, "LAG_TABLE") + fvs = swsscommon.FieldValuePairs([("admin", "up"), ("mtu", "1500")]) + ps.set("PortChannel0003", fvs) + + # create port channel member + ps = swsscommon.ProducerStateTable(apldb, "LAG_MEMBER_TABLE") + fvs = swsscommon.FieldValuePairs([("status", "enabled")]) + ps.set("PortChannel0003:Ethernet20", fvs) + time.sleep(1) + + # notify aclorch that port channel configured + stdb = swsscommon.DBConnector(6, dvs.redis_sock, 0) + ps = swsscommon.ProducerStateTable(stdb, "LAG_TABLE") + fvs = swsscommon.FieldValuePairs([("state", "ok")]) + ps.set("PortChannel0003", fvs) + time.sleep(1) + + # check acl table in asic db + test_acl_table_id = self.get_acl_table_id(dvs, adb) + + # check acl table group in asic db + self.verify_acl_group_num(adb, 1) + + # get acl table group ids and verify the id numbers + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP") + acl_group_ids = atbl.getKeys() + assert len(acl_group_ids) == 1 + + # check acl table group member + self.verify_acl_group_member(adb, acl_group_ids, test_acl_table_id) + + # get lad ids + atbl_lag = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_LAG") + lag_ids = atbl_lag.getKeys() + assert len(lag_ids) == 1 + + # check port binding + self.verify_acl_lag_binding(adb, lag_ids) + + tbl = swsscommon.Table(db, "ACL_TABLE") + tbl._del("test_LAG_2") \ No newline at end of file diff --git a/tests/test_nhg.py b/tests/test_nhg.py index bf41c793d28..75f336d0275 100644 --- a/tests/test_nhg.py +++ b/tests/test_nhg.py @@ -10,9 +10,9 @@ def test_route_nhg(dvs): dvs.runcmd("ifconfig Ethernet4 10.0.0.2/31 up") dvs.runcmd("ifconfig Ethernet8 10.0.0.4/31 up") - dvs.runcmd("arp -s 10.0.0.1 00:00:00:00:00:01") - dvs.runcmd("arp -s 10.0.0.3 00:00:00:00:00:02") - dvs.runcmd("arp -s 10.0.0.5 00:00:00:00:00:03") + dvs.runcmd("arp -s 10.0.0.1 00:00:00:00:00:01") + dvs.runcmd("arp -s 10.0.0.3 00:00:00:00:00:02") + dvs.runcmd("arp -s 10.0.0.5 00:00:00:00:00:03") dvs.servers[0].runcmd("ip link set down dev eth0") == 0 dvs.servers[1].runcmd("ip link set down dev eth0") == 0 @@ -67,7 +67,7 @@ def test_route_nhg(dvs): for k in keys: (status, fvs) = nhg_member_tbl.get(k) - + for v in fvs: if v[0] == "SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID": assert v[1] == nhgid @@ -103,7 +103,7 @@ def test_route_nhg(dvs): time.sleep(1) tbl = swsscommon.Table(db, "PORT_TABLE") - (status, fvs) = tbl.get("Ethernet0") + (status, fvs) = tbl.get("Ethernet%d" % (i * 4)) assert status == True diff --git a/tests/test_port_buffer_rel.py b/tests/test_port_buffer_rel.py new file mode 100644 index 00000000000..d8c3497121d --- /dev/null +++ b/tests/test_port_buffer_rel.py @@ -0,0 +1,33 @@ +from swsscommon import swsscommon +import time + +# The test check that the ports will be up, when the admin state is UP by conf db. + +def test_PortsAreUpAfterBuffers(dvs): + num_ports = 32 + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + conf_port_table = swsscommon.Table(conf_db, "PORT") + asic_port_table = swsscommon.Table(asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_PORT") + + # enable all ports + fvs = swsscommon.FieldValuePairs([("admin_status", "up")]) + for i in range(0, num_ports): + conf_port_table.set("Ethernet%d" % (i*4), fvs) + + time.sleep(5) + + # check that the ports are enabled in ASIC + asic_port_records = asic_port_table.getKeys() + assert len(asic_port_records) == (num_ports + 1), "Number of port records doesn't match number of ports" # +CPU port + num_set = 0 + for k in asic_port_records: + status, fvs = asic_port_table.get(k) + assert status, "Got an error when get a key" + for fv in fvs: + if fv[0] == "SAI_PORT_ATTR_ADMIN_STATE": + assert fv[1] == "true", "The port isn't UP as expected" + num_set += 1 + # make sure that state is set for all "num_ports" ports + assert num_set == num_ports, "Not all ports are up" diff --git a/tests/test_portchannel.py b/tests/test_portchannel.py new file mode 100644 index 00000000000..f9ac0bf7970 --- /dev/null +++ b/tests/test_portchannel.py @@ -0,0 +1,43 @@ +from swsscommon import swsscommon +import time +import re +import json + +def test_PortChannel(dvs): + + # create port channel + db = swsscommon.DBConnector(0, dvs.redis_sock, 0) + ps = swsscommon.ProducerStateTable(db, "LAG_TABLE") + fvs = swsscommon.FieldValuePairs([("admin", "up"), ("mtu", "1500")]) + + ps.set("PortChannel0001", fvs) + + # create port channel member + ps = swsscommon.ProducerStateTable(db, "LAG_MEMBER_TABLE") + fvs = swsscommon.FieldValuePairs([("status", "enabled")]) + + ps.set("PortChannel0001:Ethernet0", fvs) + + time.sleep(1) + + # check asic db table + asicdb = swsscommon.DBConnector(1, dvs.redis_sock, 0) + + lagtbl = swsscommon.Table(asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_LAG") + + lags = lagtbl.getKeys() + assert len(lags) == 1 + + lagmtbl = swsscommon.Table(asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER") + + lagms = lagmtbl.getKeys() + assert len(lagms) == 1 + + (status, fvs) = lagmtbl.get(lagms[0]) + for fv in fvs: + if fv[0] == "SAI_LAG_MEMBER_ATTR_LAG_ID": + assert fv[1] == lags[0] + elif fv[0] == "SAI_LAG_MEMBER_ATTR_PORT_ID": + assert dvs.asicdb.portoidmap[fv[1]] == "Ethernet0" + else: + assert False