diff --git a/scripts/internal_links_monitor.py b/scripts/internal_links_monitor.py new file mode 100644 index 0000000000..3aba3c0bd8 --- /dev/null +++ b/scripts/internal_links_monitor.py @@ -0,0 +1,235 @@ +#!/usr/bin/env python2.7 +# -*- coding: utf-8 -*- + +import syslog + + +from swsssdk import SonicV2Connector +from sonic_py_common import multi_asic + +class InternalLinkErrMontoring(): + '''Class to monitor the internal link errors for a given namespace''' + + def __init__(self, namespace, port_name_map, filter_for_backend_ports=None): + '''Initialize the class with the namespace and port_name_map in counters db''' + self.namespace = namespace + self.port_name_map = port_name_map + self.filter_for_backend_ports = filter_for_backend_ports + self.port_map = self.get_port_map() + + @property + def counter_db(self): + '''Return the counter db object''' + db = SonicV2Connector(namespace=self.namespace) + db.connect('COUNTERS_DB') + return db + + def get_port_map(self): + ''' + Return the port map from the counter db + for the port_names in the port_name_map + Additonally the port map can be filtered for backend ports + ''' + ports = self.counter_db.get_all('COUNTERS_DB', self.port_name_map) + if self.filter_for_backend_ports: + port_to_mon = self.filter_for_backend_ports(self.namespace, ports) + return port_to_mon + + @property + def port_counters(self): + '''Return the port counters for all the port in the port_map''' + port_counters = {} + for port_name, port_oid in self.port_map.items(): + port_counter = self.counter_db.get_all( + "COUNTERS_DB", 'COUNTERS:{}'.format(port_oid)) + port_counters[port_name] = port_counter + return port_counters + + def get_ports_error_above_threshold(self, counter_name, threshold): + ''' + Return the list of ports which have the counter value above the threshold + ''' + err_ports = [] + for port_name, port_counter in self.port_counters.items(): + try: + port_counter_value = port_counter[counter_name] + if int(port_counter_value) > int(threshold): + err_ports.append(port_name) + except KeyError: + print('Bad counter_name') + return err_ports + + def monitor(self, namespace, error_counter_names, threshold ): + err_ports = [] + for counter_name in error_counter_names: + err_ports_per_counter = self.get_ports_error_above_threshold( + counter_name,threshold) + if err_ports_per_counter: + syslog.syslog(syslog.LOG_CRIT, + ' {} error above threshold on internal port {} in {} '.format(counter_name,err_ports_per_counter, namespace)) + err_ports.extend(err_ports_per_counter) + return err_ports + + +class PacketChassisInternalLinkMontoring(): + '''A class for monitoring internal links in a Packet Chassis. + + Attributes: + link_monitor (dict): A dictionary of LinkMonitor objects, keyed by namespace. + error_counter_names (list): A list of error counter names to monitor. + threshold (int): The threshold for error counters. + ''' + + def __init__(self): + '''Initializes a PacketChassisInternalLinkMontoring object. + + Args: + link_monitor (dict): A dictionary of LinkMonitor objects, keyed by namespace. + error_counter_names (list): A list of error counter names to monitor. + threshold (int): The threshold for error counters. + + Returns: + None + ''' + self.link_monitor = {} + self.appdb = {} + self.configdb = {} + for namespace in self.namespaces: + self.appdb[namespace] = self.appl_db(namespace) + self.configdb[namespace] = self.config_db(namespace) + self.link_monitor[namespace] = InternalLinkErrMontoring( + namespace=namespace, port_name_map='COUNTERS_PORT_NAME_MAP', + filter_for_backend_ports=self.filter_for_backend_ports) + self.error_counter_names = ['SAI_PORT_STAT_IF_IN_ERRORS', + 'SAI_PORT_STAT_IF_OUT_ERRORS'] + # Using fixed values for 201911 + self.threshold = 0 + self.mitigationActionEnabled = True + + @property + def namespaces(self): + namespaces = [] + all_namespaces = multi_asic.get_all_namespaces() + namespaces = all_namespaces['front_ns'] + all_namespaces['back_ns'] + return namespaces + + def config_db(self,namespace): + '''Returns the config db object for the namespace''' + db = SonicV2Connector(namespace=namespace) + db.connect('CONFIG_DB') + return db + + def appl_db(self, namespace): + '''Returns the application db object for the namespace''' + db = SonicV2Connector(namespace=namespace) + db.connect('APPL_DB') + return db + + def get_port_status(self, namespace, port_name): + ''' Returns operational status of give port + When port is admin shut in CONFIG_DB, it might take some time for port to be oper down in APPL_DB. + As such, status of ports which are admin shut in config DB is reported as down + ''' + port_cfg = self.configdb[namespace].get_all('CONFIG_DB', 'PORT|{}'.format(port_name)) + port_info = self.appdb[namespace].get_all('APPL_DB', 'PORT_TABLE:{}'.format(port_name)) + if port_cfg: + if port_cfg['admin_status'] == 'up': + if port_info: + return port_info['oper_status'] + return 'down' + + def filter_for_backend_ports(self, namespace, port_map): + ''' Returns only internal (backend) ports which are operationally up for monitoring ''' + filtered_port_map = {} + for k,v in port_map.items(): + if k.startswith('Ethernet-BP'): + if self.get_port_status(namespace, k) == 'up': + filtered_port_map[k] = v + return filtered_port_map + + def get_lag_name_for_port(self, namespace, port_name): + ''' Returns name of the portchannel in which the given port is a member ''' + lag_member = self.appdb[namespace].keys('APPL_DB', 'LAG_MEMBER_TABLE:*:{}'.format(port_name)) + if len(lag_member): + table = lag_member[0].find(":") + 1 + port = lag_member[0].find(":", table) + return lag_member[0][table:port] + return '' + + def get_min_links_for_lag(self, namespace, lag_name): + ''' Returns min_links configuration of the given portchannel ''' + lag_info = self.configdb[namespace].get_all('CONFIG_DB', 'PORTCHANNEL|{}'.format(lag_name)) + return int(lag_info['min_links']) + + def get_active_lag_member_count(self, namespace, lag_name): + ''' Returns number of member ports that are operationally up in the given portchannel ''' + lag_members = self.appdb[namespace].keys('APPL_DB', 'LAG_MEMBER_TABLE:{}:*'.format(lag_name)) + active_count = 0 + for member in lag_members: + port = member.rsplit(':', 1)[1] + if self.get_port_status(namespace, port) == 'up': + active_count += 1 + return active_count + + def isolate_lag_member(self, namespace, port_name): + ''' Set admin_status of given port to down in the CONFIG_DB ''' + ret = self.configdb[namespace].set('CONFIG_DB', 'PORT|{}'.format(port_name), 'admin_status', 'down') + if ret == 0: + syslog.syslog(syslog.LOG_CRIT, + 'Internal port {} has been shutdown to mitigate errors'.format(port_name)) + else: + syslog.syslog(syslog.LOG_CRIT, + 'Unable to shutdown internal port {}, return code {}'.format(port_name, ret)) + def attempt_to_mitigate_ports(self, namespace, err_port_per_ns): + ''' Attempt to isolate given list of ports + 1. Check if number of active links in the portchannel where the port is a member is greater + than min_links. + a. If active links is greater, shutdown the port + b. If not, return after generating syslog + ''' + + for port_name in err_port_per_ns: + syslog.syslog(syslog.LOG_INFO, "Attempting mitigation of port {}".format(port_name)) + lag_name = self.get_lag_name_for_port(namespace, port_name) + active_count = self.get_active_lag_member_count(namespace, lag_name) + min_links = self.get_min_links_for_lag(namespace, lag_name) + + if active_count > min_links: + syslog.syslog(syslog.LOG_INFO, + "Active port count {} in {} sufficient to take mitigate {} (min_links {})".format( + active_count, lag_name, port_name, min_links)) + self.isolate_lag_member(namespace, port_name) + else: + syslog.syslog(syslog.LOG_CRIT, + "Active port count {} in {} insufficient to take mitigate {} (min_links {})".format( + active_count, lag_name, port_name, min_links)) + + def monitor(self): + ''' + Monitors the error counters for each internal port in each namespace. + If any error counters are above the specified threshold, a syslog message is generated. + ''' + all_error_ports = [] + for namespace, link_mon in self.link_monitor.items(): + err_port_per_ns = link_mon.monitor(namespace, self.error_counter_names, self.threshold) + if err_port_per_ns: + all_error_ports.extend(err_port_per_ns) + syslog.syslog(syslog.LOG_CRIT, + '{} internal ports in {} have errors above threshold'.format(len(err_port_per_ns), namespace)) + if self.mitigationActionEnabled: + self.attempt_to_mitigate_ports(namespace, err_port_per_ns) + return len(all_error_ports) + +def main(): + if multi_asic.is_multi_asic(): + link_monitor = PacketChassisInternalLinkMontoring() + num_of_err_ports = link_monitor.monitor() + if num_of_err_ports: + syslog.syslog(syslog.LOG_CRIT, '{} internal ports have errors above threshold'.format(num_of_err_ports)) + return -1 + return 0 + + + +if __name__ == '__main__': + main() diff --git a/setup.py b/setup.py index 5929c7d8ca..acfd414d00 100644 --- a/setup.py +++ b/setup.py @@ -98,6 +98,7 @@ 'scripts/fdbclear', 'scripts/fdbshow', 'scripts/generate_dump', + 'scripts/internal_links_monitor.py', 'scripts/intfutil', 'scripts/intfstat', 'scripts/ipintutil', diff --git a/sonic-utilities-tests/internal_links_monitor_test.py b/sonic-utilities-tests/internal_links_monitor_test.py new file mode 100644 index 0000000000..ec70db7764 --- /dev/null +++ b/sonic-utilities-tests/internal_links_monitor_test.py @@ -0,0 +1,85 @@ +import imp +import os +import importlib +import mock_tables.dbconnector +import mock_tables.mock_multi_asic + +int_errors = importlib.import_module("scripts.internal_links_monitor") + +class TestPacketChassisInternalLinkMontoring(object): + @classmethod + def setup_class(cls): + imp.reload(mock_tables.mock_multi_asic) + mock_tables.dbconnector.load_namespace_config() + os.environ['UTILITIES_UNIT_TESTING'] = "2" + + @classmethod + def teardown_class(cls): + os.environ['UTILITIES_UNIT_TESTING'] = "0" + + def test_get_port_status(self): + port_name = 'Ethernet-BP16' + namespace = 'asic0' + link_monitor = int_errors.PacketChassisInternalLinkMontoring() + assert link_monitor.get_port_status(namespace, port_name) == 'up' + + def test_isolate_lag_member(self): + port_name = 'Ethernet-BP4' + namespace = 'asic0' + link_monitor = int_errors.PacketChassisInternalLinkMontoring() + assert link_monitor.get_port_status(namespace, port_name) == 'up' + link_monitor.isolate_lag_member(namespace, port_name) + assert link_monitor.get_port_status(namespace, port_name) == 'down' + + def test_get_lag_name_for_port(self): + port_name = 'Ethernet-BP4' + namespace = 'asic0' + link_monitor = int_errors.PacketChassisInternalLinkMontoring() + assert link_monitor.get_lag_name_for_port(namespace, port_name) == 'PortChannel4001' + + def test_get_active_lag_member_count(self): + lag_name = 'PortChannel4001' + namespace = 'asic0' + link_monitor = int_errors.PacketChassisInternalLinkMontoring() + assert link_monitor.get_active_lag_member_count(namespace, lag_name) == 4 + + def test_mem_down_get_active_lag_member_count(self): + lag_name = 'PortChannel4001' + namespace = 'asic0' + port_name = 'Ethernet-BP4' + link_monitor = int_errors.PacketChassisInternalLinkMontoring() + link_monitor.isolate_lag_member(namespace, port_name) + assert link_monitor.get_active_lag_member_count(namespace, lag_name) == 3 + + def test_get_min_links_for_lag(self): + lag_name = 'PortChannel4001' + namespace = 'asic0' + link_monitor = int_errors.PacketChassisInternalLinkMontoring() + assert link_monitor.get_min_links_for_lag(namespace, lag_name) == 3 + + def test_attempt_to_mitigate_ports(self): + port_list = ['Ethernet-BP0', 'Ethernet-BP4'] + namespace = 'asic0' + lag_name = 'PortChannel4001' + link_monitor = int_errors.PacketChassisInternalLinkMontoring() + link_monitor.attempt_to_mitigate_ports(namespace, port_list) + + # Only one port should be brought down due to min_links check + assert link_monitor.get_active_lag_member_count(namespace, lag_name) == 3 + + def test_monitor(self): + link_monitor = int_errors.PacketChassisInternalLinkMontoring() + link_monitor.monitor() + + # Validation on asic0 + assert link_monitor.get_port_status('asic0', 'Ethernet-BP0') == 'up' + assert link_monitor.get_port_status('asic0', 'Ethernet-BP4') == 'up' + assert link_monitor.get_port_status('asic0', 'Ethernet-BP8') == 'down' + # Action should be skipped due to min_links check + assert link_monitor.get_port_status('asic0', 'Ethernet-BP16') == 'up' + + # Validation on asic1 + assert link_monitor.get_port_status('asic1', 'Ethernet-BP256') == 'down' + assert link_monitor.get_port_status('asic1', 'Ethernet-BP260') == 'up' + # Action should be skipped due to min_links check + assert link_monitor.get_port_status('asic1', 'Ethernet-BP264') == 'up' \ No newline at end of file diff --git a/sonic-utilities-tests/mock_tables/asic0/appl_db.json b/sonic-utilities-tests/mock_tables/asic0/appl_db.json index cfe085962f..d1a8539a2d 100644 --- a/sonic-utilities-tests/mock_tables/asic0/appl_db.json +++ b/sonic-utilities-tests/mock_tables/asic0/appl_db.json @@ -47,6 +47,30 @@ "speed": "40000", "asic_port_name": "Eth17-ASIC0" }, + "PORT_TABLE:Ethernet-BP8": { + "oper_status": "up", + "lanes": "101,102,103,104", + "description": "ASIC1:Eth2-ASIC1", + "pfc_asym": "off", + "mtu": "9100", + "alias": "Ethernet-BP8", + "admin_status": "up", + "role": "Int", + "speed": "40000", + "asic_port_name": "Eth18-ASIC0" + }, + "PORT_TABLE:Ethernet-BP16": { + "oper_status": "up", + "lanes": "105,106,107,108", + "description": "ASIC1:Eth3-ASIC1", + "pfc_asym": "off", + "mtu": "9100", + "alias": "Ethernet-BP16", + "admin_status": "up", + "role": "Int", + "speed": "40000", + "asic_port_name": "Eth19-ASIC0" + }, "LAG_MEMBER_TABLE:PortChannel1002:Ethernet0": { "status": "disabled" }, @@ -59,6 +83,12 @@ "LAG_MEMBER_TABLE:PortChannel4001:Ethernet-BP4": { "status": "enabled" }, + "LAG_MEMBER_TABLE:PortChannel4001:Ethernet-BP8": { + "status": "enabled" + }, + "LAG_MEMBER_TABLE:PortChannel4001:Ethernet-BP16": { + "status": "enabled" + }, "LAG_TABLE:PortChannel1002": { "admin_status": "up", "mtu": "9100", diff --git a/sonic-utilities-tests/mock_tables/asic0/config_db.json b/sonic-utilities-tests/mock_tables/asic0/config_db.json index 0365191c1c..5d1de12484 100644 --- a/sonic-utilities-tests/mock_tables/asic0/config_db.json +++ b/sonic-utilities-tests/mock_tables/asic0/config_db.json @@ -60,6 +60,28 @@ "speed": "40000", "asic_port_name": "Eth17-ASIC0" }, + "PORT|Ethernet-BP8": { + "lanes": "101,102,103,104", + "description": "ASIC1:Eth2-ASIC1", + "pfc_asym": "off", + "mtu": "9100", + "alias": "Ethernet-BP8", + "admin_status": "up", + "role": "Int", + "speed": "40000", + "asic_port_name": "Eth18-ASIC0" + }, + "PORT|Ethernet-BP16": { + "lanes": "105,106,107,108", + "description": "ASIC1:Eth3-ASIC1", + "pfc_asym": "off", + "mtu": "9100", + "alias": "Ethernet-BP16", + "admin_status": "up", + "role": "Int", + "speed": "40000", + "asic_port_name": "Eth19-ASIC0" + }, "PORTCHANNEL|PortChannel1002": { "admin_status": "up", "members@": "Ethernet0,Ethernet4", @@ -68,8 +90,8 @@ }, "PORTCHANNEL|PortChannel4001": { "admin_status": "up", - "members@": "Ethernet-BP0,Ethernet-BP4", - "min_links": "2", + "members@": "Ethernet-BP0,Ethernet-BP4,Ethernet-BP8,Ethernet-BP16", + "min_links": "3", "mtu": "9100" }, "PORTCHANNEL_MEMBER|PortChannel1002|Ethernet0": { @@ -84,6 +106,12 @@ "PORTCHANNEL_MEMBER|PortChannel4001|Ethernet-BP4": { "NULL": "NULL" }, + "PORTCHANNEL_MEMBER|PortChannel4001|Ethernet-BP8": { + "NULL": "NULL" + }, + "PORTCHANNEL_MEMBER|PortChannel4001|Ethernet-BP16": { + "NULL": "NULL" + }, "PFC_WD|Ethernet0": { "action": "drop", "detection_time": "200", diff --git a/sonic-utilities-tests/mock_tables/asic0/counters_db.json b/sonic-utilities-tests/mock_tables/asic0/counters_db.json index 488915a79c..a2f1d7c82a 100644 --- a/sonic-utilities-tests/mock_tables/asic0/counters_db.json +++ b/sonic-utilities-tests/mock_tables/asic0/counters_db.json @@ -1527,6 +1527,7 @@ "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS" : "0", "SAI_PORT_STAT_IF_OUT_OCTETS" : "6000", "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_OUT_ERRORS": "0", "SAI_PORT_STAT_IF_IN_DISCARDS": "1000", "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "800", "SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "100", @@ -1555,6 +1556,7 @@ "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS" : "0", "SAI_PORT_STAT_IF_OUT_OCTETS" : "8000", "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_OUT_ERRORS": "0", "SAI_PORT_STAT_IF_IN_DISCARDS": "1000", "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "800", "SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "100", @@ -1575,14 +1577,74 @@ "SAI_PORT_STAT_PFC_6_TX_PKTS": "816", "SAI_PORT_STAT_PFC_7_TX_PKTS": "817" }, + "COUNTERS:oid:0x100000000000a": { + "SAI_PORT_STAT_IF_IN_UCAST_PKTS": "10", + "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS" : "1000", + "SAI_PORT_STAT_IF_OUT_UCAST_PKTS": "100", + "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS" : "0", + "SAI_PORT_STAT_IF_OUT_OCTETS" : "10000", + "SAI_PORT_STAT_IF_IN_ERRORS": "1005", + "SAI_PORT_STAT_IF_OUT_ERRORS": "0", + "SAI_PORT_STAT_IF_IN_DISCARDS": "0", + "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "400", + "SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "200", + "SAI_PORT_STAT_PFC_0_RX_PKTS": "900", + "SAI_PORT_STAT_PFC_1_RX_PKTS": "901", + "SAI_PORT_STAT_PFC_2_RX_PKTS": "902", + "SAI_PORT_STAT_PFC_3_RX_PKTS": "903", + "SAI_PORT_STAT_PFC_4_RX_PKTS": "904", + "SAI_PORT_STAT_PFC_5_RX_PKTS": "905", + "SAI_PORT_STAT_PFC_6_RX_PKTS": "906", + "SAI_PORT_STAT_PFC_7_RX_PKTS": "907", + "SAI_PORT_STAT_PFC_0_TX_PKTS": "910", + "SAI_PORT_STAT_PFC_1_TX_PKTS": "911", + "SAI_PORT_STAT_PFC_2_TX_PKTS": "912", + "SAI_PORT_STAT_PFC_3_TX_PKTS": "913", + "SAI_PORT_STAT_PFC_4_TX_PKTS": "914", + "SAI_PORT_STAT_PFC_5_TX_PKTS": "915", + "SAI_PORT_STAT_PFC_6_TX_PKTS": "916", + "SAI_PORT_STAT_PFC_7_TX_PKTS": "917" + }, + "COUNTERS:oid:0x100000000000c": { + "SAI_PORT_STAT_IF_IN_UCAST_PKTS": "12", + "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS" : "1200", + "SAI_PORT_STAT_IF_OUT_UCAST_PKTS": "120", + "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS" : "0", + "SAI_PORT_STAT_IF_OUT_OCTETS" : "12000", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_OUT_ERRORS": "2000", + "SAI_PORT_STAT_IF_IN_DISCARDS": "400", + "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "200", + "SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "50", + "SAI_PORT_STAT_PFC_0_RX_PKTS": "1000", + "SAI_PORT_STAT_PFC_1_RX_PKTS": "1001", + "SAI_PORT_STAT_PFC_2_RX_PKTS": "1002", + "SAI_PORT_STAT_PFC_3_RX_PKTS": "1003", + "SAI_PORT_STAT_PFC_4_RX_PKTS": "1004", + "SAI_PORT_STAT_PFC_5_RX_PKTS": "1005", + "SAI_PORT_STAT_PFC_6_RX_PKTS": "1006", + "SAI_PORT_STAT_PFC_7_RX_PKTS": "1007", + "SAI_PORT_STAT_PFC_0_TX_PKTS": "1010", + "SAI_PORT_STAT_PFC_1_TX_PKTS": "1011", + "SAI_PORT_STAT_PFC_2_TX_PKTS": "1012", + "SAI_PORT_STAT_PFC_3_TX_PKTS": "1013", + "SAI_PORT_STAT_PFC_4_TX_PKTS": "1014", + "SAI_PORT_STAT_PFC_5_TX_PKTS": "1015", + "SAI_PORT_STAT_PFC_6_TX_PKTS": "1016", + "SAI_PORT_STAT_PFC_7_TX_PKTS": "1017" + }, "COUNTERS:oid:0x21000000000000": { "SAI_SWITCH_STAT_IN_DROP_REASON_RANGE_BASE": "1000" }, "COUNTERS_PORT_NAME_MAP": { "Ethernet0": "oid:0x1000000000002", "Ethernet4": "oid:0x1000000000004", - "Ethernet-BP0": "oid:0x1000000000006", - "Ethernet-BP4": "oid:0x1000000000008" + "Ethernet-BP0": "oid:0x1000000000006", + "Ethernet-BP4": "oid:0x1000000000008", + "Ethernet-BP8": "oid:0x100000000000a", + "Ethernet-BP16": "oid:0x100000000000c" }, "COUNTERS_LAG_NAME_MAP": { "PortChannel0001": "oid:0x60000000005a1", diff --git a/sonic-utilities-tests/mock_tables/asic1/appl_db.json b/sonic-utilities-tests/mock_tables/asic1/appl_db.json index 3ac977cb02..66c674b5ca 100644 --- a/sonic-utilities-tests/mock_tables/asic1/appl_db.json +++ b/sonic-utilities-tests/mock_tables/asic1/appl_db.json @@ -33,6 +33,17 @@ "speed": "40000", "asic_port_name": "Eth1-ASIC1" }, + "PORT_TABLE:Ethernet-BP264": { + "oper_status": "up", + "lanes": "53,54,55,56", + "description": "ASIC0:Eth18-ASIC0", + "pfc_asym": "off", + "mtu": "9100", + "alias": "Ethernet-BP264", + "admin_status": "up", + "speed": "40000", + "asic_port_name": "Eth2-ASIC1" + }, "LAG_TABLE:PortChannel4009": { "admin_status": "up", "oper_status": "up", @@ -43,5 +54,8 @@ }, "LAG_MEMBER_TABLE:PortChannel4009:Ethernet-BP260": { "status": "enabled" + }, + "LAG_MEMBER_TABLE:PortChannel4009:Ethernet-BP264": { + "status": "enabled" } } diff --git a/sonic-utilities-tests/mock_tables/asic1/config_db.json b/sonic-utilities-tests/mock_tables/asic1/config_db.json index 0a9c1bc8bf..d74656c0ff 100644 --- a/sonic-utilities-tests/mock_tables/asic1/config_db.json +++ b/sonic-utilities-tests/mock_tables/asic1/config_db.json @@ -49,10 +49,21 @@ "role": "Int", "asic_port_name": "Eth1-ASIC1" }, + "PORT|Ethernet-BP264": { + "lanes": "53,54,55,56", + "description": "ASIC0:Eth18-ASIC0", + "pfc_asym": "off", + "mtu": "9100", + "alias": "Ethernet-BP264", + "admin_status": "up", + "speed": "40000", + "role": "Int", + "asic_port_name": "Eth2-ASIC1" + }, "PORTCHANNEL|PortChannel4009": { "admin_status": "up", "members": [ - "Ethernet-BP256,Ethernet-BP260" + "Ethernet-BP256,Ethernet-BP260,Ethernet-BP264" ], "min_links": "2", "mtu": "9100" @@ -63,6 +74,9 @@ "PORTCHANNEL_MEMBER|PortChannel4009|Ethernet-BP260" : { "NULL": "NULL" }, + "PORTCHANNEL_MEMBER|PortChannel4009|Ethernet-BP264" : { + "NULL": "NULL" + }, "PFC_WD|Ethernet-BP256": { "action": "drop", "detection_time": "200", diff --git a/sonic-utilities-tests/mock_tables/asic1/counters_db.json b/sonic-utilities-tests/mock_tables/asic1/counters_db.json index a323ecde3e..9bd35b6a32 100644 --- a/sonic-utilities-tests/mock_tables/asic1/counters_db.json +++ b/sonic-utilities-tests/mock_tables/asic1/counters_db.json @@ -127,6 +127,7 @@ "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS" : "0", "SAI_PORT_STAT_IF_OUT_OCTETS" : "1000", "SAI_PORT_STAT_IF_IN_ERRORS": "10", + "SAI_PORT_STAT_IF_OUT_ERRORS": "0", "SAI_PORT_STAT_IF_IN_DISCARDS": "100", "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "80", "SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "20", @@ -155,6 +156,7 @@ "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS" : "0", "SAI_PORT_STAT_IF_OUT_OCTETS" : "4000", "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_OUT_ERRORS": "0", "SAI_PORT_STAT_IF_IN_DISCARDS": "1000", "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "800", "SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "100", @@ -175,12 +177,42 @@ "SAI_PORT_STAT_PFC_6_TX_PKTS": "116", "SAI_PORT_STAT_PFC_7_TX_PKTS": "117" }, + "COUNTERS:oid:0x1000000000b0a": { + "SAI_PORT_STAT_IF_IN_UCAST_PKTS": "2", + "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS": "0", + "SAI_PORT_STAT_IF_IN_OCTETS" : "200", + "SAI_PORT_STAT_IF_OUT_UCAST_PKTS": "20", + "SAI_PORT_STAT_IF_OUT_NON_UCAST_PKTS" : "0", + "SAI_PORT_STAT_IF_OUT_OCTETS" : "2000", + "SAI_PORT_STAT_IF_IN_ERRORS": "0", + "SAI_PORT_STAT_IF_OUT_ERRORS": "1003", + "SAI_PORT_STAT_IF_IN_DISCARDS": "500", + "SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "200", + "SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "50", + "SAI_PORT_STAT_PFC_0_RX_PKTS": "200", + "SAI_PORT_STAT_PFC_1_RX_PKTS": "201", + "SAI_PORT_STAT_PFC_2_RX_PKTS": "202", + "SAI_PORT_STAT_PFC_3_RX_PKTS": "203", + "SAI_PORT_STAT_PFC_4_RX_PKTS": "204", + "SAI_PORT_STAT_PFC_5_RX_PKTS": "205", + "SAI_PORT_STAT_PFC_6_RX_PKTS": "206", + "SAI_PORT_STAT_PFC_7_RX_PKTS": "207", + "SAI_PORT_STAT_PFC_0_TX_PKTS": "210", + "SAI_PORT_STAT_PFC_1_TX_PKTS": "211", + "SAI_PORT_STAT_PFC_2_TX_PKTS": "212", + "SAI_PORT_STAT_PFC_3_TX_PKTS": "213", + "SAI_PORT_STAT_PFC_4_TX_PKTS": "214", + "SAI_PORT_STAT_PFC_5_TX_PKTS": "215", + "SAI_PORT_STAT_PFC_6_TX_PKTS": "216", + "SAI_PORT_STAT_PFC_7_TX_PKTS": "217" + }, "COUNTERS:oid:0x21000000000000": { "SAI_SWITCH_STAT_IN_DROP_REASON_RANGE_BASE": "1000" }, "COUNTERS_PORT_NAME_MAP": { "Ethernet-BP256": "oid:0x1000000000b06", - "Ethernet-BP260": "oid:0x1000000000b08" + "Ethernet-BP260": "oid:0x1000000000b08", + "Ethernet-BP264": "oid:0x1000000000b0a" }, "COUNTERS_LAG_NAME_MAP": { "PortChannel0001": "oid:0x60000000005a1",