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

[sonic-utilities] CLI support for port auto negotiation #1568

Merged
merged 22 commits into from
May 7, 2021
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
79a7f8e
Add CLIs to support port auto negotiation
Junchao-Mellanox Jan 11, 2021
960ebeb
Adjust CLI for port auto negotiation
Junchao-Mellanox Jan 22, 2021
d328d87
Fix unit test issue
Junchao-Mellanox Feb 1, 2021
6deb7df
Fix unit test issues
Junchao-Mellanox Feb 22, 2021
408a166
Merge commit '42cab68' into port-auto-neg
Junchao-Mellanox Feb 22, 2021
3a6f711
Change autoneg value range from 0|1 to on|off
Junchao-Mellanox Mar 5, 2021
3bc1518
Merge commit '6ced42c' into port-auto-neg
Junchao-Mellanox Mar 12, 2021
e11e288
Fix unit test issue
Junchao-Mellanox Mar 15, 2021
5e2f34e
Fixes issue: db_migrator change cause db_migrator test case failure
Junchao-Mellanox Mar 15, 2021
b7369b8
Fix issues found in manual test
Junchao-Mellanox Mar 17, 2021
81f1da8
Fix issue: db migrator not working for port auto negotiation attributes
Junchao-Mellanox Mar 19, 2021
0f10f46
Add unit test for DB migrator
Junchao-Mellanox Mar 23, 2021
ce6dded
Merge branch 'master' into port-auto-neg
Junchao-Mellanox Mar 25, 2021
2892c4f
Merge commit '9a2872d' into port-auto-neg
Junchao-Mellanox Apr 2, 2021
4ecc4b8
Fix review comments
Junchao-Mellanox Apr 2, 2021
d19e369
Fix review comments
Junchao-Mellanox Apr 2, 2021
0399b08
Fix review comment
Junchao-Mellanox Apr 2, 2021
edc5f51
Merge commit '5976399' into port-auto-neg
Junchao-Mellanox Apr 16, 2021
87d9861
Merge branch 'master' into port-auto-neg
Junchao-Mellanox Apr 28, 2021
8eaf2e8
Merge branch 'master' into port-auto-neg
Junchao-Mellanox May 6, 2021
7c5273a
Update command reference
Junchao-Mellanox May 7, 2021
4adca3e
Merge branch 'port-auto-neg' of github.com:Junchao-Mellanox/sonic-uti…
Junchao-Mellanox May 7, 2021
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
120 changes: 120 additions & 0 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3014,6 +3014,126 @@ def speed(ctx, interface_name, interface_speed, verbose):
command += " -vv"
clicommon.run_command(command, display_cmd=verbose)

#
# 'autoneg' subcommand
#

@interface.command()
@click.pass_context
@click.argument('interface_name', metavar='<interface_name>', required=True)
@click.argument('mode', metavar='<mode>', required=True, type=click.Choice(["enabled", "disabled"]))
@click.option('-v', '--verbose', is_flag=True, help="Enable verbose output")
def autoneg(ctx, interface_name, mode, verbose):
"""Set interface auto negotiation mode"""
# Get the config_db connector
config_db = ctx.obj['config_db']

if clicommon.get_interface_naming_mode() == "alias":
interface_name = interface_alias_to_name(config_db, interface_name)
if interface_name is None:
ctx.fail("'interface_name' is None!")

log.log_info("'interface autoneg {} {}' executing...".format(interface_name, mode))

if ctx.obj['namespace'] is DEFAULT_NAMESPACE:
command = "portconfig -p {} -an {}".format(interface_name, mode)
else:
command = "portconfig -p {} -an {} -n {}".format(interface_name, mode, ctx.obj['namespace'])

if verbose:
command += " -vv"
clicommon.run_command(command, display_cmd=verbose)

#
# 'adv-speeds' subcommand
#

@interface.command()
@click.pass_context
@click.argument('interface_name', metavar='<interface_name>', required=True)
@click.argument('speed_list', metavar='<speed_list>', required=True)
@click.option('-v', '--verbose', is_flag=True, help="Enable verbose output")
def advertised_speeds(ctx, interface_name, speed_list, verbose):
"""Set interface advertised speeds"""
# Get the config_db connector
config_db = ctx.obj['config_db']

if clicommon.get_interface_naming_mode() == "alias":
interface_name = interface_alias_to_name(config_db, interface_name)
if interface_name is None:
ctx.fail("'interface_name' is None!")

log.log_info("'interface advertised_speeds {} {}' executing...".format(interface_name, speed_list))

if ctx.obj['namespace'] is DEFAULT_NAMESPACE:
command = "portconfig -p {} -S {}".format(interface_name, speed_list)
else:
command = "portconfig -p {} -S {} -n {}".format(interface_name, speed_list, ctx.obj['namespace'])

if verbose:
command += " -vv"
clicommon.run_command(command, display_cmd=verbose)

#
# 'interface-type' subcommand
#

@interface.command(name='type')
@click.pass_context
@click.argument('interface_name', metavar='<interface_name>', required=True)
@click.argument('interface_type_value', metavar='<interface_type_value>', required=True)
@click.option('-v', '--verbose', is_flag=True, help="Enable verbose output")
def interface_type(ctx, interface_name, interface_type_value, verbose):
"""Set interface type"""
# Get the config_db connector
config_db = ctx.obj['config_db']

if clicommon.get_interface_naming_mode() == "alias":
interface_name = interface_alias_to_name(config_db, interface_name)
if interface_name is None:
ctx.fail("'interface_name' is None!")

log.log_info("'interface interface_type {} {}' executing...".format(interface_name, interface_type_value))

if ctx.obj['namespace'] is DEFAULT_NAMESPACE:
command = "portconfig -p {} -t {}".format(interface_name, interface_type_value)
else:
command = "portconfig -p {} -t {} -n {}".format(interface_name, interface_type_value, ctx.obj['namespace'])

if verbose:
command += " -vv"
clicommon.run_command(command, display_cmd=verbose)

#
# 'advertised-interface-types' subcommand
#

@interface.command()
@click.pass_context
@click.argument('interface_name', metavar='<interface_name>', required=True)
@click.argument('interface_type_list', metavar='<interface_type_list>', required=True)
@click.option('-v', '--verbose', is_flag=True, help="Enable verbose output")
def advertised_types(ctx, interface_name, interface_type_list, verbose):
"""Set interface advertised types"""
# Get the config_db connector
config_db = ctx.obj['config_db']

if clicommon.get_interface_naming_mode() == "alias":
interface_name = interface_alias_to_name(config_db, interface_name)
if interface_name is None:
ctx.fail("'interface_name' is None!")

log.log_info("'interface advertised_interface_types {} {}' executing...".format(interface_name, interface_type_list))

if ctx.obj['namespace'] is DEFAULT_NAMESPACE:
command = "portconfig -p {} -T {}".format(interface_name, interface_type_list)
else:
command = "portconfig -p {} -T {} -n {}".format(interface_name, interface_type_list, ctx.obj['namespace'])

if verbose:
command += " -vv"
clicommon.run_command(command, display_cmd=verbose)

#
# 'breakout' subcommand
#
Expand Down
22 changes: 21 additions & 1 deletion scripts/db_migrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,18 @@ def prepare_dynamic_buffer_for_warm_reboot(self, buffer_pools=None, buffer_profi

return True

def migrate_config_db_port_table_for_auto_neg(self):
table_name = 'PORT'
port_table = self.configDB.get_table(table_name)
for key, value in port_table.items():
if 'autoneg' in value:
if value['autoneg'] == '1':
self.configDB.set(self.configDB.CONFIG_DB, '{}|{}'.format(table_name, key), 'autoneg', 'on')
if 'speed' in value and 'adv_speeds' not in value:
self.configDB.set(self.configDB.CONFIG_DB, '{}|{}'.format(table_name, key), 'adv_speeds', value['speed'])
elif value['autoneg'] == '0':
self.configDB.set(self.configDB.CONFIG_DB, '{}|{}'.format(table_name, key), 'autoneg', 'off')

def version_unknown(self):
"""
version_unknown tracks all SONiC versions that doesn't have a version
Expand Down Expand Up @@ -470,10 +482,18 @@ def version_1_0_5(self):

def version_2_0_0(self):
"""
Current latest version. Nothing to do here.
Version 2_0_0.
"""
log.log_info('Handling version_2_0_0')
self.migrate_config_db_port_table_for_auto_neg()
self.set_version('version_2_0_1')
return 'version_2_0_1'

def version_2_0_1(self):
"""
Current latest version. Nothing to do here.
"""
log.log_info('Handling version_2_0_1')
return None

def get_version(self):
Expand Down
84 changes: 82 additions & 2 deletions scripts/intfutil
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ PORT_FEC = "fec"
PORT_DESCRIPTION = "description"
PORT_OPTICS_TYPE = "type"
PORT_PFC_ASYM_STATUS = "pfc_asym"
PORT_AUTONEG = 'autoneg'
PORT_ADV_SPEEDS = 'adv_speeds'
PORT_INTERFACE_TYPE = 'interface_type'
PORT_ADV_INTERFACE_TYPES = 'adv_interface_types'

VLAN_SUB_INTERFACE_SEPARATOR = "."
VLAN_SUB_INTERFACE_TYPE = "802.1q-encapsulation"
Expand Down Expand Up @@ -133,7 +137,13 @@ def appl_db_port_status_get(appl_db, intf_name, status_type):
if status is None:
return "N/A"
if status_type == PORT_SPEED and status != "N/A":
status = '{}G'.format(status[:-3])
status = '{}G'.format(status[:-3])
elif status_type == PORT_ADV_SPEEDS and status != "N/A" and status != "all":
speed_list = status.split(',')
new_speed_list = []
for s in natsorted(speed_list):
new_speed_list.append('{}G'.format(s[:-3]))
status = ','.join(new_speed_list)
return status

def state_db_port_optics_get(state_db, intf_name, type):
Expand Down Expand Up @@ -506,10 +516,77 @@ class IntfDescription(object):
if self.appl_db_keys:
self.table += self.generate_intf_description()


# ========================== interface-autoneg logic ==========================
header_autoneg = ['Interface', 'Auto-Neg Mode', 'Speed', 'Adv Speeds', 'Type', 'Adv Types', 'Oper', 'Admin']


class IntfAutoNegStatus(object):

def __init__(self, intf_name, namespace_option, display_option):
self.db = None
self.config_db = None
self.table = []
self.multi_asic = multi_asic_util.MultiAsic(
display_option, namespace_option)

if intf_name is not None and intf_name == SUB_PORT:
self.intf_name = None
else:
self.intf_name = intf_name

def display_autoneg_status(self):

self.get_intf_autoneg_status()

# Sorting and tabulating the result table.
sorted_table = natsorted(self.table)
print(tabulate(sorted_table, header_autoneg, tablefmt="simple", stralign='right'))

def generate_autoneg_status(self):
"""
Generate interface-autoneg output
"""

i = {}
table = []
key = []

#
# Iterate through all the keys and append port's associated state to
# the result table.
#
for i in self.appl_db_keys:
key = re.split(':', i, maxsplit=1)[-1].strip()
if key in self.front_panel_ports_list:
if self.multi_asic.skip_display(constants.PORT_OBJ, key):
continue
autoneg_mode = appl_db_port_status_get(self.db, key, PORT_AUTONEG)
if autoneg_mode != 'N/A':
autoneg_mode = 'enabled' if autoneg_mode == 'on' else 'disabled'
table.append((key,
autoneg_mode,
appl_db_port_status_get(self.db, key, PORT_SPEED),
appl_db_port_status_get(self.db, key, PORT_ADV_SPEEDS),
appl_db_port_status_get(self.db, key, PORT_INTERFACE_TYPE),
appl_db_port_status_get(self.db, key, PORT_ADV_INTERFACE_TYPES),
appl_db_port_status_get(self.db, key, PORT_OPER_STATUS),
appl_db_port_status_get(self.db, key, PORT_ADMIN_STATUS),
))
return table

@multi_asic_util.run_on_multi_asic
def get_intf_autoneg_status(self):
self.front_panel_ports_list = get_frontpanel_port_list(self.config_db)
self.appl_db_keys = appl_db_keys_get(self.db, self.front_panel_ports_list, self.intf_name)
if self.appl_db_keys:
self.table += self.generate_autoneg_status()


def main():
parser = argparse.ArgumentParser(description='Display Interface information',
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-c', '--command', type=str, help='get interface status or description', default=None)
parser.add_argument('-c', '--command', type=str, help='get interface status or description or auto negotiation status', default=None)
parser.add_argument('-i', '--interface', type=str, help='interface information for specific port: Ethernet0', default=None)
parser = multi_asic_util.multi_asic_args(parser)
args = parser.parse_args()
Expand All @@ -520,6 +597,9 @@ def main():
elif args.command == "description":
interface_desc = IntfDescription(args.interface, args.namespace, args.display)
interface_desc.display_intf_description()
elif args.command == "autoneg":
interface_autoneg_status = IntfAutoNegStatus(args.interface, args.namespace, args.display)
interface_autoneg_status.display_autoneg_status()

sys.exit(0)

Expand Down
Loading