From 438b77565009e56c0947bcc8551ff3f644c2220a Mon Sep 17 00:00:00 2001 From: liora <liora@nvidia.com> Date: Tue, 24 Jan 2023 16:05:47 +0000 Subject: [PATCH 1/5] Add support for 4600/4600C/2201 platforms with sonic interface names aligned to 4 instead of 8. Replace system calls to Python library functions when accessing Redis DB. --- .../ecmp_calculator/ecmp_calc.py | 47 ++++++++++-------- .../docker-syncd-mlnx/lib/port_utils.py | 48 ++++++++++++++++--- 2 files changed, 69 insertions(+), 26 deletions(-) diff --git a/platform/mellanox/docker-syncd-mlnx/ecmp_calculator/ecmp_calc.py b/platform/mellanox/docker-syncd-mlnx/ecmp_calculator/ecmp_calc.py index 286a40fd2027..a1e12dddf2f7 100755 --- a/platform/mellanox/docker-syncd-mlnx/ecmp_calculator/ecmp_calc.py +++ b/platform/mellanox/docker-syncd-mlnx/ecmp_calculator/ecmp_calc.py @@ -23,14 +23,18 @@ PORT, VPORT, VLAN, SX_ENTRY_NOT_FOUND from packet_scheme import PACKET_SCHEME from port_utils import sx_get_ports_map, is_lag +from swsscommon.swsscommon import ConfigDBConnector, DBConnector, Table IP_VERSION_IPV4 = 1 IP_VERSION_IPV6 = 2 -PORT_CHANNEL_IDX = 1 +PORT_CHANNEL_IDX = 0 VRF_NAME_IDX = 1 IP_VERSION_MAX_MASK_LEN = {IP_VERSION_IPV4: 32, IP_VERSION_IPV6: 128} +APPL_DB_NAME = 'APPL_DB' INTF_TABLE = 'INTF_TABLE' +VRF_TABLE = 'VRF_TABLE' +LAG_MEMBER_TABLE = 'LAG_MEMBER_TABLE' HASH_CALC_PATH = '/usr/bin/sx_hash_calculator' HASH_CALC_INPUT_FILE = "/tmp/hash_calculator_input.json" HASH_CALC_OUTPUT_FILE = "/tmp/hash_calculator_output.json" @@ -113,6 +117,8 @@ def __init__(self): self.egress_ports = [] self.debug = False + self.config_db = ConfigDBConnector() + self.appl_db = DBConnector(APPL_DB_NAME, 0) self.open_sdk_connection() self.init_ports_map() self.get_active_vrids() @@ -137,7 +143,7 @@ def debug_print(self, *args, **kwargs): print(*args, **kwargs) def init_ports_map(self): - self.ports_map = sx_get_ports_map(self.handle) + self.ports_map = sx_get_ports_map(self.handle, self.config_db) def validate_ingress_port(self, interface): if interface not in self.ports_map.values(): @@ -156,15 +162,12 @@ def validate_args(self, interface, packet, vrf, debug): if not self.validate_vrf(): raise ValueError("VRF validation failed: VRF {} does not exist".format(self.user_vrf)) - def validate_vrf(self): - query_output = exec_cmd(['/usr/bin/redis-cli', '-n', '0', 'keys','*VRF*']).strip() - if not query_output: - return False + def validate_vrf(self): + vrf_table = Table(self.appl_db, VRF_TABLE) + vrf_table_keys = vrf_table.getKeys() - vrf_entries= query_output.split('\n') - for entry in vrf_entries: - vrf = entry.split(':')[VRF_NAME_IDX] - if vrf == self.user_vrf: + for key in vrf_table_keys: + if key == self.user_vrf: return True return False @@ -289,26 +292,30 @@ def print_egress_port(self): def is_port_bind_to_user_vrf(self, port_type, port, vlan_id = 0): if port_type == PORT: # INTF_TABLE:Ethernet0 - entry = '{}:{}'.format(INTF_TABLE, port) + entry = '{}'.format(port) elif port_type == VPORT: # INTF_TABLE:Ethernet0.300 - entry = '{}:{}.{}'.format(INTF_TABLE, port, vlan_id) + entry = '{}.{}'.format(port, vlan_id) elif port_type == VLAN: # INTF_TABLE:Vlan300 - entry = '{}:Vlan{}'.format(INTF_TABLE, vlan_id) + entry = 'Vlan{}'.format(vlan_id) + + vrf_table = Table(self.appl_db, INTF_TABLE) + (_, port_vrf) = vrf_table.hget(entry, 'vrf_name') - port_vrf = exec_cmd(['/usr/bin/redis-cli', '-n', '0', 'hget', entry, 'vrf_name']) if self.user_vrf == port_vrf.strip(): return True return False # Get port-channel name for given port-channel member port - def get_port_channel_name(self, port): - query_output = exec_cmd(['/usr/bin/redis-cli', '-n', '0', 'keys','*LAG_MEMBER_TABLE*']) - for line in query_output.split('\n'): - if str(port) in line: - port_channel = line.split(':')[PORT_CHANNEL_IDX] + def get_port_channel_name(self, port): + lag_member_table = Table(self.appl_db, LAG_MEMBER_TABLE) + lag_member_table_keys = lag_member_table.getKeys() + + for key in lag_member_table_keys: + if str(port) in key: + port_channel = key.split(':')[PORT_CHANNEL_IDX] return port_channel raise KeyError("Failed to get port-channel name for interface {}".format(port)) @@ -368,7 +375,7 @@ def get_lag_member(self, logical, flood_case = False): member_index = self.get_lag_member_index(len(lag_members), flood_case) lag_member = lag_members[member_index] - self.debug_print("Lag member from which trafic will egress: {}".format(lag_member)) + self.debug_print("Lag members: {}\nLag member from which trafic will egress: {}".format(lag_members, lag_member)) return lag_member def call_hash_calculator(self, input_dict): diff --git a/platform/mellanox/docker-syncd-mlnx/lib/port_utils.py b/platform/mellanox/docker-syncd-mlnx/lib/port_utils.py index cce63298cf9a..376d3bf53bd7 100755 --- a/platform/mellanox/docker-syncd-mlnx/lib/port_utils.py +++ b/platform/mellanox/docker-syncd-mlnx/lib/port_utils.py @@ -2,25 +2,59 @@ from python_sdk_api.sx_api import * import inspect +import re DEVICE_ID = 1 SWITCH_ID = 0 +PORT_TABLE = 'PORT' +FIRST_LANE_INDEX = 0 ETHERNET_PREFIX = 'Ethernet' ASIC_MAX_LANES = {SX_CHIP_TYPE_SPECTRUM: 4, SX_CHIP_TYPE_SPECTRUM2: 4, SX_CHIP_TYPE_SPECTRUM3: 8, SX_CHIP_TYPE_SPECTRUM4: 8} -def sx_get_ports_map(handle): +def get_ports_lanes_map(config_db): + """ Get lane number of the first lane in use by port for all existing ports. + + Args: + config_db (ConfigDBConnector): Config DB connector + + Returns: + dict: key is lane number of the first lane in use by port, value is SONiC port index (124 for Ethernet124) + """ + lanes_map = {} + config_db.connect() + + ports_table = config_db.get_table(PORT_TABLE) + if ports_table is None: + raise Exception("Can't read {} table".format(PORT_TABLE)) + + ports_table_keys = config_db.get_keys(PORT_TABLE) + for port in ports_table_keys: + port_data = ports_table.get(port) + if port_data is not None: + lanes = port_data.get('lanes') + first_lane = lanes.split(',')[FIRST_LANE_INDEX] + port_idx = re.sub(r"\D", "", port) + lanes_map[int(first_lane)] = int(port_idx) + + return lanes_map + +def sx_get_ports_map(handle, config_db): """ Get ports map from SDK logical index to SONiC index Args: handle (sx_api_handle_t): SDK handle - + config_db (ConfigDBConnector): Config DB connector + Returns: - dict : Dictionary of ports indices. Key is SDK logical index, value is SONiC index (4 for Ethernet4) + dict: key is SDK logical index, value is SONiC index (4 for Ethernet4) """ try: ports_map = {} + # Get lanes map + lanes_map = get_ports_lanes_map(config_db) + # Get chip type chip_type = sx_get_chip_type(handle) @@ -48,7 +82,9 @@ def sx_get_ports_map(handle): lane_index = get_lane_index(lane_bmap, ASIC_MAX_LANES[chip_type]) assert lane_index != -1, "Failed to calculate port index" - sonic_index = label_port * ASIC_MAX_LANES[chip_type] + lane_index; + first_lane = label_port * ASIC_MAX_LANES[chip_type] + lane_index; + sonic_index = lanes_map[first_lane] + sonic_interface = ETHERNET_PREFIX + str(sonic_index) ports_map[logical_port] = sonic_interface @@ -65,7 +101,7 @@ def sx_get_chip_type(handle): handle (sx_api_handle_t): SDK handle Returns: - sx_chip_types_t : Chip type + sx_chip_types_t: Chip type """ try: device_info_cnt_p = new_uint32_t_p() @@ -95,7 +131,7 @@ def get_lane_index(lane_bmap, max_lanes): max_lanes (int): Max lanes in module Returns: - int : index of the first bit set to 1 in lane_bmap + int: index of the first bit set to 1 in lane_bmap """ for lane_idx in range(0, max_lanes): if (lane_bmap & 0x1 == 1): From 03c51724bb3f2b1419e568e88650c8bfa697ebab Mon Sep 17 00:00:00 2001 From: liora <liora@nvidia.com> Date: Mon, 30 Jan 2023 13:24:04 +0000 Subject: [PATCH 2/5] Fix review comments --- .../docker-syncd-mlnx/ecmp_calculator/ecmp_calc.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/platform/mellanox/docker-syncd-mlnx/ecmp_calculator/ecmp_calc.py b/platform/mellanox/docker-syncd-mlnx/ecmp_calculator/ecmp_calc.py index a1e12dddf2f7..2edc8ad4ffbd 100755 --- a/platform/mellanox/docker-syncd-mlnx/ecmp_calculator/ecmp_calc.py +++ b/platform/mellanox/docker-syncd-mlnx/ecmp_calculator/ecmp_calc.py @@ -166,9 +166,8 @@ def validate_vrf(self): vrf_table = Table(self.appl_db, VRF_TABLE) vrf_table_keys = vrf_table.getKeys() - for key in vrf_table_keys: - if key == self.user_vrf: - return True + if self.user_vrf in vrf_table_keys: + return True return False @@ -314,7 +313,7 @@ def get_port_channel_name(self, port): lag_member_table_keys = lag_member_table.getKeys() for key in lag_member_table_keys: - if str(port) in key: + if port in key: port_channel = key.split(':')[PORT_CHANNEL_IDX] return port_channel From cb07ba279b3eb26166594f13e18328c97c0b6b2d Mon Sep 17 00:00:00 2001 From: liora <liora@nvidia.com> Date: Sun, 5 Feb 2023 14:09:50 +0000 Subject: [PATCH 3/5] Fix second review comments --- .../docker-syncd-mlnx/lib/port_utils.py | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/platform/mellanox/docker-syncd-mlnx/lib/port_utils.py b/platform/mellanox/docker-syncd-mlnx/lib/port_utils.py index 376d3bf53bd7..75ec5e4186a4 100755 --- a/platform/mellanox/docker-syncd-mlnx/lib/port_utils.py +++ b/platform/mellanox/docker-syncd-mlnx/lib/port_utils.py @@ -9,8 +9,6 @@ PORT_TABLE = 'PORT' FIRST_LANE_INDEX = 0 ETHERNET_PREFIX = 'Ethernet' -ASIC_MAX_LANES = {SX_CHIP_TYPE_SPECTRUM: 4, SX_CHIP_TYPE_SPECTRUM2: 4, - SX_CHIP_TYPE_SPECTRUM3: 8, SX_CHIP_TYPE_SPECTRUM4: 8} def get_ports_lanes_map(config_db): """ Get lane number of the first lane in use by port for all existing ports. @@ -39,6 +37,30 @@ def get_ports_lanes_map(config_db): return lanes_map +def get_port_max_width(handle): + """ Get max number of lanes in port according to chip type + + Args: + handle (sx_api_handle_t): SDK handle + + Returns: + int: max lanes in port + """ + # Get chip type + chip_type = sx_get_chip_type(handle) + + limits = rm_resources_t() + modes = rm_modes_t() + + rm_chip_limits_get(chip_type, limits) + max_width = limits.port_map_width_max + + # SPC2 ports have 8 lanes but SONiC is using 4 + if chip_type == SX_CHIP_TYPE_SPECTRUM2: + max_width = 4 + + return max_width + def sx_get_ports_map(handle, config_db): """ Get ports map from SDK logical index to SONiC index @@ -55,8 +77,8 @@ def sx_get_ports_map(handle, config_db): # Get lanes map lanes_map = get_ports_lanes_map(config_db) - # Get chip type - chip_type = sx_get_chip_type(handle) + # Get max number of lanes in port + port_max_width = get_port_max_width(handle) # Get ports count port_cnt_p = new_uint32_t_p() @@ -79,10 +101,10 @@ def sx_get_ports_map(handle, config_db): continue # Calculate sonic index (sonic index=4 for Ethernet4) - lane_index = get_lane_index(lane_bmap, ASIC_MAX_LANES[chip_type]) + lane_index = get_lane_index(lane_bmap, port_max_width) assert lane_index != -1, "Failed to calculate port index" - first_lane = label_port * ASIC_MAX_LANES[chip_type] + lane_index; + first_lane = label_port * port_max_width + lane_index; sonic_index = lanes_map[first_lane] sonic_interface = ETHERNET_PREFIX + str(sonic_index) From 69a82db3b6bde21fad53899abce530facbc433d0 Mon Sep 17 00:00:00 2001 From: liora <liora@nvidia.com> Date: Sun, 5 Feb 2023 14:12:37 +0000 Subject: [PATCH 4/5] Remove newline --- platform/mellanox/docker-syncd-mlnx/lib/port_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/platform/mellanox/docker-syncd-mlnx/lib/port_utils.py b/platform/mellanox/docker-syncd-mlnx/lib/port_utils.py index 75ec5e4186a4..15bd50337201 100755 --- a/platform/mellanox/docker-syncd-mlnx/lib/port_utils.py +++ b/platform/mellanox/docker-syncd-mlnx/lib/port_utils.py @@ -51,7 +51,6 @@ def get_port_max_width(handle): limits = rm_resources_t() modes = rm_modes_t() - rm_chip_limits_get(chip_type, limits) max_width = limits.port_map_width_max From f2bc9b013ad064fc891c7542f1ae61a655bdd1a6 Mon Sep 17 00:00:00 2001 From: liora <liora@nvidia.com> Date: Mon, 6 Feb 2023 07:21:40 +0000 Subject: [PATCH 5/5] Fix more review comments --- platform/mellanox/docker-syncd-mlnx/lib/port_utils.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/platform/mellanox/docker-syncd-mlnx/lib/port_utils.py b/platform/mellanox/docker-syncd-mlnx/lib/port_utils.py index 15bd50337201..f00d22d5426c 100755 --- a/platform/mellanox/docker-syncd-mlnx/lib/port_utils.py +++ b/platform/mellanox/docker-syncd-mlnx/lib/port_utils.py @@ -51,7 +51,9 @@ def get_port_max_width(handle): limits = rm_resources_t() modes = rm_modes_t() - rm_chip_limits_get(chip_type, limits) + + rc = rm_chip_limits_get(chip_type, limits) + sx_check_rc(rc) max_width = limits.port_map_width_max # SPC2 ports have 8 lanes but SONiC is using 4 @@ -72,6 +74,8 @@ def sx_get_ports_map(handle, config_db): """ try: ports_map = {} + port_attributes_list = None + port_cnt_p = None # Get lanes map lanes_map = get_ports_lanes_map(config_db)