Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Mellanox] [ECMP calculator] Add support for 4600/4600C/2201 platforms with different interface naming method #13814

Merged
merged 5 commits into from
Feb 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 27 additions & 21 deletions platform/mellanox/docker-syncd-mlnx/ecmp_calculator/ecmp_calc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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()
Expand All @@ -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():
Expand All @@ -156,16 +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:
return True
if self.user_vrf in vrf_table_keys:
return True

return False

Expand Down Expand Up @@ -289,26 +291,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 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))
Expand Down Expand Up @@ -368,7 +374,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):
Expand Down
83 changes: 72 additions & 11 deletions platform/mellanox/docker-syncd-mlnx/lib/port_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,86 @@

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 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()

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
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

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 = {}
port_attributes_list = None
port_cnt_p = None

# Get chip type
chip_type = sx_get_chip_type(handle)
# Get lanes map
lanes_map = get_ports_lanes_map(config_db)

# 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()
Expand All @@ -45,10 +104,12 @@ def sx_get_ports_map(handle):
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"

sonic_index = 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)
ports_map[logical_port] = sonic_interface

Expand All @@ -65,7 +126,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()
Expand Down Expand Up @@ -95,7 +156,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):
Expand Down