sonic-buildimage/src/sonic-config-engine/portconfig.py

289 lines
10 KiB
Python
Raw Normal View History

try:
import os
import sys
import json
import ast
import re
from collections import OrderedDict
from swsssdk import ConfigDBConnector
from sonic_py_common import device_info
except ImportError as e:
raise ImportError("%s - required module not found" % str(e))
# 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:
print("error occurred while parsing json: {}".format(sys.exc_info()[1]))
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
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:
if os.path.isfile(candidate):
return candidate
return None
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)
if not port_config_file:
port_config_file = device_info.get_path_to_port_config_file(hwsku, asic)
if not port_config_file:
return ({}, {}, {})
# 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)
def parse_port_config_file(port_config_file):
ports = {}
port_alias_map = {}
port_alias_asic_map = {}
# 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
# 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)
# 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:
port_config_file = device_info.get_path_to_port_config_file(hwsku)
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")
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