2020-06-18 18:26:09 -05:00
|
|
|
try:
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
import json
|
|
|
|
import ast
|
|
|
|
import re
|
|
|
|
from collections import OrderedDict
|
|
|
|
from swsssdk import ConfigDBConnector
|
2020-09-04 12:19:12 -05:00
|
|
|
from sonic_py_common import device_info
|
2020-06-18 18:26:09 -05:00
|
|
|
except ImportError as e:
|
|
|
|
raise ImportError("%s - required module not found" % str(e))
|
2017-10-24 12:56:09 -05:00
|
|
|
|
2020-06-18 18:26:09 -05:00
|
|
|
# Global Variable
|
|
|
|
PLATFORM_ROOT_PATH = '/usr/share/sonic/device'
|
|
|
|
PLATFORM_ROOT_PATH_DOCKER = '/usr/share/sonic/platform'
|
|
|
|
SONIC_ROOT_PATH = '/usr/share/sonic'
|
|
|
|
HWSKU_ROOT_PATH = '/usr/share/sonic/hwsku'
|
|
|
|
|
|
|
|
PLATFORM_JSON = 'platform.json'
|
|
|
|
PORT_CONFIG_INI = 'port_config.ini'
|
|
|
|
HWSKU_JSON = 'hwsku.json'
|
|
|
|
|
|
|
|
PORT_STR = "Ethernet"
|
|
|
|
BRKOUT_MODE = "default_brkout_mode"
|
|
|
|
CUR_BRKOUT_MODE = "brkout_mode"
|
|
|
|
INTF_KEY = "interfaces"
|
|
|
|
|
|
|
|
BRKOUT_PATTERN = r'(\d{1,3})x(\d{1,3}G)(\[\d{1,3}G\])?(\((\d{1,3})\))?'
|
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Helper Functions
|
|
|
|
#
|
|
|
|
def readJson(filename):
|
|
|
|
# Read 'platform.json' or 'hwsku.json' file
|
|
|
|
try:
|
|
|
|
with open(filename) as fp:
|
|
|
|
try:
|
|
|
|
data = json.load(fp)
|
|
|
|
except json.JSONDecodeError:
|
|
|
|
print("Json file does not exist")
|
|
|
|
data_dict = ast.literal_eval(json.dumps(data))
|
|
|
|
return data_dict
|
|
|
|
except Exception as e:
|
2020-08-19 11:29:40 -05:00
|
|
|
print("error occurred while parsing json: {}".format(sys.exc_info()[1]))
|
2020-06-18 18:26:09 -05:00
|
|
|
return None
|
|
|
|
|
|
|
|
def db_connect_configdb():
|
|
|
|
"""
|
|
|
|
Connect to configdb
|
|
|
|
"""
|
|
|
|
config_db = ConfigDBConnector()
|
|
|
|
if config_db is None:
|
|
|
|
return None
|
|
|
|
try:
|
|
|
|
"""
|
|
|
|
This could be blocking during the config load_minigraph phase,
|
|
|
|
as the CONFIG_DB_INITIALIZED is not yet set in the configDB.
|
|
|
|
We can ignore the check by using config_db.db_connect('CONFIG_DB') instead
|
|
|
|
"""
|
|
|
|
# Connect only if available & initialized
|
|
|
|
config_db.connect(wait_for_init=False)
|
|
|
|
except Exception as e:
|
|
|
|
config_db = None
|
|
|
|
return config_db
|
2017-10-24 12:56:09 -05:00
|
|
|
|
2020-06-18 18:26:09 -05:00
|
|
|
def get_hwsku_file_name(hwsku=None, platform=None):
|
|
|
|
hwsku_candidates_Json = []
|
|
|
|
hwsku_candidates_Json.append(os.path.join(HWSKU_ROOT_PATH, HWSKU_JSON))
|
|
|
|
if hwsku:
|
|
|
|
if platform:
|
|
|
|
hwsku_candidates_Json.append(os.path.join(PLATFORM_ROOT_PATH, platform, hwsku, HWSKU_JSON))
|
|
|
|
hwsku_candidates_Json.append(os.path.join(PLATFORM_ROOT_PATH_DOCKER, hwsku, HWSKU_JSON))
|
|
|
|
hwsku_candidates_Json.append(os.path.join(SONIC_ROOT_PATH, hwsku, HWSKU_JSON))
|
|
|
|
for candidate in hwsku_candidates_Json:
|
2017-10-24 12:56:09 -05:00
|
|
|
if os.path.isfile(candidate):
|
|
|
|
return candidate
|
|
|
|
return None
|
|
|
|
|
2020-06-18 18:26:09 -05:00
|
|
|
def get_port_config(hwsku=None, platform=None, port_config_file=None, hwsku_config_file=None, asic=None):
|
|
|
|
config_db = db_connect_configdb()
|
|
|
|
# If available, Read from CONFIG DB first
|
|
|
|
if config_db is not None and port_config_file is None:
|
|
|
|
|
|
|
|
port_data = config_db.get_table("PORT")
|
|
|
|
if bool(port_data):
|
|
|
|
ports = ast.literal_eval(json.dumps(port_data))
|
|
|
|
port_alias_map = {}
|
|
|
|
port_alias_asic_map = {}
|
|
|
|
for intf_name in ports.keys():
|
|
|
|
port_alias_map[ports[intf_name]["alias"]] = intf_name
|
|
|
|
return (ports, port_alias_map, port_alias_asic_map)
|
2020-05-04 18:15:15 -05:00
|
|
|
|
2017-10-24 12:56:09 -05:00
|
|
|
if not port_config_file:
|
2020-09-04 12:19:12 -05:00
|
|
|
port_config_file = device_info.get_path_to_port_config_file(hwsku, asic)
|
2017-10-24 12:56:09 -05:00
|
|
|
if not port_config_file:
|
2020-05-04 18:15:15 -05:00
|
|
|
return ({}, {}, {})
|
2017-10-24 12:56:09 -05:00
|
|
|
|
|
|
|
|
2020-06-18 18:26:09 -05:00
|
|
|
# Read from 'platform.json' file
|
|
|
|
if port_config_file.endswith('.json'):
|
|
|
|
if not hwsku_config_file:
|
|
|
|
hwsku_json_file = get_hwsku_file_name(hwsku, platform)
|
|
|
|
if not hwsku_json_file:
|
|
|
|
return ({}, {}, {})
|
|
|
|
else:
|
|
|
|
hwsku_json_file = hwsku_config_file
|
|
|
|
|
|
|
|
return parse_platform_json_file(hwsku_json_file, port_config_file)
|
|
|
|
|
|
|
|
# If 'platform.json' file is not available, read from 'port_config.ini'
|
|
|
|
else:
|
|
|
|
return parse_port_config_file(port_config_file)
|
|
|
|
|
2017-10-24 12:56:09 -05:00
|
|
|
def parse_port_config_file(port_config_file):
|
|
|
|
ports = {}
|
|
|
|
port_alias_map = {}
|
2020-05-04 18:15:15 -05:00
|
|
|
port_alias_asic_map = {}
|
2017-10-24 12:56:09 -05:00
|
|
|
# Default column definition
|
|
|
|
titles = ['name', 'lanes', 'alias', 'index']
|
|
|
|
with open(port_config_file) as data:
|
|
|
|
for line in data:
|
|
|
|
if line.startswith('#'):
|
|
|
|
if "name" in line:
|
|
|
|
titles = line.strip('#').split()
|
|
|
|
continue;
|
|
|
|
tokens = line.split()
|
|
|
|
if len(tokens) < 2:
|
|
|
|
continue
|
|
|
|
name_index = titles.index('name')
|
|
|
|
name = tokens[name_index]
|
|
|
|
data = {}
|
|
|
|
for i, item in enumerate(tokens):
|
|
|
|
if i == name_index:
|
|
|
|
continue
|
|
|
|
data[titles[i]] = item
|
|
|
|
data.setdefault('alias', name)
|
|
|
|
ports[name] = data
|
|
|
|
port_alias_map[data['alias']] = name
|
2020-05-04 18:15:15 -05:00
|
|
|
# asic_port_name to sonic_name mapping also included in
|
|
|
|
# port_alias_map
|
|
|
|
if (('asic_port_name' in data) and
|
|
|
|
(data['asic_port_name'] != name)):
|
|
|
|
port_alias_map[data['asic_port_name']] = name
|
|
|
|
# alias to asic_port_name mapping
|
|
|
|
if 'asic_port_name' in data:
|
|
|
|
port_alias_asic_map[data['alias']] = data['asic_port_name'].strip()
|
|
|
|
return (ports, port_alias_map, port_alias_asic_map)
|
2017-10-24 12:56:09 -05:00
|
|
|
|
2020-06-18 18:26:09 -05:00
|
|
|
# Generate configs (i.e. alias, lanes, speed, index) for port
|
|
|
|
def gen_port_config(ports, parent_intf_id, index, alias_at_lanes, lanes, k, offset):
|
|
|
|
if k is not None:
|
|
|
|
num_lane_used, speed, alt_speed, _ , assigned_lane = k[0], k[1], k[2], k[3], k[4]
|
|
|
|
|
|
|
|
# In case of symmetric mode
|
|
|
|
if assigned_lane is None:
|
|
|
|
assigned_lane = len(lanes.split(","))
|
|
|
|
|
|
|
|
parent_intf_id = int(offset)+int(parent_intf_id)
|
|
|
|
alias_start = 0 + offset
|
|
|
|
|
|
|
|
step = int(assigned_lane)//int(num_lane_used)
|
|
|
|
for i in range(0,int(assigned_lane), step):
|
|
|
|
intf_name = PORT_STR + str(parent_intf_id)
|
|
|
|
ports[intf_name] = {}
|
|
|
|
ports[intf_name]['alias'] = alias_at_lanes.split(",")[alias_start]
|
|
|
|
ports[intf_name]['lanes'] = ','.join(lanes.split(",")[alias_start:alias_start+step])
|
|
|
|
if speed:
|
|
|
|
speed_pat = re.search("^((\d+)G|\d+)$", speed.upper())
|
|
|
|
if speed_pat is None:
|
|
|
|
raise Exception('{} speed is not Supported...'.format(speed))
|
|
|
|
speed_G, speed_orig = speed_pat.group(2), speed_pat.group(1)
|
|
|
|
if speed_G:
|
|
|
|
conv_speed = int(speed_G)*1000
|
|
|
|
else:
|
|
|
|
conv_speed = int(speed_orig)
|
|
|
|
ports[intf_name]['speed'] = str(conv_speed)
|
|
|
|
else:
|
|
|
|
raise Exception('Regex return for speed is None...')
|
|
|
|
|
|
|
|
ports[intf_name]['index'] = index.split(",")[alias_start]
|
|
|
|
ports[intf_name]['admin_status'] = "up"
|
|
|
|
|
|
|
|
parent_intf_id += step
|
|
|
|
alias_start += step
|
|
|
|
|
|
|
|
offset = int(assigned_lane) + int(offset)
|
|
|
|
return offset
|
|
|
|
else:
|
|
|
|
raise Exception('Regex return for k is None...')
|
|
|
|
|
|
|
|
"""
|
|
|
|
Given a port and breakout mode, this method returns
|
|
|
|
the list of child ports using platform_json file
|
|
|
|
"""
|
|
|
|
def get_child_ports(interface, breakout_mode, platform_json_file):
|
|
|
|
child_ports = {}
|
|
|
|
|
|
|
|
port_dict = readJson(platform_json_file)
|
|
|
|
|
|
|
|
index = port_dict[INTF_KEY][interface]['index']
|
|
|
|
alias_at_lanes = port_dict[INTF_KEY][interface]['alias_at_lanes']
|
|
|
|
lanes = port_dict[INTF_KEY][interface]['lanes']
|
|
|
|
|
|
|
|
"""
|
|
|
|
Example of match_list for some breakout_mode using regex
|
|
|
|
Breakout Mode -------> Match_list
|
|
|
|
-----------------------------
|
|
|
|
2x25G(2)+1x50G(2) ---> [('2', '25G', None, '(2)', '2'), ('1', '50G', None, '(2)', '2')]
|
|
|
|
1x50G(2)+2x25G(2) ---> [('1', '50G', None, '(2)', '2'), ('2', '25G', None, '(2)', '2')]
|
|
|
|
1x100G[40G] ---------> [('1', '100G', '[40G]', None, None)]
|
|
|
|
2x50G ---------------> [('2', '50G', None, None, None)]
|
|
|
|
"""
|
|
|
|
# Asymmetric breakout mode
|
|
|
|
if re.search("\+",breakout_mode) is not None:
|
|
|
|
breakout_parts = breakout_mode.split("+")
|
|
|
|
match_list = [re.match(BRKOUT_PATTERN, i).groups() for i in breakout_parts]
|
|
|
|
|
|
|
|
# Symmetric breakout mode
|
|
|
|
else:
|
|
|
|
match_list = [re.match(BRKOUT_PATTERN, breakout_mode).groups()]
|
|
|
|
|
|
|
|
offset = 0
|
|
|
|
parent_intf_id = int(re.search("Ethernet(\d+)", interface).group(1))
|
|
|
|
for k in match_list:
|
|
|
|
offset = gen_port_config(child_ports, parent_intf_id, index, alias_at_lanes, lanes, k, offset)
|
|
|
|
return child_ports
|
|
|
|
|
|
|
|
def parse_platform_json_file(hwsku_json_file, platform_json_file):
|
|
|
|
ports = {}
|
|
|
|
port_alias_map = {}
|
|
|
|
port_alias_asic_map = {}
|
|
|
|
|
|
|
|
port_dict = readJson(platform_json_file)
|
|
|
|
hwsku_dict = readJson(hwsku_json_file)
|
|
|
|
|
|
|
|
if not port_dict:
|
|
|
|
raise Exception("port_dict is none")
|
|
|
|
if not hwsku_dict:
|
|
|
|
raise Exception("hwsku_dict is none")
|
|
|
|
|
|
|
|
if INTF_KEY not in port_dict or INTF_KEY not in hwsku_dict:
|
|
|
|
raise Exception("INTF_KEY is not present in appropriate file")
|
|
|
|
|
|
|
|
for intf in port_dict[INTF_KEY]:
|
|
|
|
if intf not in hwsku_dict[INTF_KEY]:
|
|
|
|
raise Exception("{} is not available in hwsku_dict".format(intf))
|
|
|
|
|
|
|
|
# take default_brkout_mode from hwsku.json
|
|
|
|
brkout_mode = hwsku_dict[INTF_KEY][intf][BRKOUT_MODE]
|
|
|
|
|
|
|
|
child_ports = get_child_ports(intf, brkout_mode, platform_json_file)
|
|
|
|
ports.update(child_ports)
|
|
|
|
|
|
|
|
if not ports:
|
|
|
|
raise Exception("Ports dictionary is empty")
|
|
|
|
|
|
|
|
for i in ports.keys():
|
|
|
|
port_alias_map[ports[i]["alias"]]= i
|
|
|
|
return (ports, port_alias_map, port_alias_asic_map)
|
|
|
|
|
|
|
|
|
|
|
|
def get_breakout_mode(hwsku=None, platform=None, port_config_file=None):
|
|
|
|
if not port_config_file:
|
2020-09-04 12:19:12 -05:00
|
|
|
port_config_file = device_info.get_path_to_port_config_file(hwsku)
|
2020-06-18 18:26:09 -05:00
|
|
|
if not port_config_file:
|
|
|
|
return None
|
|
|
|
if port_config_file.endswith('.json'):
|
|
|
|
hwsku_json_file = get_hwsku_file_name(hwsku, platform)
|
|
|
|
if not hwsku_json_file:
|
|
|
|
raise Exception("'hwsku_json' file does not exist!!! This file is necessary to proceed forward.")
|
|
|
|
|
|
|
|
return parse_breakout_mode(hwsku_json_file)
|
|
|
|
else:
|
|
|
|
return None
|
|
|
|
|
|
|
|
def parse_breakout_mode(hwsku_json_file):
|
|
|
|
brkout_table = {}
|
|
|
|
hwsku_dict = readJson(hwsku_json_file)
|
|
|
|
if not hwsku_dict:
|
|
|
|
raise Exception("hwsku_dict is empty")
|
|
|
|
if INTF_KEY not in hwsku_dict:
|
|
|
|
raise Exception("INTF_KEY is not present in hwsku_dict")
|
2017-10-24 12:56:09 -05:00
|
|
|
|
2020-06-18 18:26:09 -05:00
|
|
|
for intf in hwsku_dict[INTF_KEY]:
|
|
|
|
brkout_table[intf] = {}
|
|
|
|
brkout_table[intf][CUR_BRKOUT_MODE] = hwsku_dict[INTF_KEY][intf][BRKOUT_MODE]
|
|
|
|
return brkout_table
|