diff --git a/orchagent/debugcounterorch.cpp b/orchagent/debugcounterorch.cpp index 25d0b94589..ed27f400d4 100644 --- a/orchagent/debugcounterorch.cpp +++ b/orchagent/debugcounterorch.cpp @@ -5,6 +5,7 @@ #include "schema.h" #include "drop_counter.h" #include +#include "observer.h" using std::string; using std::unordered_map; @@ -34,6 +35,8 @@ DebugCounterOrch::DebugCounterOrch(DBConnector *db, const vector& table_ { SWSS_LOG_ENTER(); publishDropCounterCapabilities(); + + gPortsOrch->attach(this); } DebugCounterOrch::~DebugCounterOrch(void) @@ -41,6 +44,52 @@ DebugCounterOrch::~DebugCounterOrch(void) SWSS_LOG_ENTER(); } +void DebugCounterOrch::update(SubjectType type, void *cntx) +{ + SWSS_LOG_ENTER(); + + if (type == SUBJECT_TYPE_PORT_CHANGE) + { + if (!cntx) + { + SWSS_LOG_ERROR("cntx is NULL"); + return; + } + + PortUpdate *update = static_cast(cntx); + Port &port = update->port; + + if (update->add) + { + for (const auto& debug_counter: debug_counters) + { + DebugCounter *counter = debug_counter.second.get(); + auto counter_type = counter->getCounterType(); + auto counter_stat = counter->getDebugCounterSAIStat(); + auto flex_counter_type = getFlexCounterType(counter_type); + if (flex_counter_type == CounterType::PORT_DEBUG) + { + installDebugFlexCounters(counter_type, counter_stat, port.m_port_id); + } + } + } + else + { + for (const auto& debug_counter: debug_counters) + { + DebugCounter *counter = debug_counter.second.get(); + auto counter_type = counter->getCounterType(); + auto counter_stat = counter->getDebugCounterSAIStat(); + auto flex_counter_type = getFlexCounterType(counter_type); + if (flex_counter_type == CounterType::PORT_DEBUG) + { + uninstallDebugFlexCounters(counter_type, counter_stat, port.m_port_id); + } + } + } + } +} + // doTask processes updates from the consumer and modifies the state of the // following components: // 1) The ASIC, by creating, modifying, and deleting debug counters @@ -476,7 +525,8 @@ CounterType DebugCounterOrch::getFlexCounterType(const string& counter_type) } void DebugCounterOrch::installDebugFlexCounters(const string& counter_type, - const string& counter_stat) + const string& counter_stat, + sai_object_id_t port_id) { SWSS_LOG_ENTER(); CounterType flex_counter_type = getFlexCounterType(counter_type); @@ -489,6 +539,14 @@ void DebugCounterOrch::installDebugFlexCounters(const string& counter_type, { for (auto const &curr : gPortsOrch->getAllPorts()) { + if (port_id != SAI_NULL_OBJECT_ID) + { + if (curr.second.m_port_id != port_id) + { + continue; + } + } + if (curr.second.m_type != Port::Type::PHY) { continue; @@ -503,7 +561,8 @@ void DebugCounterOrch::installDebugFlexCounters(const string& counter_type, } void DebugCounterOrch::uninstallDebugFlexCounters(const string& counter_type, - const string& counter_stat) + const string& counter_stat, + sai_object_id_t port_id) { SWSS_LOG_ENTER(); CounterType flex_counter_type = getFlexCounterType(counter_type); @@ -516,6 +575,14 @@ void DebugCounterOrch::uninstallDebugFlexCounters(const string& counter_type, { for (auto const &curr : gPortsOrch->getAllPorts()) { + if (port_id != SAI_NULL_OBJECT_ID) + { + if (curr.second.m_port_id != port_id) + { + continue; + } + } + if (curr.second.m_type != Port::Type::PHY) { continue; @@ -616,3 +683,6 @@ bool DebugCounterOrch::isDropReasonValid(const string& drop_reason) const return true; } + + + diff --git a/orchagent/debugcounterorch.h b/orchagent/debugcounterorch.h index e5b512c8e4..edfb5d98e0 100644 --- a/orchagent/debugcounterorch.h +++ b/orchagent/debugcounterorch.h @@ -10,6 +10,7 @@ #include "flex_counter_stat_manager.h" #include "debug_counter.h" #include "drop_counter.h" +#include "observer.h" extern "C" { #include "sai.h" @@ -17,9 +18,11 @@ extern "C" { #define DEBUG_COUNTER_FLEX_COUNTER_GROUP "DEBUG_COUNTER" +using DebugCounterMap = std::unordered_map>; + // DebugCounterOrch is an orchestrator for managing debug counters. It handles // the creation, deletion, and modification of debug counters. -class DebugCounterOrch: public Orch +class DebugCounterOrch: public Orch, public Observer { public: DebugCounterOrch(swss::DBConnector *db, const std::vector& table_names, int poll_interval); @@ -27,6 +30,7 @@ class DebugCounterOrch: public Orch void doTask(Consumer& consumer); + void update(SubjectType, void *cntx); private: // Debug Capability Reporting Functions void publishDropCounterCapabilities(); @@ -48,10 +52,12 @@ class DebugCounterOrch: public Orch CounterType getFlexCounterType(const std::string& counter_type) noexcept(false); void installDebugFlexCounters( const std::string& counter_type, - const std::string& counter_stat); + const std::string& counter_stat, + sai_object_id_t port_id = SAI_NULL_OBJECT_ID); void uninstallDebugFlexCounters( const std::string& counter_type, - const std::string& counter_stat); + const std::string& counter_stat, + sai_object_id_t port_id = SAI_NULL_OBJECT_ID); // Debug Counter Initialization Helper Functions std::string getDebugCounterType( @@ -83,7 +89,7 @@ class DebugCounterOrch: public Orch FlexCounterStatManager flex_counter_manager; - std::unordered_map> debug_counters; + DebugCounterMap debug_counters; // free_drop_counters are drop counters that have been created by a user // that do not have any drop reasons associated with them yet. Because diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index d4fe4828b4..a6563d45ca 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -52,6 +52,7 @@ CoppOrch *gCoppOrch; P4Orch *gP4Orch; BfdOrch *gBfdOrch; Srv6Orch *gSrv6Orch; +DebugCounterOrch *gDebugCounterOrch; bool gIsNatSupported = false; @@ -282,7 +283,7 @@ bool OrchDaemon::init() CFG_DEBUG_COUNTER_DROP_REASON_TABLE_NAME }; - DebugCounterOrch *debug_counter_orch = new DebugCounterOrch(m_configDb, debug_counter_tables, 1000); + gDebugCounterOrch = new DebugCounterOrch(m_configDb, debug_counter_tables, 1000); const int natorch_base_pri = 50; @@ -330,7 +331,7 @@ bool OrchDaemon::init() * when iterating ConsumerMap. This is ensured implicitly by the order of keys in ordered map. * For cases when Orch has to process tables in specific order, like PortsOrch during warm start, it has to override Orch::doTask() */ - m_orchList = { gSwitchOrch, gCrmOrch, gPortsOrch, gBufferOrch, mux_orch, mux_cb_orch, gIntfsOrch, gNeighOrch, gNhgMapOrch, gNhgOrch, gCbfNhgOrch, gRouteOrch, gCoppOrch, gQosOrch, wm_orch, policer_orch, tunnel_decap_orch, sflow_orch, debug_counter_orch, gMacsecOrch, gBfdOrch, gSrv6Orch}; + m_orchList = { gSwitchOrch, gCrmOrch, gPortsOrch, gBufferOrch, mux_orch, mux_cb_orch, gIntfsOrch, gNeighOrch, gNhgMapOrch, gNhgOrch, gCbfNhgOrch, gRouteOrch, gCoppOrch, gQosOrch, wm_orch, policer_orch, tunnel_decap_orch, sflow_orch, gDebugCounterOrch, gMacsecOrch, gBfdOrch, gSrv6Orch}; bool initialize_dtel = false; if (platform == BFN_PLATFORM_SUBSTRING || platform == VS_PLATFORM_SUBSTRING) diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 1434f98379..d394b53f46 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -2378,6 +2378,18 @@ bool PortsOrch::initPort(const string &alias, const string &role, const int inde port_buffer_drop_stat_manager.setCounterIdList(p.m_port_id, CounterType::PORT, port_buffer_drop_stats); } + /* when a port is added and priority group map counter is enabled --> we need to add pg counter for it */ + if (m_isPriorityGroupMapGenerated) + { + generatePriorityGroupMapPerPort(p); + } + + /* when a port is added and queue map counter is enabled --> we need to add queue map counter for it */ + if (m_isQueueMapGenerated) + { + generateQueueMapPerPort(p); + } + PortUpdate update = { p, true }; notify(SUBJECT_TYPE_PORT_CHANGE, static_cast(&update)); @@ -2410,8 +2422,13 @@ void PortsOrch::deInitPort(string alias, sai_object_id_t port_id) { SWSS_LOG_ENTER(); - Port p(alias, Port::PHY); - p.m_port_id = port_id; + Port p; + + if (!getPort(port_id, p)) + { + SWSS_LOG_ERROR("Failed to get port object for port id 0x%" PRIx64, port_id); + return; + } /* remove port from flex_counter_table for updating counters */ auto flex_counters_orch = gDirectory.get(); @@ -2425,9 +2442,20 @@ void PortsOrch::deInitPort(string alias, sai_object_id_t port_id) port_buffer_drop_stat_manager.clearCounterIdList(p.m_port_id); } + /* remove pg port counters */ + if (m_isPriorityGroupMapGenerated) + { + removePriorityGroupMapPerPort(p); + } + + /* remove queue port counters */ + if (m_isQueueMapGenerated) + { + removeQueueMapPerPort(p); + } /* remove port name map from counter table */ - m_counter_db->hdel(COUNTERS_PORT_NAME_MAP, alias); + m_counterTable->hdel("", alias); /* Remove the associated port serdes attribute */ removePortSerdesAttribute(p.m_port_id); @@ -2436,7 +2464,6 @@ void PortsOrch::deInitPort(string alias, sai_object_id_t port_id) SWSS_LOG_NOTICE("De-Initialized port %s", alias.c_str()); } - bool PortsOrch::bake() { SWSS_LOG_ENTER(); @@ -5409,6 +5436,44 @@ void PortsOrch::generateQueueMap() m_isQueueMapGenerated = true; } +void PortsOrch::removeQueueMapPerPort(const Port& port) +{ + /* Remove the Queue map in the Counter DB */ + + for (size_t queueIndex = 0; queueIndex < port.m_queue_ids.size(); ++queueIndex) + { + std::ostringstream name; + name << port.m_alias << ":" << queueIndex; + std::unordered_set counter_stats; + + const auto id = sai_serialize_object_id(port.m_queue_ids[queueIndex]); + + m_queueTable->hdel("",name.str()); + m_queuePortTable->hdel("",id); + + string queueType; + uint8_t queueRealIndex = 0; + if (getQueueTypeAndIndex(port.m_queue_ids[queueIndex], queueType, queueRealIndex)) + { + m_queueTypeTable->hdel("",id); + m_queueIndexTable->hdel("",id); + } + + for (const auto& it: queue_stat_ids) + { + counter_stats.emplace(sai_serialize_queue_stat(it)); + } + queue_stat_manager.clearCounterIdList(port.m_queue_ids[queueIndex]); + + /* remove watermark queue counters */ + string key = getQueueWatermarkFlexCounterTableKey(id); + + m_flexCounterTable->del(key); + } + + CounterCheckOrch::getInstance().removePort(port); +} + void PortsOrch::generateQueueMapPerPort(const Port& port) { /* Create the Queue map in the Counter DB */ @@ -5487,6 +5552,32 @@ void PortsOrch::generatePriorityGroupMap() m_isPriorityGroupMapGenerated = true; } +void PortsOrch::removePriorityGroupMapPerPort(const Port& port) +{ + /* Remove the PG map in the Counter DB */ + + for (size_t pgIndex = 0; pgIndex < port.m_priority_group_ids.size(); ++pgIndex) + { + std::ostringstream name; + name << port.m_alias << ":" << pgIndex; + + const auto id = sai_serialize_object_id(port.m_priority_group_ids[pgIndex]); + string key = getPriorityGroupWatermarkFlexCounterTableKey(id); + + m_pgTable->hdel("",name.str()); + m_pgPortTable->hdel("",id); + m_pgIndexTable->hdel("",id); + + m_flexCounterTable->del(key); + + key = getPriorityGroupDropPacketsFlexCounterTableKey(id); + /* remove dropped packets counters to flex_counter */ + m_flexCounterTable->del(key); + } + + CounterCheckOrch::getInstance().removePort(port); +} + void PortsOrch::generatePriorityGroupMapPerPort(const Port& port) { /* Create the PG map in the Counter DB */ @@ -5644,7 +5735,7 @@ void PortsOrch::doTask(NotificationConsumer &consumer) updateDbPortOperSpeed(port, 0); } } - + /* update m_portList */ m_portList[port.m_alias] = port; } diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index 843ffbd7f1..bdfcf47ad0 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -312,9 +312,11 @@ class PortsOrch : public Orch, public Subject bool m_isQueueMapGenerated = false; void generateQueueMapPerPort(const Port& port); + void removeQueueMapPerPort(const Port& port); bool m_isPriorityGroupMapGenerated = false; void generatePriorityGroupMapPerPort(const Port& port); + void removePriorityGroupMapPerPort(const Port& port); bool m_isPortCounterMapGenerated = false; bool m_isPortBufferDropCounterMapGenerated = false; diff --git a/tests/conftest.py b/tests/conftest.py index f1e8248a14..39706295af 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -22,6 +22,7 @@ from dvslib.dvs_pbh import DVSPbh from dvslib.dvs_route import DVSRoute from dvslib import dvs_vlan +from dvslib import dvs_port from dvslib import dvs_lag from dvslib import dvs_mirror from dvslib import dvs_policer @@ -1765,7 +1766,11 @@ def dvs_vlan_manager(request, dvs): dvs.get_counters_db(), dvs.get_app_db()) - +@pytest.yield_fixture(scope="class") +def dvs_port_manager(request, dvs): + request.cls.dvs_port = dvs_port.DVSPort(dvs.get_asic_db(), + dvs.get_config_db()) + @pytest.yield_fixture(scope="class") def dvs_mirror_manager(request, dvs): request.cls.dvs_mirror = dvs_mirror.DVSMirror(dvs.get_asic_db(), diff --git a/tests/dvslib/dvs_database.py b/tests/dvslib/dvs_database.py index 4256b5802d..371b7f61e9 100644 --- a/tests/dvslib/dvs_database.py +++ b/tests/dvslib/dvs_database.py @@ -92,6 +92,17 @@ def delete_entry(self, table_name: str, key: str) -> None: table = swsscommon.Table(self.db_connection, table_name) table._del(key) # pylint: disable=protected-access + def delete_field(self, table_name: str, key: str, field: str) -> None: + """Remove a field from an entry stored at `key` in the specified table. + + Args: + table_name: The name of the table where the entry is being removed. + key: The key that maps to the entry being removed. + field: The field that needs to be removed + """ + table = swsscommon.Table(self.db_connection, table_name) + table.hdel(key, field) + def get_keys(self, table_name: str) -> List[str]: """Get all of the keys stored in the specified table. diff --git a/tests/dvslib/dvs_port.py b/tests/dvslib/dvs_port.py new file mode 100644 index 0000000000..8c53994242 --- /dev/null +++ b/tests/dvslib/dvs_port.py @@ -0,0 +1,20 @@ + +class DVSPort(object): + def __init__(self, adb, cdb): + self.asic_db = adb + self.config_db = cdb + + def remove_port(self, port_name): + self.config_db.delete_field("CABLE_LENGTH", "AZURE", port_name) + + port_bufferpg_keys = self.config_db.get_keys("BUFFER_PG|%s" % port_name) + for key in port_bufferpg_keys: + self.config_db.delete_entry("BUFFER_PG|%s|%s" % (port_name, key), "") + + port_bufferqueue_keys = self.config_db.get_keys("BUFFER_QUEUE|%s" % port_name) + for key in port_bufferqueue_keys: + self.config_db.delete_entry("BUFFER_QUEUE|%s|%s" % (port_name, key), "") + + self.config_db.delete_entry("BREAKOUT_CFG|%s" % port_name, "") + self.config_db.delete_entry("INTERFACE|%s" % port_name, "") + self.config_db.delete_entry("PORT", port_name) diff --git a/tests/test_drop_counters.py b/tests/test_drop_counters.py index b003876f1a..cd089be917 100644 --- a/tests/test_drop_counters.py +++ b/tests/test_drop_counters.py @@ -11,7 +11,7 @@ # Debug Counter Table DEBUG_COUNTER_TABLE = 'DEBUG_COUNTER' -DROP_REASON_TABLE = 'DEBUG_COUNTER_DROP_REASON' +DROP_REASON_TABLE = 'DEBUG_COUNTER_DROP_REASON' # Debug Counter Capability Table CAPABILITIES_TABLE = 'DEBUG_COUNTER_CAPABILITIES' @@ -54,7 +54,11 @@ EXPECTED_ASIC_FIELDS = [ASIC_COUNTER_TYPE_FIELD, ASIC_COUNTER_INGRESS_REASON_LIST_FIELD, ASIC_COUNTER_EGRESS_REASON_LIST_FIELD] EXPECTED_NUM_ASIC_FIELDS = 2 +# port to be add and removed +PORT = "Ethernet0" +PORT_TABLE_NAME = "PORT" +@pytest.mark.usefixtures('dvs_port_manager') # FIXME: It is really annoying to have to re-run tests due to inconsistent timing, should # implement some sort of polling interface for checking ASIC/flex counter tables after # applying changes to config DB @@ -64,6 +68,7 @@ def setup_db(self, dvs): self.config_db = swsscommon.DBConnector(4, dvs.redis_sock, 0) self.flex_db = swsscommon.DBConnector(5, dvs.redis_sock, 0) self.state_db = swsscommon.DBConnector(6, dvs.redis_sock, 0) + self.counters_db = swsscommon.DBConnector(2, dvs.redis_sock, 0) def genericGetAndAssert(self, table, key): status, fields = table.get(key) @@ -654,6 +659,79 @@ def test_removeInvalidDropReason(self, dvs, testlog): # Cleanup for the next test. self.delete_drop_counter(name) self.remove_drop_reason(name, reason1) + + def getPortOid(self, dvs, port_name): + port_name_map = swsscommon.Table(self.counters_db, "COUNTERS_PORT_NAME_MAP") + status, returned_value = port_name_map.hget("", port_name); + assert status == True + return returned_value + + def test_add_remove_port(self, dvs, testlog): + """ + This test verifies that debug counters are removed when we remove a port + and debug counters are added each time we add ports (if debug counter is enabled) + """ + self.setup_db(dvs) + + # save port info + cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0) + tbl = swsscommon.Table(cdb, PORT_TABLE_NAME) + (status, fvs) = tbl.get(PORT) + assert status == True + + # get counter oid + oid = self.getPortOid(dvs, PORT) + + # verifies debug coutner dont exist for port + flex_counter_table = swsscommon.Table(self.flex_db, FLEX_COUNTER_TABLE) + status, fields = flex_counter_table.get(oid) + assert len(fields) == 0 + + # add debug counters + name1 = 'DEBUG_0' + reason1 = 'L3_ANY' + name2 = 'DEBUG_1' + reason2 = 'L2_ANY' + + self.create_drop_counter(name1, PORT_INGRESS_DROPS) + self.add_drop_reason(name1, reason1) + + self.create_drop_counter(name2, PORT_EGRESS_DROPS) + self.add_drop_reason(name2, reason2) + time.sleep(3) + + # verifies debug counter exist for port + flex_counter_table = swsscommon.Table(self.flex_db, FLEX_COUNTER_TABLE) + status, fields = flex_counter_table.get(oid) + assert status == True + assert len(fields) == 1 + + # remove port and wait until it was removed from ASIC DB + self.dvs_port.remove_port(PORT) + dvs.get_asic_db().wait_for_deleted_entry("ASIC_STATE:SAI_OBJECT_TYPE_PORT", oid) + + # verify that debug counter were removed + status, fields = flex_counter_table.get(oid) + assert len(fields) == 0 + + # add port and wait until the port is added on asic db + num_of_keys_without_port = len(dvs.get_asic_db().get_keys("ASIC_STATE:SAI_OBJECT_TYPE_PORT")) + tbl.set(PORT, fvs) + dvs.get_asic_db().wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_PORT", num_of_keys_without_port + 1) + dvs.get_counters_db().wait_for_fields("COUNTERS_PORT_NAME_MAP", "", [PORT]) + + # verifies that debug counters were added for port + oid = self.getPortOid(dvs, PORT) + status, fields = flex_counter_table.get(oid) + assert status == True + assert len(fields) == 1 + + # Cleanup for the next test. + self.delete_drop_counter(name1) + self.remove_drop_reason(name1, reason1) + + self.delete_drop_counter(name2) + self.remove_drop_reason(name2, reason2) def test_createAndDeleteMultipleCounters(self, dvs, testlog): """ diff --git a/tests/test_flex_counters.py b/tests/test_flex_counters.py index ea950af7c1..bd95aa433d 100644 --- a/tests/test_flex_counters.py +++ b/tests/test_flex_counters.py @@ -6,6 +6,8 @@ TUNNEL_TYPE_MAP = "COUNTERS_TUNNEL_TYPE_MAP" NUMBER_OF_RETRIES = 10 CPU_PORT_OID = "0x0" +PORT = "Ethernet0" +PORT_MAP = "COUNTERS_PORT_NAME_MAP" counter_group_meta = { 'port_counter': { @@ -63,7 +65,7 @@ } } - +@pytest.mark.usefixtures('dvs_port_manager') class TestFlexCounters(object): def setup_dbs(self, dvs): @@ -372,3 +374,64 @@ def test_remove_trap_group(self, dvs): assert trap_id not in counters_keys self.set_flex_counter_group_status(meta_data['key'], meta_data['group_name'], 'disable') + + def test_add_remove_ports(self, dvs): + self.setup_dbs(dvs) + + # set flex counter + counter_key = counter_group_meta['queue_counter']['key'] + counter_stat = counter_group_meta['queue_counter']['group_name'] + counter_map = counter_group_meta['queue_counter']['name_map'] + self.set_flex_counter_group_status(counter_key, counter_map) + + # receive port info + fvs = self.config_db.get_entry("PORT", PORT) + assert len(fvs) > 0 + + # save all the oids of the pg drop counters + oid_list = [] + counters_queue_map = self.counters_db.get_entry("COUNTERS_QUEUE_NAME_MAP", "") + for key, oid in counters_queue_map.items(): + if PORT in key: + oid_list.append(oid) + fields = self.flex_db.get_entry("FLEX_COUNTER_TABLE", counter_stat + ":%s" % oid) + assert len(fields) == 1 + oid_list_len = len(oid_list) + + # get port oid + port_oid = self.counters_db.get_entry(PORT_MAP, "")[PORT] + + # remove port and verify that it was removed properly + self.dvs_port.remove_port(PORT) + dvs.get_asic_db().wait_for_deleted_entry("ASIC_STATE:SAI_OBJECT_TYPE_PORT", port_oid) + + # verify counters were removed from flex counter table + for oid in oid_list: + fields = self.flex_db.get_entry("FLEX_COUNTER_TABLE", counter_stat + ":%s" % oid) + assert len(fields) == 0 + + # verify that port counter maps were removed from counters db + counters_queue_map = self.counters_db.get_entry("COUNTERS_QUEUE_NAME_MAP", "") + for key in counters_queue_map.keys(): + if PORT in key: + assert False + + # add port and wait until the port is added on asic db + num_of_keys_without_port = len(dvs.get_asic_db().get_keys("ASIC_STATE:SAI_OBJECT_TYPE_PORT")) + + self.config_db.create_entry("PORT", PORT, fvs) + + dvs.get_asic_db().wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_PORT", num_of_keys_without_port + 1) + dvs.get_counters_db().wait_for_fields("COUNTERS_QUEUE_NAME_MAP", "", ["%s:0"%(PORT)]) + + # verify queue counters were added + oid_list = [] + counters_queue_map = self.counters_db.get_entry("COUNTERS_QUEUE_NAME_MAP", "") + + for key, oid in counters_queue_map.items(): + if PORT in key: + oid_list.append(oid) + fields = self.flex_db.get_entry("FLEX_COUNTER_TABLE", counter_stat + ":%s" % oid) + assert len(fields) == 1 + # the number of the oids needs to be the same as the original number of oids (before removing a port and adding) + assert oid_list_len == len(oid_list) diff --git a/tests/test_pg_drop_counter.py b/tests/test_pg_drop_counter.py index 1cdd834747..b3682881de 100644 --- a/tests/test_pg_drop_counter.py +++ b/tests/test_pg_drop_counter.py @@ -9,6 +9,9 @@ pg_drop_attr = "SAI_INGRESS_PRIORITY_GROUP_STAT_DROPPED_PACKETS" +PORT = "Ethernet0" + +@pytest.mark.usefixtures('dvs_port_manager') class TestPGDropCounter(object): DEFAULT_POLL_INTERVAL = 10 pgs = {} @@ -73,8 +76,7 @@ def clear_flex_counter(self): self.config_db.delete_entry("FLEX_COUNTER_TABLE", "PG_DROP") self.config_db.delete_entry("FLEX_COUNTER_TABLE", "PG_WATERMARK") - - + def test_pg_drop_counters(self, dvs): self.setup_dbs(dvs) self.pgs = self.asic_db.get_keys("ASIC_STATE:SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP") @@ -94,3 +96,49 @@ def test_pg_drop_counters(self, dvs): self.verify_value(dvs, self.pgs, pg_drop_attr, "123") finally: self.clear_flex_counter() + + def test_pg_drop_counter_port_add_remove(self, dvs): + self.setup_dbs(dvs) + + try: + # configure pg drop flex counter + self.set_up_flex_counter() + + # receive port info + fvs = self.config_db.get_entry("PORT", PORT) + assert len(fvs) > 0 + + # save all the oids of the pg drop counters + oid_list = [] + for priority in range(0,7): + oid_list.append(dvs.get_counters_db().get_entry("COUNTERS_PG_NAME_MAP", "")["%s:%d"%(PORT, priority)]) + # verify that counters exists on flex counter + fields = self.flex_db.get_entry("FLEX_COUNTER_TABLE", "PG_WATERMARK_STAT_COUNTER:%s"%oid_list[-1]) + assert len(fields) == 1 + + # remove port + port_oid = self.counters_db.get_entry("COUNTERS_PORT_NAME_MAP", "")[PORT] + self.dvs_port.remove_port(PORT) + dvs.get_asic_db().wait_for_deleted_entry("ASIC_STATE:SAI_OBJECT_TYPE_PORT", port_oid) + + # verify counters were removed from flex counter table + for oid in oid_list: + fields = self.flex_db.get_entry("FLEX_COUNTER_TABLE", "PG_WATERMARK_STAT_COUNTER:%s"%oid) + assert len(fields) == 0 + + # add port and wait until the port is added on asic db + num_of_keys_without_port = len(dvs.get_asic_db().get_keys("ASIC_STATE:SAI_OBJECT_TYPE_PORT")) + self.config_db.create_entry("PORT", PORT, fvs) + dvs.get_asic_db().wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_PORT", num_of_keys_without_port + 1) + dvs.get_counters_db().wait_for_fields("COUNTERS_PG_NAME_MAP", "", ["%s:0"%(PORT)]) + + # verify counter was added + for priority in range(0,7): + oid = dvs.get_counters_db().get_entry("COUNTERS_PG_NAME_MAP", "")["%s:%d"%(PORT, priority)] + + # verify that counters exists on flex counter + fields = self.flex_db.get_entry("FLEX_COUNTER_TABLE", "PG_WATERMARK_STAT_COUNTER:%s"%oid) + assert len(fields) == 1 + + finally: + self.clear_flex_counter()