From 28b00515b395be50740add7020c0722bfe65d124 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Tue, 9 Jun 2020 12:09:27 -0700 Subject: [PATCH 01/29] Initial changes for interface commands --- config/main.py | 406 ++++++++++++++++++++++++++++++++++++++++----- scripts/portconfig | 18 +- 2 files changed, 375 insertions(+), 49 deletions(-) diff --git a/config/main.py b/config/main.py index 8b9443b20b..9e32c83d23 100755 --- a/config/main.py +++ b/config/main.py @@ -293,11 +293,42 @@ def validate_namespace(namespace): else: return False -def interface_alias_to_name(interface_alias): +# Return the namespace where an interface belongs +def get_intf_namespace(port): + """If it is a non multi-asic device, or if the interface is management interface + return '' ( empty string ) which maps to current namespace ( in case of config commands + it is linux host ) + """ + if is_multi_asic() == False or port == 'eth0': + return DEFAULT_NAMESPACE + + # If it is PortChannel or Vlan interface or Loopback, user needs to input the namespace. + if port.startswith("PortChannel") or port.startswith("Vlan") or port.startswith("Loopback"): + return None + + if port.startswith("Ethernet"): + if VLAN_SUB_INTERFACE_SEPARATOR in port: + intf_name = port.split(VLAN_SUB_INTERFACE_SEPARATOR)[0] + else: + intf_name = port + + """Currently the CONFIG_DB in each namespace is checked to see if the interface exists + This would be changed in future once we have the interface to ASIC mapping stored in global DB. + Global DB is the database docker service running in the linux host. + """ + ns_list = get_all_namespaces() + namespaces = ns_list['front_ns'] + ns_list['back_ns'] + for namespace in namespaces: + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() + entry = config_db.get_entry('PORT', intf_name) + if entry: + return namespace + return None + +def interface_alias_to_name(config_db, interface_alias): """Return default interface name if alias name is given as argument """ - config_db = ConfigDBConnector() - config_db.connect() port_dict = config_db.get_table('PORT') vlan_id = "" @@ -322,17 +353,15 @@ def interface_alias_to_name(interface_alias): return interface_alias if sub_intf_sep_idx == -1 else interface_alias + VLAN_SUB_INTERFACE_SEPARATOR + vlan_id -def interface_name_is_valid(interface_name): +def interface_name_is_valid(config_db, interface_name): """Check if the interface name is valid """ - config_db = ConfigDBConnector() - config_db.connect() port_dict = config_db.get_table('PORT') port_channel_dict = config_db.get_table('PORTCHANNEL') sub_port_intf_dict = config_db.get_table('VLAN_SUB_INTERFACE') if clicommon.get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(interface_name) + interface_name = interface_alias_to_name(config_db, interface_name) if interface_name is not None: if not port_dict: @@ -351,11 +380,9 @@ def interface_name_is_valid(interface_name): return True return False -def interface_name_to_alias(interface_name): +def interface_name_to_alias(config_db, interface_name): """Return alias interface name if default name is given as argument """ - config_db = ConfigDBConnector() - config_db.connect() port_dict = config_db.get_table('PORT') if interface_name is not None: @@ -430,8 +457,18 @@ def set_interface_naming_mode(mode): user = os.getenv('SUDO_USER') bashrc_ifacemode_line = "export SONIC_CLI_IFACE_MODE={}".format(mode) + """In case of multi-asic, we can check for the alias mode support in any of + the namespaces as this setting of alias mode should be identical everywhere. + Here by default we set the namespaces to be a list just having '' which + represents the linux host. In case of multi-asic, we take the first namespace + created for the front facing ASIC. + """ + namespaces = [DEFAULT_NAMESPACE] + if is_multi_asic: + namespaces = get_all_namespaces()['front_ns'] + # Ensure all interfaces have an 'alias' key in PORT dict - config_db = ConfigDBConnector() + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespaces[0]) config_db.connect() port_dict = config_db.get_table('PORT') @@ -1207,11 +1244,22 @@ def hostname(new_hostname): # 'portchannel' group ('config portchannel ...') # @config.group(cls=clicommon.AbbreviationGroup) +@click.option('-n', '--namespace', help='Namespace name', default=None) @click.pass_context -def portchannel(ctx): - config_db = ConfigDBConnector() +def portchannel(ctx, namespace): + #If multi ASIC platform, check if the namespace entered by user is valid + if is_multi_asic(): + if namespace is None: + ctx.fail("namespace [-n] option required for portchannel/member (add/del)") + if not validate_namespace(str(namespace)): + ctx.fail("Invalid Namespace entered {}".format(namespace)) + else: + namespace=DEFAULT_NAMESPACE + + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=str(namespace)) config_db.connect() - ctx.obj = {'db': config_db} + ctx.obj = {'db': config_db, 'namespace': str(namespace)} + pass @portchannel.command('add') @click.argument('portchannel_name', metavar='', required=True) @@ -1251,6 +1299,14 @@ def add_portchannel_member(ctx, portchannel_name, port_name): db = ctx.obj['db'] if clicommon.is_port_mirror_dst_port(db, port_name): ctx.fail("{} is configured as mirror destination port".format(port_name)) + if is_multi_asic(): + # Get the namespace based on the member interface given by user. + intf_ns = get_intf_namespace(port_name) + if intf_ns is None: + ctx.fail("member interface {} is invalid".format(port_name)) + elif intf_ns != ctx.obj['namespace']: + ctx.fail("member interface {} doesn't exist in namespace {}".format(port_name, ctx.obj['namespace'])) + db.set_entry('PORTCHANNEL_MEMBER', (portchannel_name, port_name), {'NULL': 'NULL'}) @@ -1261,6 +1317,14 @@ def add_portchannel_member(ctx, portchannel_name, port_name): def del_portchannel_member(ctx, portchannel_name, port_name): """Remove member from portchannel""" db = ctx.obj['db'] + if is_multi_asic(): + # Get the namespace based on the member interface given by user. + intf_ns = get_intf_namespace(port_name) + if intf_ns is None: + ctx.fail("member interface {} is invalid".format(port_name)) + elif intf_ns != ctx.obj['namespace']: + ctx.fail("member interface {} doesn't exist in namespace {}".format(port_name, ctx.obj['namespace'])) + db.set_entry('PORTCHANNEL_MEMBER', (portchannel_name, port_name), None) db.set_entry('PORTCHANNEL_MEMBER', portchannel_name + '|' + port_name, None) @@ -1695,6 +1759,163 @@ def warm_restart_bgp_eoiu(ctx, enable): db = ctx.obj['db'] db.mod_entry('WARM_RESTART', 'bgp', {'bgp_eoiu': enable}) +# +# 'vlan' group ('config vlan ...') +# +@config.group(cls=AbbreviationGroup) +@click.pass_context +@click.option('-n', '--namespace', help='Namespace name', default=None) +@click.option('-s', '--redis-unix-socket-path', help='unix socket path for redis connection') +def vlan(ctx, redis_unix_socket_path, namespace): + """VLAN-related configuration tasks""" + kwargs = {} + if redis_unix_socket_path: + kwargs['unix_socket_path'] = redis_unix_socket_path + + #If multi ASIC platform, check if the namespace entered by user is valid + if is_multi_asic(): + if namespace is None: + ctx.fail("namespace [-n] option required for vlan/member (add/del)") + if not validate_namespace(str(namespace)): + ctx.fail("Invalid Namespace entered {}".format(namespace)) + else: + namespace=DEFAULT_NAMESPACE + + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=str(namespace), **kwargs) + config_db.connect(wait_for_init=False) + ctx.obj = {'db': config_db, 'namespace': str(namespace)} + pass + +@vlan.command('add') +@click.argument('vid', metavar='', required=True, type=int) +@click.pass_context +def add_vlan(ctx, vid): + if vid >= 1 and vid <= 4094: + db = ctx.obj['db'] + vlan = 'Vlan{}'.format(vid) + if len(db.get_entry('VLAN', vlan)) != 0: + ctx.fail("{} already exists".format(vlan)) + db.set_entry('VLAN', vlan, {'vlanid': vid}) + else : + ctx.fail("Invalid VLAN ID {} (1-4094)".format(vid)) + +@vlan.command('del') +@click.argument('vid', metavar='', required=True, type=int) +@click.pass_context +def del_vlan(ctx, vid): + """Delete VLAN""" + log.log_info("'vlan del {}' executing...".format(vid)) + db = ctx.obj['db'] + keys = [ (k, v) for k, v in db.get_table('VLAN_MEMBER') if k == 'Vlan{}'.format(vid) ] + for k in keys: + db.set_entry('VLAN_MEMBER', k, None) + db.set_entry('VLAN', 'Vlan{}'.format(vid), None) + + +# +# 'member' group ('config vlan member ...') +# +@vlan.group(cls=AbbreviationGroup, name='member') +@click.pass_context +def vlan_member(ctx): + pass + + +@vlan_member.command('add') +@click.argument('vid', metavar='', required=True, type=int) +@click.argument('interface_name', metavar='', required=True) +@click.option('-u', '--untagged', is_flag=True) +@click.pass_context +def add_vlan_member(ctx, vid, interface_name, untagged): + """Add VLAN member""" + log.log_info("'vlan member add {} {}' executing...".format(vid, interface_name)) + if is_multi_asic(): + # Get the namespace based on the member interface given by user. + intf_ns = get_intf_namespace(interface_name) + if intf_ns is None: + ctx.fail("member interface {} is invalid".format(interface_name)) + elif intf_ns != ctx.obj['namespace']: + ctx.fail("member interface {} doesn't exist in namespace {}".format(interface_name, ctx.obj['namespace'])) + + db = ctx.obj['db'] + vlan_name = 'Vlan{}'.format(vid) + vlan = db.get_entry('VLAN', vlan_name) + interface_table = db.get_table('INTERFACE') + + if get_interface_naming_mode() == "alias": + interface_name = interface_alias_to_name(db, interface_name) + if interface_name is None: + ctx.fail("'interface_name' is None!") + + if len(vlan) == 0: + ctx.fail("{} doesn't exist".format(vlan_name)) + if interface_is_mirror_dst_port(db, interface_name): + ctx.fail("{} is configured as mirror destination port".format(interface_name)) + + members = vlan.get('members', []) + if interface_name in members: + if get_interface_naming_mode() == "alias": + interface_name = interface_name_to_alias(db, interface_name) + if interface_name is None: + ctx.fail("'interface_name' is None!") + ctx.fail("{} is already a member of {}".format(interface_name, + vlan_name)) + else: + ctx.fail("{} is already a member of {}".format(interface_name, + vlan_name)) + for entry in interface_table: + if (interface_name == entry[0]): + ctx.fail("{} is a L3 interface!".format(interface_name)) + + members.append(interface_name) + vlan['members'] = members + db.set_entry('VLAN', vlan_name, vlan) + db.set_entry('VLAN_MEMBER', (vlan_name, interface_name), {'tagging_mode': "untagged" if untagged else "tagged" }) + + +@vlan_member.command('del') +@click.argument('vid', metavar='', required=True, type=int) +@click.argument('interface_name', metavar='', required=True) +@click.pass_context +def del_vlan_member(ctx, vid, interface_name): + """Delete VLAN member""" + log.log_info("'vlan member del {} {}' executing...".format(vid, interface_name)) + if is_multi_asic(): + # Get the namespace based on the member interface given by user. + intf_ns = get_intf_namespace(interface_name) + if intf_ns is None: + ctx.fail("member interface {} is invalid".format(interface_name)) + elif intf_ns != ctx.obj['namespace']: + ctx.fail("member interface {} doesn't exist in namespace {}".format(interface_name, ctx.obj['namespace'])) + + db = ctx.obj['db'] + vlan_name = 'Vlan{}'.format(vid) + vlan = db.get_entry('VLAN', vlan_name) + + if get_interface_naming_mode() == "alias": + interface_name = interface_alias_to_name(db, interface_name) + if interface_name is None: + ctx.fail("'interface_name' is None!") + + if len(vlan) == 0: + ctx.fail("{} doesn't exist".format(vlan_name)) + members = vlan.get('members', []) + if interface_name not in members: + if get_interface_naming_mode() == "alias": + interface_name = interface_name_to_alias(db, interface_name) + if interface_name is None: + ctx.fail("'interface_name' is None!") + ctx.fail("{} is not a member of {}".format(interface_name, vlan_name)) + else: + ctx.fail("{} is not a member of {}".format(interface_name, vlan_name)) + members.remove(interface_name) + if len(members) == 0: + del vlan['members'] + else: + vlan['members'] = members + db.set_entry('VLAN', vlan_name, vlan) + db.set_entry('VLAN_MEMBER', (vlan_name, interface_name), None) + def mvrf_restart_services(): """Restart interfaces-config service and NTP service when mvrf is changed""" """ @@ -2037,13 +2258,17 @@ def remove_neighbor(neighbor_ip_or_hostname): # @config.group(cls=clicommon.AbbreviationGroup) +@click.option('-n', '--namespace', help='Namespace name', default=None) @click.pass_context -def interface(ctx): +def interface(ctx, namespace): """Interface-related configuration tasks""" - config_db = ConfigDBConnector() - config_db.connect() - ctx.obj = {} - ctx.obj['config_db'] = config_db + #Check if the namespace entered by user is valid + if is_multi_asic(): + if namespace is not None and not validate_namespace(namespace): + ctx.fail("Invalid Namespace entered {}".format(namespace)) + else: + namespace=DEFAULT_NAMESPACE + ctx.obj = {'namespace': None if namespace is None else str(namespace)} # # 'startup' subcommand @@ -2054,15 +2279,23 @@ def interface(ctx): @click.pass_context def startup(ctx, interface_name): """Start up interface""" + namespace = ctx.obj['namespace'] + if is_multi_asic() and namespace is None: + ns = get_intf_namespace(interface_name) + if ns is None: + ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + else: + namespace = ns + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() - config_db = ctx.obj['config_db'] if clicommon.get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(interface_name) + interface_name = interface_alias_to_name(config_db, interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") intf_fs = parse_interface_in_filter(interface_name) - if len(intf_fs) == 1 and interface_name_is_valid(interface_name) is False: + if len(intf_fs) == 1 and interface_name_is_valid(config_db, interface_name) is False: ctx.fail("Interface name is invalid. Please enter a valid interface name!!") log.log_info("'interface startup {}' executing...".format(interface_name)) @@ -2091,14 +2324,23 @@ def startup(ctx, interface_name): def shutdown(ctx, interface_name): """Shut down interface""" log.log_info("'interface shutdown {}' executing...".format(interface_name)) - config_db = ctx.obj['config_db'] + namespace = ctx.obj['namespace'] + if is_multi_asic() and namespace is None: + ns = get_intf_namespace(interface_name) + if ns is None: + ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + else: + namespace = ns + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() + if clicommon.get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(interface_name) + interface_name = interface_alias_to_name(config_db, interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") intf_fs = parse_interface_in_filter(interface_name) - if len(intf_fs) == 1 and interface_name_is_valid(interface_name) is False: + if len(intf_fs) == 1 and interface_name_is_valid(config_db, interface_name) is False: ctx.fail("Interface name is invalid. Please enter a valid interface name!!") port_dict = config_db.get_table('PORT') @@ -2127,14 +2369,24 @@ def shutdown(ctx, interface_name): @click.option('-v', '--verbose', is_flag=True, help="Enable verbose output") def speed(ctx, interface_name, interface_speed, verbose): """Set interface speed""" + namespace = ctx.obj['namespace'] + if is_multi_asic() and namespace is None: + ns = get_intf_namespace(interface_name) + if ns is None: + ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + else: + namespace = ns + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() + if clicommon.get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(interface_name) + 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 speed {} {}' executing...".format(interface_name, interface_speed)) - command = "portconfig -p {} -s {}".format(interface_name, interface_speed) + command = "portconfig -p {} -s {} -n {}".format(interface_name, interface_speed, namespace) if verbose: command += " -vv" clicommon.run_command(command, display_cmd=verbose) @@ -2292,12 +2544,22 @@ def mgmt_ip_restart_services(): @click.option('-v', '--verbose', is_flag=True, help="Enable verbose output") def mtu(ctx, interface_name, interface_mtu, verbose): """Set interface mtu""" + namespace = ctx.obj['namespace'] + if is_multi_asic() and namespace is None: + ns = get_intf_namespace(interface_name) + if ns is None: + ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + else: + namespace = ns + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() + if clicommon.get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(interface_name) + interface_name = interface_alias_to_name(config_db, interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") - command = "portconfig -p {} -m {}".format(interface_name, interface_mtu) + command = "portconfig -p {} -m {} -n {}".format(interface_name, interface_mtu, namespace) if verbose: command += " -vv" clicommon.run_command(command, display_cmd=verbose) @@ -2342,9 +2604,18 @@ def ip(ctx): @click.pass_context def add(ctx, interface_name, ip_addr, gw): """Add an IP address towards the interface""" - config_db = ctx.obj["config_db"] + namespace = ctx.obj['namespace'] + if is_multi_asic() and namespace is None: + ns = get_intf_namespace(interface_name) + if ns is None: + ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + else: + namespace = ns + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() + if clicommon.get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(interface_name) + interface_name = interface_alias_to_name(config_db, interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") @@ -2401,9 +2672,18 @@ def add(ctx, interface_name, ip_addr, gw): @click.pass_context def remove(ctx, interface_name, ip_addr): """Remove an IP address from the interface""" - config_db = ctx.obj["config_db"] + namespace = ctx.obj['namespace'] + if is_multi_asic() and namespace is None: + ns = get_intf_namespace(interface_name) + if ns is None: + ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + else: + namespace = ns + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() + if clicommon.get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(interface_name) + interface_name = interface_alias_to_name(config_db, interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") @@ -2501,9 +2781,18 @@ def vrf(ctx): @click.pass_context def bind(ctx, interface_name, vrf_name): """Bind the interface to VRF""" - config_db = ctx.obj["config_db"] + namespace = ctx.obj['namespace'] + if is_multi_asic() and namespace is None: + ns = get_intf_namespace(interface_name) + if ns is None: + ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + else: + namespace = ns + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() + if clicommon.get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(interface_name) + interface_name = interface_alias_to_name(config_db, interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") @@ -2519,7 +2808,7 @@ def bind(ctx, interface_name, vrf_name): config_db.set_entry(table_name, interface_del, None) config_db.set_entry(table_name, interface_name, None) # When config_db del entry and then add entry with same key, the DEL will lost. - state_db = SonicV2Connector(host='127.0.0.1') + state_db = SonicV2Connector(host='127.0.0.1', use_unix_socket_path=True, namespace=namespace) state_db.connect(state_db.STATE_DB, False) _hash = '{}{}'.format('INTERFACE_TABLE|', interface_name) while state_db.get(state_db.STATE_DB, _hash, "state") == "ok": @@ -2536,9 +2825,18 @@ def bind(ctx, interface_name, vrf_name): @click.pass_context def unbind(ctx, interface_name): """Unbind the interface to VRF""" - config_db = ctx.obj["config_db"] + namespace = ctx.obj['namespace'] + if is_multi_asic() and namespace is None: + ns = get_intf_namespace(interface_name) + if ns is None: + ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + else: + namespace = ns + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() + if clicommon.get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(interface_name) + interface_name = interface_alias_to_name(config_db, interface_name) if interface_name is None: ctx.fail("interface is None!") @@ -2966,8 +3264,17 @@ def pfc(ctx): @click.pass_context def asymmetric(ctx, interface_name, status): """Set asymmetric PFC configuration.""" + namespace = ctx.obj['namespace'] + if is_multi_asic() and namespace is None: + ns = get_intf_namespace(interface_name) + if ns is None: + ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + else: + namespace = ns + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() if clicommon.get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(interface_name) + interface_name = interface_alias_to_name(config_db, interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") @@ -2984,6 +3291,15 @@ def asymmetric(ctx, interface_name, status): @click.pass_context def priority(ctx, interface_name, priority, status): """Set PFC priority configuration.""" + namespace = ctx.obj['namespace'] + if is_multi_asic() and namespace is None: + ns = get_intf_namespace(interface_name) + if ns is None: + ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + else: + namespace = ns + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(interface_name) if interface_name is None: @@ -3382,11 +3698,11 @@ def interface(ctx): @click.argument('ifname', metavar='', required=True, type=str) @click.pass_context def enable(ctx, ifname): - if not interface_name_is_valid(ifname) and ifname != 'all': + config_db = ctx.obj['db'] + if not interface_name_is_valid(config_db, ifname) and ifname != 'all': click.echo("Invalid interface name") return - config_db = ctx.obj['db'] intf_dict = config_db.get_table('SFLOW_SESSION') if intf_dict and ifname in intf_dict.keys(): @@ -3402,11 +3718,11 @@ def enable(ctx, ifname): @click.argument('ifname', metavar='', required=True, type=str) @click.pass_context def disable(ctx, ifname): - if not interface_name_is_valid(ifname) and ifname != 'all': + config_db = ctx.obj['db'] + if not interface_name_is_valid(config_db, ifname) and ifname != 'all': click.echo("Invalid interface name") return - config_db = ctx.obj['db'] intf_dict = config_db.get_table('SFLOW_SESSION') if intf_dict and ifname in intf_dict.keys(): @@ -3424,14 +3740,14 @@ def disable(ctx, ifname): @click.argument('rate', metavar='', required=True, type=int) @click.pass_context def sample_rate(ctx, ifname, rate): - if not interface_name_is_valid(ifname) and ifname != 'all': + config_db = ctx.obj['db'] + if not interface_name_is_valid(config_db, ifname) and ifname != 'all': click.echo('Invalid interface name') return if not is_valid_sample_rate(rate): click.echo('Error: Sample rate must be between 256 and 8388608') return - config_db = ctx.obj['db'] sess_dict = config_db.get_table('SFLOW_SESSION') if sess_dict and ifname in sess_dict.keys(): diff --git a/scripts/portconfig b/scripts/portconfig index 6b21739d95..0c9a47e8a0 100755 --- a/scripts/portconfig +++ b/scripts/portconfig @@ -4,7 +4,7 @@ portconfig is the utility to show and change ECN configuration usage: portconfig [-h] [-v] [-s] [-f] [-m] [-p PROFILE] [-gmin GREEN_MIN] [-gmax GREEN_MAX] [-ymin YELLOW_MIN] [-ymax YELLOW_MAX] - [-rmin RED_MIN] [-rmax RED_MAX] [-vv] + [-rmin RED_MIN] [-rmax RED_MAX] [-vv] [-n namespace] optional arguments: -h --help show this help message and exit @@ -14,6 +14,7 @@ optional arguments: -s --speed port speed in Mbits -f --fec port fec mode -m --mtu port mtu in bytes + -n --namesapce Namespace name """ from __future__ import print_function @@ -30,12 +31,16 @@ class portconfig(object): """ Process aclstat """ - def __init__(self, verbose, port): + def __init__(self, verbose, port, namespace): self.verbose = verbose # Set up db connections - self.db = swsssdk.ConfigDBConnector() + if namespace is None: + self.db = swsssdk.ConfigDBConnector() + else: + self.db = swsssdk.ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) self.db.connect() + # check whether table for this port exists port_tables = self.db.get_table(PORT_TABLE_NAME) if not port_tables.has_key(port): @@ -72,10 +77,15 @@ def main(): parser.add_argument('-f', '--fec', type=str, help='port fec mode value in (none, rs, fc)', default=None) parser.add_argument('-m', '--mtu', type=int, help='port mtu value in bytes', default=None) parser.add_argument('-vv', '--verbose', action='store_true', help='Verbose output', default=False) + parser.add_argument('-n', '--namespace', metavar='namespace details', type = str, required = False, + help = 'The asic namespace whose DB instance we need to connect', default=None) args = parser.parse_args() + if args.namespace is not None: + swsssdk.SonicDBConfig.load_sonic_global_db_config(namespace=args.namespace) + try: - port = portconfig(args.verbose, args.port) + port = portconfig(args.verbose, args.port, args.namespace) if args.list: port.list_params(args.port) elif args.speed or args.fec or args.mtu: From 9fab92554dd029da8cca158801b29c9fe4d8bc9b Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Tue, 12 May 2020 00:03:25 -0700 Subject: [PATCH 02/29] Review comments update --- config/main.py | 46 +++++++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/config/main.py b/config/main.py index 9e32c83d23..a3f08fa0b0 100755 --- a/config/main.py +++ b/config/main.py @@ -312,10 +312,10 @@ def get_intf_namespace(port): else: intf_name = port - """Currently the CONFIG_DB in each namespace is checked to see if the interface exists - This would be changed in future once we have the interface to ASIC mapping stored in global DB. - Global DB is the database docker service running in the linux host. - """ + # Currently the CONFIG_DB in each namespace is checked to see if the interface exists + # This would be changed in future once we have the interface to ASIC mapping stored in global DB. + # Global DB is the database docker service running in the linux host. + ns_list = get_all_namespaces() namespaces = ns_list['front_ns'] + ns_list['back_ns'] for namespace in namespaces: @@ -457,14 +457,14 @@ def set_interface_naming_mode(mode): user = os.getenv('SUDO_USER') bashrc_ifacemode_line = "export SONIC_CLI_IFACE_MODE={}".format(mode) - """In case of multi-asic, we can check for the alias mode support in any of - the namespaces as this setting of alias mode should be identical everywhere. - Here by default we set the namespaces to be a list just having '' which - represents the linux host. In case of multi-asic, we take the first namespace - created for the front facing ASIC. - """ + # In case of multi-asic, we can check for the alias mode support in any of + # the namespaces as this setting of alias mode should be identical everywhere. + # Here by default we set the namespaces to be a list just having '' which + # represents the linux host. In case of multi-asic, we take the first namespace + # created for the front facing ASIC. + namespaces = [DEFAULT_NAMESPACE] - if is_multi_asic: + if is_multi_asic(): namespaces = get_all_namespaces()['front_ns'] # Ensure all interfaces have an 'alias' key in PORT dict @@ -906,9 +906,8 @@ def save(filename): click.echo("Input {} config file(s) separated by comma for multiple files ".format(num_cfg_file)) return - """In case of multi-asic mode we have additional config_db{NS}.json files for - various namespaces created per ASIC. {NS} is the namespace index. - """ + # In case of multi-asic mode we have additional config_db{NS}.json files for + # various namespaces created per ASIC. {NS} is the namespace index. for inst in range(-1, num_cfg_file-1): #inst = -1, refers to the linux host where there is no namespace. if inst is -1: @@ -963,9 +962,8 @@ def load(filename, yes): click.echo("Input {} config file(s) separated by comma for multiple files ".format(num_cfg_file)) return - """In case of multi-asic mode we have additional config_db{NS}.json files for - various namespaces created per ASIC. {NS} is the namespace index. - """ + # In case of multi-asic mode we have additional config_db{NS}.json files for + # various namespaces created per ASIC. {NS} is the namespace index. for inst in range(-1, num_cfg_file-1): #inst = -1, refers to the linux host where there is no namespace. if inst is -1: @@ -1046,11 +1044,10 @@ def reload(db, filename, yes, load_sysinfo, no_service_restart): log.log_info("'reload' stopping services...") _stop_services(db.cfgdb) - """ In Single AISC platforms we have single DB service. In multi-ASIC platforms we have a global DB - service running in the host + DB services running in each ASIC namespace created per ASIC. - In the below logic, we get all namespaces in this platform and add an empty namespace '' - denoting the current namespace which we are in ( the linux host ) - """ + # In Single AISC platforms we have single DB service. In multi-ASIC platforms we have a global DB + # service running in the host + DB services running in each ASIC namespace created per ASIC. + # In the below logic, we get all namespaces in this platform and add an empty namespace '' + # denoting the current namespace which we are in ( the linux host ) for inst in range(-1, num_cfg_file-1): # Get the namespace name, for linux host it is None if inst is -1: @@ -1067,7 +1064,7 @@ def reload(db, filename, yes, load_sysinfo, no_service_restart): else: file = "/etc/sonic/config_db{}.json".format(inst) - #Check the file exists before proceeding. + # Check the file exists before proceeding. if not os.path.isfile(file): click.echo("The config_db file {} doesn't exist".format(file)) continue @@ -1090,7 +1087,6 @@ def reload(db, filename, yes, load_sysinfo, no_service_restart): # For the database service running in linux host we use the file user gives as input # or by default DEFAULT_CONFIG_DB_FILE. In the case of database service running in namespace, # the default config_db.json format is used. - if namespace is None: if os.path.isfile(INIT_CFG_FILE): command = "{} -j {} -j {} --write-to-db".format(SONIC_CFGGEN_PATH, INIT_CFG_FILE, file) @@ -2262,7 +2258,7 @@ def remove_neighbor(neighbor_ip_or_hostname): @click.pass_context def interface(ctx, namespace): """Interface-related configuration tasks""" - #Check if the namespace entered by user is valid + # Check if the namespace entered by user is valid if is_multi_asic(): if namespace is not None and not validate_namespace(namespace): ctx.fail("Invalid Namespace entered {}".format(namespace)) From 8a0cd82b043c5054c249937c4f3a4dcfb66de140 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Tue, 12 May 2020 10:02:12 -0700 Subject: [PATCH 03/29] Command message update, Fix to handle changed number of arguments in certain APIs. --- config/main.py | 59 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/config/main.py b/config/main.py index a3f08fa0b0..783fa06fee 100755 --- a/config/main.py +++ b/config/main.py @@ -313,9 +313,8 @@ def get_intf_namespace(port): intf_name = port # Currently the CONFIG_DB in each namespace is checked to see if the interface exists - # This would be changed in future once we have the interface to ASIC mapping stored in global DB. - # Global DB is the database docker service running in the linux host. - + # TODO This logic of checking each DB will be updated once the interface to ASIC mapping is + # stored in global DB. Global DB is the database docker service running in the linux host. ns_list = get_all_namespaces() namespaces = ns_list['front_ns'] + ns_list['back_ns'] for namespace in namespaces: @@ -1255,7 +1254,6 @@ def portchannel(ctx, namespace): config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=str(namespace)) config_db.connect() ctx.obj = {'db': config_db, 'namespace': str(namespace)} - pass @portchannel.command('add') @click.argument('portchannel_name', metavar='', required=True) @@ -1780,7 +1778,6 @@ def vlan(ctx, redis_unix_socket_path, namespace): config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=str(namespace), **kwargs) config_db.connect(wait_for_init=False) ctx.obj = {'db': config_db, 'namespace': str(namespace)} - pass @vlan.command('add') @click.argument('vid', metavar='', required=True, type=int) @@ -2279,7 +2276,7 @@ def startup(ctx, interface_name): if is_multi_asic() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: - ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) else: namespace = ns config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) @@ -2324,7 +2321,7 @@ def shutdown(ctx, interface_name): if is_multi_asic() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: - ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) else: namespace = ns config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) @@ -2369,7 +2366,7 @@ def speed(ctx, interface_name, interface_speed, verbose): if is_multi_asic() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: - ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) else: namespace = ns config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) @@ -2544,7 +2541,7 @@ def mtu(ctx, interface_name, interface_mtu, verbose): if is_multi_asic() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: - ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) else: namespace = ns config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) @@ -2604,7 +2601,7 @@ def add(ctx, interface_name, ip_addr, gw): if is_multi_asic() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: - ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) else: namespace = ns config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) @@ -2672,7 +2669,7 @@ def remove(ctx, interface_name, ip_addr): if is_multi_asic() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: - ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) else: namespace = ns config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) @@ -2726,12 +2723,22 @@ def transceiver(ctx): @click.pass_context def lpmode(ctx, interface_name, state): """Enable/disable low-power mode for SFP transceiver module""" + namespace = ctx.obj['namespace'] + if is_multi_asic() and namespace is None: + ns = get_intf_namespace(interface_name) + if ns is None: + ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) + else: + namespace = ns + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() + if clicommon.get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(interface_name) + interface_name = interface_alias_to_name(config_db, interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") - if interface_name_is_valid(interface_name) is False: + if interface_name_is_valid(config_db, interface_name) is False: ctx.fail("Interface name is invalid. Please enter a valid interface name!!") cmd = "sudo sfputil lpmode {} {}".format("on" if state == "enable" else "off", interface_name) @@ -2746,12 +2753,22 @@ def lpmode(ctx, interface_name, state): @click.pass_context def reset(ctx, interface_name): """Reset SFP transceiver module""" + namespace = ctx.obj['namespace'] + if is_multi_asic() and namespace is None: + ns = get_intf_namespace(interface_name) + if ns is None: + ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) + else: + namespace = ns + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() + if clicommon.get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(interface_name) + interface_name = interface_alias_to_name(config_db, interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") - if interface_name_is_valid(interface_name) is False: + if interface_name_is_valid(config_db, interface_name) is False: ctx.fail("Interface name is invalid. Please enter a valid interface name!!") cmd = "sudo sfputil reset {}".format(interface_name) @@ -2781,7 +2798,7 @@ def bind(ctx, interface_name, vrf_name): if is_multi_asic() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: - ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) else: namespace = ns config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) @@ -2804,7 +2821,7 @@ def bind(ctx, interface_name, vrf_name): config_db.set_entry(table_name, interface_del, None) config_db.set_entry(table_name, interface_name, None) # When config_db del entry and then add entry with same key, the DEL will lost. - state_db = SonicV2Connector(host='127.0.0.1', use_unix_socket_path=True, namespace=namespace) + state_db = SonicV2Connector(use_unix_socket_path=True, namespace=namespace) state_db.connect(state_db.STATE_DB, False) _hash = '{}{}'.format('INTERFACE_TABLE|', interface_name) while state_db.get(state_db.STATE_DB, _hash, "state") == "ok": @@ -2825,7 +2842,7 @@ def unbind(ctx, interface_name): if is_multi_asic() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: - ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) else: namespace = ns config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) @@ -3264,7 +3281,7 @@ def asymmetric(ctx, interface_name, status): if is_multi_asic() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: - ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) else: namespace = ns config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) @@ -3291,13 +3308,13 @@ def priority(ctx, interface_name, priority, status): if is_multi_asic() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: - ctx.fail("namespace [-n] option required to modify interface {}".format(interface_name)) + ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) else: namespace = ns config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) config_db.connect() if clicommon.get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(interface_name) + interface_name = interface_alias_to_name(config_db, interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") From 3889ed931ff1e57a1b42ce152a78bde461c7f13f Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Tue, 12 May 2020 11:44:59 -0700 Subject: [PATCH 04/29] Update for review comments --- config/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/main.py b/config/main.py index 783fa06fee..cc68832953 100755 --- a/config/main.py +++ b/config/main.py @@ -1242,7 +1242,7 @@ def hostname(new_hostname): @click.option('-n', '--namespace', help='Namespace name', default=None) @click.pass_context def portchannel(ctx, namespace): - #If multi ASIC platform, check if the namespace entered by user is valid + # If multi ASIC platform, check if the namespace entered by user is valid if is_multi_asic(): if namespace is None: ctx.fail("namespace [-n] option required for portchannel/member (add/del)") @@ -1766,7 +1766,7 @@ def vlan(ctx, redis_unix_socket_path, namespace): if redis_unix_socket_path: kwargs['unix_socket_path'] = redis_unix_socket_path - #If multi ASIC platform, check if the namespace entered by user is valid + # If multi ASIC platform, check if the namespace entered by user is valid if is_multi_asic(): if namespace is None: ctx.fail("namespace [-n] option required for vlan/member (add/del)") From bd75a68075cf627d206821c10ea1de09030bd025 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Tue, 19 May 2020 09:10:36 -0700 Subject: [PATCH 05/29] Updates based on the move of common API's to sonic_device_util.py --- config/main.py | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/config/main.py b/config/main.py index cc68832953..19f31a6ccf 100755 --- a/config/main.py +++ b/config/main.py @@ -296,10 +296,10 @@ def validate_namespace(namespace): # Return the namespace where an interface belongs def get_intf_namespace(port): """If it is a non multi-asic device, or if the interface is management interface - return '' ( empty string ) which maps to current namespace ( in case of config commands + return '' ( DEFAULT_NAMESPACE ) which maps to current namespace ( in case of config commands it is linux host ) """ - if is_multi_asic() == False or port == 'eth0': + if sonic_device_util.is_multi_npu() == False or port == 'eth0': return DEFAULT_NAMESPACE # If it is PortChannel or Vlan interface or Loopback, user needs to input the namespace. @@ -315,7 +315,8 @@ def get_intf_namespace(port): # Currently the CONFIG_DB in each namespace is checked to see if the interface exists # TODO This logic of checking each DB will be updated once the interface to ASIC mapping is # stored in global DB. Global DB is the database docker service running in the linux host. - ns_list = get_all_namespaces() + + ns_list = sonic_device_util.get_all_namespaces() namespaces = ns_list['front_ns'] + ns_list['back_ns'] for namespace in namespaces: config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) @@ -463,8 +464,8 @@ def set_interface_naming_mode(mode): # created for the front facing ASIC. namespaces = [DEFAULT_NAMESPACE] - if is_multi_asic(): - namespaces = get_all_namespaces()['front_ns'] + if sonic_device_util.is_multi_npu(): + namespaces = sonic_device_util.get_all_namespaces()['front_ns'] # Ensure all interfaces have an 'alias' key in PORT dict config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespaces[0]) @@ -1243,7 +1244,7 @@ def hostname(new_hostname): @click.pass_context def portchannel(ctx, namespace): # If multi ASIC platform, check if the namespace entered by user is valid - if is_multi_asic(): + if sonic_device_util.is_multi_npu(): if namespace is None: ctx.fail("namespace [-n] option required for portchannel/member (add/del)") if not validate_namespace(str(namespace)): @@ -1293,7 +1294,7 @@ def add_portchannel_member(ctx, portchannel_name, port_name): db = ctx.obj['db'] if clicommon.is_port_mirror_dst_port(db, port_name): ctx.fail("{} is configured as mirror destination port".format(port_name)) - if is_multi_asic(): + if sonic_device_util.is_multi_npu(): # Get the namespace based on the member interface given by user. intf_ns = get_intf_namespace(port_name) if intf_ns is None: @@ -1311,7 +1312,7 @@ def add_portchannel_member(ctx, portchannel_name, port_name): def del_portchannel_member(ctx, portchannel_name, port_name): """Remove member from portchannel""" db = ctx.obj['db'] - if is_multi_asic(): + if sonic_device_util.is_multi_npu(): # Get the namespace based on the member interface given by user. intf_ns = get_intf_namespace(port_name) if intf_ns is None: @@ -1767,7 +1768,7 @@ def vlan(ctx, redis_unix_socket_path, namespace): kwargs['unix_socket_path'] = redis_unix_socket_path # If multi ASIC platform, check if the namespace entered by user is valid - if is_multi_asic(): + if sonic_device_util.is_multi_npu(): if namespace is None: ctx.fail("namespace [-n] option required for vlan/member (add/del)") if not validate_namespace(str(namespace)): @@ -1822,7 +1823,7 @@ def vlan_member(ctx): def add_vlan_member(ctx, vid, interface_name, untagged): """Add VLAN member""" log.log_info("'vlan member add {} {}' executing...".format(vid, interface_name)) - if is_multi_asic(): + if sonic_device_util.is_multi_npu(): # Get the namespace based on the member interface given by user. intf_ns = get_intf_namespace(interface_name) if intf_ns is None: @@ -1873,7 +1874,7 @@ def add_vlan_member(ctx, vid, interface_name, untagged): def del_vlan_member(ctx, vid, interface_name): """Delete VLAN member""" log.log_info("'vlan member del {} {}' executing...".format(vid, interface_name)) - if is_multi_asic(): + if sonic_device_util.is_multi_npu(): # Get the namespace based on the member interface given by user. intf_ns = get_intf_namespace(interface_name) if intf_ns is None: @@ -2256,7 +2257,7 @@ def remove_neighbor(neighbor_ip_or_hostname): def interface(ctx, namespace): """Interface-related configuration tasks""" # Check if the namespace entered by user is valid - if is_multi_asic(): + if sonic_device_util.is_multi_npu(): if namespace is not None and not validate_namespace(namespace): ctx.fail("Invalid Namespace entered {}".format(namespace)) else: @@ -2273,7 +2274,7 @@ def interface(ctx, namespace): def startup(ctx, interface_name): """Start up interface""" namespace = ctx.obj['namespace'] - if is_multi_asic() and namespace is None: + if sonic_device_util.is_multi_npu() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) @@ -2318,7 +2319,7 @@ def shutdown(ctx, interface_name): """Shut down interface""" log.log_info("'interface shutdown {}' executing...".format(interface_name)) namespace = ctx.obj['namespace'] - if is_multi_asic() and namespace is None: + if sonic_device_util.is_multi_npu() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) @@ -2363,7 +2364,7 @@ def shutdown(ctx, interface_name): def speed(ctx, interface_name, interface_speed, verbose): """Set interface speed""" namespace = ctx.obj['namespace'] - if is_multi_asic() and namespace is None: + if sonic_device_util.is_multi_npu() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) @@ -2538,7 +2539,7 @@ def mgmt_ip_restart_services(): def mtu(ctx, interface_name, interface_mtu, verbose): """Set interface mtu""" namespace = ctx.obj['namespace'] - if is_multi_asic() and namespace is None: + if sonic_device_util.is_multi_npu() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) @@ -2598,7 +2599,7 @@ def ip(ctx): def add(ctx, interface_name, ip_addr, gw): """Add an IP address towards the interface""" namespace = ctx.obj['namespace'] - if is_multi_asic() and namespace is None: + if sonic_device_util.is_multi_npu() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) @@ -2666,7 +2667,7 @@ def add(ctx, interface_name, ip_addr, gw): def remove(ctx, interface_name, ip_addr): """Remove an IP address from the interface""" namespace = ctx.obj['namespace'] - if is_multi_asic() and namespace is None: + if sonic_device_util.is_multi_npu() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) @@ -2724,7 +2725,7 @@ def transceiver(ctx): def lpmode(ctx, interface_name, state): """Enable/disable low-power mode for SFP transceiver module""" namespace = ctx.obj['namespace'] - if is_multi_asic() and namespace is None: + if sonic_device_util.is_multi_npu() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) @@ -2754,7 +2755,7 @@ def lpmode(ctx, interface_name, state): def reset(ctx, interface_name): """Reset SFP transceiver module""" namespace = ctx.obj['namespace'] - if is_multi_asic() and namespace is None: + if sonic_device_util.is_multi_npu() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) @@ -2795,7 +2796,7 @@ def vrf(ctx): def bind(ctx, interface_name, vrf_name): """Bind the interface to VRF""" namespace = ctx.obj['namespace'] - if is_multi_asic() and namespace is None: + if sonic_device_util.is_multi_npu() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) @@ -2839,7 +2840,7 @@ def bind(ctx, interface_name, vrf_name): def unbind(ctx, interface_name): """Unbind the interface to VRF""" namespace = ctx.obj['namespace'] - if is_multi_asic() and namespace is None: + if sonic_device_util.is_multi_npu() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) @@ -3278,7 +3279,7 @@ def pfc(ctx): def asymmetric(ctx, interface_name, status): """Set asymmetric PFC configuration.""" namespace = ctx.obj['namespace'] - if is_multi_asic() and namespace is None: + if sonic_device_util.is_multi_npu() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) @@ -3305,7 +3306,7 @@ def asymmetric(ctx, interface_name, status): def priority(ctx, interface_name, priority, status): """Set PFC priority configuration.""" namespace = ctx.obj['namespace'] - if is_multi_asic() and namespace is None: + if sonic_device_util.is_multi_npu() and namespace is None: ns = get_intf_namespace(interface_name) if ns is None: ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) From e1e3cee456f2efdb25db84f79e6e21a1906b80ed Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Mon, 8 Jun 2020 14:44:20 -0700 Subject: [PATCH 06/29] Reusing the existing API's to check interface validity and addressing comments. --- config/main.py | 254 ++++++++++++++++++++++--------------------------- 1 file changed, 112 insertions(+), 142 deletions(-) diff --git a/config/main.py b/config/main.py index 19f31a6ccf..0f3a0e3d98 100755 --- a/config/main.py +++ b/config/main.py @@ -293,39 +293,6 @@ def validate_namespace(namespace): else: return False -# Return the namespace where an interface belongs -def get_intf_namespace(port): - """If it is a non multi-asic device, or if the interface is management interface - return '' ( DEFAULT_NAMESPACE ) which maps to current namespace ( in case of config commands - it is linux host ) - """ - if sonic_device_util.is_multi_npu() == False or port == 'eth0': - return DEFAULT_NAMESPACE - - # If it is PortChannel or Vlan interface or Loopback, user needs to input the namespace. - if port.startswith("PortChannel") or port.startswith("Vlan") or port.startswith("Loopback"): - return None - - if port.startswith("Ethernet"): - if VLAN_SUB_INTERFACE_SEPARATOR in port: - intf_name = port.split(VLAN_SUB_INTERFACE_SEPARATOR)[0] - else: - intf_name = port - - # Currently the CONFIG_DB in each namespace is checked to see if the interface exists - # TODO This logic of checking each DB will be updated once the interface to ASIC mapping is - # stored in global DB. Global DB is the database docker service running in the linux host. - - ns_list = sonic_device_util.get_all_namespaces() - namespaces = ns_list['front_ns'] + ns_list['back_ns'] - for namespace in namespaces: - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - config_db.connect() - entry = config_db.get_entry('PORT', intf_name) - if entry: - return namespace - return None - def interface_alias_to_name(config_db, interface_alias): """Return default interface name if alias name is given as argument """ @@ -437,6 +404,33 @@ def is_interface_bind_to_vrf(config_db, interface_name): return True return False +# Return the namespace where an interface belongs +def get_port_namespace(ctx, port): + """If it is a non multi-asic device, or if the interface is management interface + return '' ( DEFAULT_NAMESPACE ) which maps to current namespace ( in case of config commands + it is linux host ) + """ + if sonic_device_util.is_multi_npu() == False or port == 'eth0': + return DEFAULT_NAMESPACE + + # Get the table to check for interface presence + table_name = get_interface_table_name(port) + if table_name == "": + # If table name is not valid, exit with fail + ctx.fail("Input the namespace [-n] option to configure interface {}".format(port)) + + ns_list = sonic_device_util.get_all_namespaces() + namespaces = ns_list['front_ns'] + ns_list['back_ns'] + for namespace in namespaces: + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() + entry = config_db.get_entry(table_name, port) + if entry: + return namespace + + # If interface not matched in any namespace, exit with fail + ctx.fail("Input the namespace [-n] option to configure interface {}".format(port)) + def del_interface_bind_to_vrf(config_db, vrf_name): """del interface bind to vrf """ @@ -1245,16 +1239,14 @@ def hostname(new_hostname): def portchannel(ctx, namespace): # If multi ASIC platform, check if the namespace entered by user is valid if sonic_device_util.is_multi_npu(): - if namespace is None: + if namespace is DEFAULT_NAMESPACE: ctx.fail("namespace [-n] option required for portchannel/member (add/del)") - if not validate_namespace(str(namespace)): + if not validate_namespace(namespace): ctx.fail("Invalid Namespace entered {}".format(namespace)) - else: - namespace=DEFAULT_NAMESPACE - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=str(namespace)) + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) config_db.connect() - ctx.obj = {'db': config_db, 'namespace': str(namespace)} + ctx.obj = {'db': config_db, 'namespace': namespace} @portchannel.command('add') @click.argument('portchannel_name', metavar='', required=True) @@ -1294,13 +1286,10 @@ def add_portchannel_member(ctx, portchannel_name, port_name): db = ctx.obj['db'] if clicommon.is_port_mirror_dst_port(db, port_name): ctx.fail("{} is configured as mirror destination port".format(port_name)) - if sonic_device_util.is_multi_npu(): - # Get the namespace based on the member interface given by user. - intf_ns = get_intf_namespace(port_name) - if intf_ns is None: - ctx.fail("member interface {} is invalid".format(port_name)) - elif intf_ns != ctx.obj['namespace']: - ctx.fail("member interface {} doesn't exist in namespace {}".format(port_name, ctx.obj['namespace'])) + + # Check if the member interface given by user is valid in the namespace. + if interface_name_is_valid(db, port_name) is False: + ctx.fail("Interface name is invalid. Please enter a valid interface name!!") db.set_entry('PORTCHANNEL_MEMBER', (portchannel_name, port_name), {'NULL': 'NULL'}) @@ -1312,18 +1301,14 @@ def add_portchannel_member(ctx, portchannel_name, port_name): def del_portchannel_member(ctx, portchannel_name, port_name): """Remove member from portchannel""" db = ctx.obj['db'] - if sonic_device_util.is_multi_npu(): - # Get the namespace based on the member interface given by user. - intf_ns = get_intf_namespace(port_name) - if intf_ns is None: - ctx.fail("member interface {} is invalid".format(port_name)) - elif intf_ns != ctx.obj['namespace']: - ctx.fail("member interface {} doesn't exist in namespace {}".format(port_name, ctx.obj['namespace'])) + + # Check if the member interface given by user is valid in the namespace. + if interface_name_is_valid(db, port_name) is False: + ctx.fail("Interface name is invalid. Please enter a valid interface name!!") db.set_entry('PORTCHANNEL_MEMBER', (portchannel_name, port_name), None) db.set_entry('PORTCHANNEL_MEMBER', portchannel_name + '|' + port_name, None) - # # 'mirror_session' group ('config mirror_session ...') # @@ -1759,7 +1744,7 @@ def warm_restart_bgp_eoiu(ctx, enable): # @config.group(cls=AbbreviationGroup) @click.pass_context -@click.option('-n', '--namespace', help='Namespace name', default=None) +@click.option('-n', '--namespace', help='Namespace name', default=DEFAULT_NAMESPACE) @click.option('-s', '--redis-unix-socket-path', help='unix socket path for redis connection') def vlan(ctx, redis_unix_socket_path, namespace): """VLAN-related configuration tasks""" @@ -1769,16 +1754,14 @@ def vlan(ctx, redis_unix_socket_path, namespace): # If multi ASIC platform, check if the namespace entered by user is valid if sonic_device_util.is_multi_npu(): - if namespace is None: + if namespace is DEFAULT_NAMESPACE: ctx.fail("namespace [-n] option required for vlan/member (add/del)") - if not validate_namespace(str(namespace)): + if not validate_namespace(namespace): ctx.fail("Invalid Namespace entered {}".format(namespace)) - else: - namespace=DEFAULT_NAMESPACE - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=str(namespace), **kwargs) + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace, **kwargs) config_db.connect(wait_for_init=False) - ctx.obj = {'db': config_db, 'namespace': str(namespace)} + ctx.obj = {'db': config_db, 'namespace': namespace} @vlan.command('add') @click.argument('vid', metavar='', required=True, type=int) @@ -1832,6 +1815,11 @@ def add_vlan_member(ctx, vid, interface_name, untagged): ctx.fail("member interface {} doesn't exist in namespace {}".format(interface_name, ctx.obj['namespace'])) db = ctx.obj['db'] + + # Check if the member interface given by user is valid in the namespace. + if interface_name_is_valid(db, interface_name) is False: + ctx.fail("Interface name is invalid. Please enter a valid interface name!!") + vlan_name = 'Vlan{}'.format(vid) vlan = db.get_entry('VLAN', vlan_name) interface_table = db.get_table('INTERFACE') @@ -1883,6 +1871,11 @@ def del_vlan_member(ctx, vid, interface_name): ctx.fail("member interface {} doesn't exist in namespace {}".format(interface_name, ctx.obj['namespace'])) db = ctx.obj['db'] + + # Check if the member interface given by user is valid in the namespace. + if interface_name_is_valid(db, interface_name) is False: + ctx.fail("Interface name is invalid. Please enter a valid interface name!!") + vlan_name = 'Vlan{}'.format(vid) vlan = db.get_entry('VLAN', vlan_name) @@ -2258,11 +2251,10 @@ def interface(ctx, namespace): """Interface-related configuration tasks""" # Check if the namespace entered by user is valid if sonic_device_util.is_multi_npu(): - if namespace is not None and not validate_namespace(namespace): + if namespace is not DEFAULT_NAMESPACE and not validate_namespace(namespace): ctx.fail("Invalid Namespace entered {}".format(namespace)) - else: - namespace=DEFAULT_NAMESPACE - ctx.obj = {'namespace': None if namespace is None else str(namespace)} + + ctx.obj = {'namespace': namespace} # # 'startup' subcommand @@ -2273,13 +2265,11 @@ def interface(ctx, namespace): @click.pass_context def startup(ctx, interface_name): """Start up interface""" - namespace = ctx.obj['namespace'] - if sonic_device_util.is_multi_npu() and namespace is None: - ns = get_intf_namespace(interface_name) - if ns is None: - ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) - else: - namespace = ns + # In multi ASIC platforms, if the user don't give the namespace, try to derive the + # namespace from the interface name. + if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: + namespace = get_port_namespace(ctx, interface_name) + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) config_db.connect() @@ -2363,13 +2353,11 @@ def shutdown(ctx, interface_name): @click.option('-v', '--verbose', is_flag=True, help="Enable verbose output") def speed(ctx, interface_name, interface_speed, verbose): """Set interface speed""" - namespace = ctx.obj['namespace'] - if sonic_device_util.is_multi_npu() and namespace is None: - ns = get_intf_namespace(interface_name) - if ns is None: - ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) - else: - namespace = ns + # In multi ASIC platforms, if the user don't give the namespace, try to derive the + # namespace from the interface name. + if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: + namespace = get_port_namespace(ctx, interface_name) + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) config_db.connect() @@ -2538,13 +2526,11 @@ def mgmt_ip_restart_services(): @click.option('-v', '--verbose', is_flag=True, help="Enable verbose output") def mtu(ctx, interface_name, interface_mtu, verbose): """Set interface mtu""" - namespace = ctx.obj['namespace'] - if sonic_device_util.is_multi_npu() and namespace is None: - ns = get_intf_namespace(interface_name) - if ns is None: - ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) - else: - namespace = ns + # In multi ASIC platforms, if the user don't give the namespace, try to derive the + # namespace from the interface name. + if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: + namespace = get_port_namespace(ctx, interface_name) + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) config_db.connect() @@ -2598,13 +2584,11 @@ def ip(ctx): @click.pass_context def add(ctx, interface_name, ip_addr, gw): """Add an IP address towards the interface""" - namespace = ctx.obj['namespace'] - if sonic_device_util.is_multi_npu() and namespace is None: - ns = get_intf_namespace(interface_name) - if ns is None: - ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) - else: - namespace = ns + # In multi ASIC platforms, if the user don't give the namespace, try to derive the + # namespace from the interface name. + if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: + namespace = get_port_namespace(ctx, interface_name) + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) config_db.connect() @@ -2666,13 +2650,11 @@ def add(ctx, interface_name, ip_addr, gw): @click.pass_context def remove(ctx, interface_name, ip_addr): """Remove an IP address from the interface""" - namespace = ctx.obj['namespace'] - if sonic_device_util.is_multi_npu() and namespace is None: - ns = get_intf_namespace(interface_name) - if ns is None: - ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) - else: - namespace = ns + # In multi ASIC platforms, if the user don't give the namespace, try to derive the + # namespace from the interface name. + if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: + namespace = get_port_namespace(ctx, interface_name) + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) config_db.connect() @@ -2724,13 +2706,11 @@ def transceiver(ctx): @click.pass_context def lpmode(ctx, interface_name, state): """Enable/disable low-power mode for SFP transceiver module""" - namespace = ctx.obj['namespace'] - if sonic_device_util.is_multi_npu() and namespace is None: - ns = get_intf_namespace(interface_name) - if ns is None: - ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) - else: - namespace = ns + # In multi ASIC platforms, if the user don't give the namespace, try to derive the + # namespace from the interface name. + if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: + namespace = get_port_namespace(ctx, interface_name) + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) config_db.connect() @@ -2754,13 +2734,11 @@ def lpmode(ctx, interface_name, state): @click.pass_context def reset(ctx, interface_name): """Reset SFP transceiver module""" - namespace = ctx.obj['namespace'] - if sonic_device_util.is_multi_npu() and namespace is None: - ns = get_intf_namespace(interface_name) - if ns is None: - ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) - else: - namespace = ns + # In multi ASIC platforms, if the user don't give the namespace, try to derive the + # namespace from the interface name. + if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: + namespace = get_port_namespace(ctx, interface_name) + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) config_db.connect() @@ -2795,13 +2773,11 @@ def vrf(ctx): @click.pass_context def bind(ctx, interface_name, vrf_name): """Bind the interface to VRF""" - namespace = ctx.obj['namespace'] - if sonic_device_util.is_multi_npu() and namespace is None: - ns = get_intf_namespace(interface_name) - if ns is None: - ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) - else: - namespace = ns + # In multi ASIC platforms, if the user don't give the namespace, try to derive the + # namespace from the interface name. + if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: + namespace = get_port_namespace(ctx, interface_name) + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) config_db.connect() @@ -2839,13 +2815,11 @@ def bind(ctx, interface_name, vrf_name): @click.pass_context def unbind(ctx, interface_name): """Unbind the interface to VRF""" - namespace = ctx.obj['namespace'] - if sonic_device_util.is_multi_npu() and namespace is None: - ns = get_intf_namespace(interface_name) - if ns is None: - ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) - else: - namespace = ns + # In multi ASIC platforms, if the user don't give the namespace, try to derive the + # namespace from the interface name. + if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: + namespace = get_port_namespace(ctx, interface_name) + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) config_db.connect() @@ -3278,13 +3252,11 @@ def pfc(ctx): @click.pass_context def asymmetric(ctx, interface_name, status): """Set asymmetric PFC configuration.""" - namespace = ctx.obj['namespace'] - if sonic_device_util.is_multi_npu() and namespace is None: - ns = get_intf_namespace(interface_name) - if ns is None: - ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) - else: - namespace = ns + # In multi ASIC platforms, if the user don't give the namespace, try to derive the + # namespace from the interface name. + if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: + namespace = get_port_namespace(ctx, interface_name) + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) config_db.connect() if clicommon.get_interface_naming_mode() == "alias": @@ -3305,13 +3277,11 @@ def asymmetric(ctx, interface_name, status): @click.pass_context def priority(ctx, interface_name, priority, status): """Set PFC priority configuration.""" - namespace = ctx.obj['namespace'] - if sonic_device_util.is_multi_npu() and namespace is None: - ns = get_intf_namespace(interface_name) - if ns is None: - ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) - else: - namespace = ns + # In multi ASIC platforms, if the user don't give the namespace, try to derive the + # namespace from the interface name. + if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: + namespace = get_port_namespace(ctx, interface_name) + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) config_db.connect() if clicommon.get_interface_naming_mode() == "alias": From d5070c037d0d0edcd9a3cdf43c8fa843c7d992fc Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Tue, 9 Jun 2020 09:18:44 -0700 Subject: [PATCH 07/29] Convert duplicate code into functions. --- config/main.py | 155 ++++++++++++++++++++++--------------------------- 1 file changed, 68 insertions(+), 87 deletions(-) diff --git a/config/main.py b/config/main.py index 0f3a0e3d98..e6358cdfae 100755 --- a/config/main.py +++ b/config/main.py @@ -404,8 +404,37 @@ def is_interface_bind_to_vrf(config_db, interface_name): return True return False +# Validate whether a given namespace name is valid in the device. +def validate_namespace(namespace): + if not sonic_device_util.is_multi_npu(): + return True + + namespaces = sonic_device_util.get_all_namespaces() + if namespace in namespaces['front_ns'] + namespaces['back_ns']: + return True + else: + return False + +def get_port_table_name(interface_name): + """Get table name by port_name prefix + """ + if interface_name.startswith("Ethernet"): + if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: + return "VLAN_SUB_INTERFACE" + return "PORT" + elif interface_name.startswith("PortChannel"): + if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: + return "VLAN_SUB_INTERFACE" + return "PORTCHANNEL" + elif interface_name.startswith("Vlan"): + return "VLAN_INTERFACE" + elif interface_name.startswith("Loopback"): + return "LOOPBACK_INTERFACE" + else: + return "" + # Return the namespace where an interface belongs -def get_port_namespace(ctx, port): +def get_port_namespace(port): """If it is a non multi-asic device, or if the interface is management interface return '' ( DEFAULT_NAMESPACE ) which maps to current namespace ( in case of config commands it is linux host ) @@ -414,10 +443,9 @@ def get_port_namespace(ctx, port): return DEFAULT_NAMESPACE # Get the table to check for interface presence - table_name = get_interface_table_name(port) + table_name = get_port_table_name(port) if table_name == "": - # If table name is not valid, exit with fail - ctx.fail("Input the namespace [-n] option to configure interface {}".format(port)) + return None ns_list = sonic_device_util.get_all_namespaces() namespaces = ns_list['front_ns'] + ns_list['back_ns'] @@ -428,8 +456,25 @@ def get_port_namespace(ctx, port): if entry: return namespace - # If interface not matched in any namespace, exit with fail - ctx.fail("Input the namespace [-n] option to configure interface {}".format(port)) + return None + +# Return the config_db connector based on the input interface and namespace +def get_interface_configDB_connector(ctx, interface_name, namespace): + # In multi ASIC platforms, if the user don't give the namespace, try to derive the + # namespace using interface name. + if sonic_device_util.is_multi_npu() == True and namespace == DEFAULT_NAMESPACE: + ns_name = get_port_namespace(interface_name) + if ns_name is None: + # If namespace cannot be derived from interface name, exit with message to user + ctx.fail("Input the namespace [-n] option to configure interface {}".format(interface_name)) + else: + ns_name = namespace + + # Create the ConfigDBConnector object and connect + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=ns_name) + config_db.connect() + + return config_db def del_interface_bind_to_vrf(config_db, vrf_name): """del interface bind to vrf @@ -1238,8 +1283,8 @@ def hostname(new_hostname): @click.pass_context def portchannel(ctx, namespace): # If multi ASIC platform, check if the namespace entered by user is valid - if sonic_device_util.is_multi_npu(): - if namespace is DEFAULT_NAMESPACE: + if sonic_device_util.is_multi_npu(): + if namespace == DEFAULT_NAMESPACE: ctx.fail("namespace [-n] option required for portchannel/member (add/del)") if not validate_namespace(namespace): ctx.fail("Invalid Namespace entered {}".format(namespace)) @@ -1754,7 +1799,7 @@ def vlan(ctx, redis_unix_socket_path, namespace): # If multi ASIC platform, check if the namespace entered by user is valid if sonic_device_util.is_multi_npu(): - if namespace is DEFAULT_NAMESPACE: + if namespace == DEFAULT_NAMESPACE: ctx.fail("namespace [-n] option required for vlan/member (add/del)") if not validate_namespace(namespace): ctx.fail("Invalid Namespace entered {}".format(namespace)) @@ -2251,7 +2296,7 @@ def interface(ctx, namespace): """Interface-related configuration tasks""" # Check if the namespace entered by user is valid if sonic_device_util.is_multi_npu(): - if namespace is not DEFAULT_NAMESPACE and not validate_namespace(namespace): + if namespace != DEFAULT_NAMESPACE and not validate_namespace(namespace): ctx.fail("Invalid Namespace entered {}".format(namespace)) ctx.obj = {'namespace': namespace} @@ -2265,13 +2310,7 @@ def interface(ctx, namespace): @click.pass_context def startup(ctx, interface_name): """Start up interface""" - # In multi ASIC platforms, if the user don't give the namespace, try to derive the - # namespace from the interface name. - if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: - namespace = get_port_namespace(ctx, interface_name) - - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - config_db.connect() + config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2353,13 +2392,7 @@ def shutdown(ctx, interface_name): @click.option('-v', '--verbose', is_flag=True, help="Enable verbose output") def speed(ctx, interface_name, interface_speed, verbose): """Set interface speed""" - # In multi ASIC platforms, if the user don't give the namespace, try to derive the - # namespace from the interface name. - if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: - namespace = get_port_namespace(ctx, interface_name) - - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - config_db.connect() + config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2526,13 +2559,7 @@ def mgmt_ip_restart_services(): @click.option('-v', '--verbose', is_flag=True, help="Enable verbose output") def mtu(ctx, interface_name, interface_mtu, verbose): """Set interface mtu""" - # In multi ASIC platforms, if the user don't give the namespace, try to derive the - # namespace from the interface name. - if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: - namespace = get_port_namespace(ctx, interface_name) - - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - config_db.connect() + config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2584,13 +2611,7 @@ def ip(ctx): @click.pass_context def add(ctx, interface_name, ip_addr, gw): """Add an IP address towards the interface""" - # In multi ASIC platforms, if the user don't give the namespace, try to derive the - # namespace from the interface name. - if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: - namespace = get_port_namespace(ctx, interface_name) - - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - config_db.connect() + config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2650,13 +2671,7 @@ def add(ctx, interface_name, ip_addr, gw): @click.pass_context def remove(ctx, interface_name, ip_addr): """Remove an IP address from the interface""" - # In multi ASIC platforms, if the user don't give the namespace, try to derive the - # namespace from the interface name. - if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: - namespace = get_port_namespace(ctx, interface_name) - - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - config_db.connect() + config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2706,13 +2721,7 @@ def transceiver(ctx): @click.pass_context def lpmode(ctx, interface_name, state): """Enable/disable low-power mode for SFP transceiver module""" - # In multi ASIC platforms, if the user don't give the namespace, try to derive the - # namespace from the interface name. - if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: - namespace = get_port_namespace(ctx, interface_name) - - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - config_db.connect() + config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2734,13 +2743,7 @@ def lpmode(ctx, interface_name, state): @click.pass_context def reset(ctx, interface_name): """Reset SFP transceiver module""" - # In multi ASIC platforms, if the user don't give the namespace, try to derive the - # namespace from the interface name. - if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: - namespace = get_port_namespace(ctx, interface_name) - - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - config_db.connect() + config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2773,13 +2776,7 @@ def vrf(ctx): @click.pass_context def bind(ctx, interface_name, vrf_name): """Bind the interface to VRF""" - # In multi ASIC platforms, if the user don't give the namespace, try to derive the - # namespace from the interface name. - if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: - namespace = get_port_namespace(ctx, interface_name) - - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - config_db.connect() + config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2815,13 +2812,7 @@ def bind(ctx, interface_name, vrf_name): @click.pass_context def unbind(ctx, interface_name): """Unbind the interface to VRF""" - # In multi ASIC platforms, if the user don't give the namespace, try to derive the - # namespace from the interface name. - if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: - namespace = get_port_namespace(ctx, interface_name) - - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - config_db.connect() + config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -3252,14 +3243,9 @@ def pfc(ctx): @click.pass_context def asymmetric(ctx, interface_name, status): """Set asymmetric PFC configuration.""" - # In multi ASIC platforms, if the user don't give the namespace, try to derive the - # namespace from the interface name. - if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: - namespace = get_port_namespace(ctx, interface_name) + config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - config_db.connect() - if clicommon.get_interface_naming_mode() == "alias": + if 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!") @@ -3277,14 +3263,9 @@ def asymmetric(ctx, interface_name, status): @click.pass_context def priority(ctx, interface_name, priority, status): """Set PFC priority configuration.""" - # In multi ASIC platforms, if the user don't give the namespace, try to derive the - # namespace from the interface name. - if sonic_device_util.is_multi_npu() == True and namespace is DEFAULT_NAMESPACE: - namespace = get_port_namespace(ctx, interface_name) + config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - config_db.connect() - if clicommon.get_interface_naming_mode() == "alias": + if 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!") From 1aeba6595c6e22ed41c2bc88d7489c9970d590f0 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Tue, 9 Jun 2020 12:33:33 -0700 Subject: [PATCH 08/29] Changes in interface fec command for the namespace approach. --- config/main.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config/main.py b/config/main.py index e6358cdfae..2e81754d99 100755 --- a/config/main.py +++ b/config/main.py @@ -2578,14 +2578,16 @@ def mtu(ctx, interface_name, interface_mtu, verbose): @click.option('-v', '--verbose', is_flag=True, help="Enable verbose output") def fec(ctx, interface_name, interface_fec, verbose): """Set interface fec""" + config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + if interface_fec not in ["rs", "fc", "none"]: ctx.fail("'fec not in ['rs', 'fc', 'none']!") if clicommon.get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(interface_name) + interface_name = interface_alias_to_name(config_db, interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") - command = "portconfig -p {} -f {}".format(interface_name, interface_fec) + command = "portconfig -p {} -f {} -n {}".format(interface_name, interface_fec, namespace) if verbose: command += " -vv" clicommon.run_command(command, display_cmd=verbose) From 8727a12b7ec9c7bc40385216c19c2893daa73f0f Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Tue, 9 Jun 2020 13:14:24 -0700 Subject: [PATCH 09/29] Using the namespace as string instead of unicode. Additionaly changes to update the namespace keyword to ctx.obj['namespace'] in portconfig scripts invocation. --- config/main.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/config/main.py b/config/main.py index 2e81754d99..744cfad7e5 100755 --- a/config/main.py +++ b/config/main.py @@ -1284,14 +1284,14 @@ def hostname(new_hostname): def portchannel(ctx, namespace): # If multi ASIC platform, check if the namespace entered by user is valid if sonic_device_util.is_multi_npu(): - if namespace == DEFAULT_NAMESPACE: + if str(namespace) == DEFAULT_NAMESPACE: ctx.fail("namespace [-n] option required for portchannel/member (add/del)") - if not validate_namespace(namespace): - ctx.fail("Invalid Namespace entered {}".format(namespace)) + if not validate_namespace(str(namespace)): + ctx.fail("Invalid Namespace entered {}".format(str(namespace))) - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=str(namespace)) config_db.connect() - ctx.obj = {'db': config_db, 'namespace': namespace} + ctx.obj = {'db': config_db, 'namespace': str(namespace)} @portchannel.command('add') @click.argument('portchannel_name', metavar='', required=True) @@ -1799,14 +1799,14 @@ def vlan(ctx, redis_unix_socket_path, namespace): # If multi ASIC platform, check if the namespace entered by user is valid if sonic_device_util.is_multi_npu(): - if namespace == DEFAULT_NAMESPACE: + if str(namespace) == DEFAULT_NAMESPACE: ctx.fail("namespace [-n] option required for vlan/member (add/del)") - if not validate_namespace(namespace): - ctx.fail("Invalid Namespace entered {}".format(namespace)) + if not validate_namespace(str(namespace)): + ctx.fail("Invalid Namespace entered {}".format(str(namespace))) - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace, **kwargs) + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=str(namespace), **kwargs) config_db.connect(wait_for_init=False) - ctx.obj = {'db': config_db, 'namespace': namespace} + ctx.obj = {'db': config_db, 'namespace': str(namespace)} @vlan.command('add') @click.argument('vid', metavar='', required=True, type=int) @@ -2296,10 +2296,10 @@ def interface(ctx, namespace): """Interface-related configuration tasks""" # Check if the namespace entered by user is valid if sonic_device_util.is_multi_npu(): - if namespace != DEFAULT_NAMESPACE and not validate_namespace(namespace): - ctx.fail("Invalid Namespace entered {}".format(namespace)) + if str(namespace) != DEFAULT_NAMESPACE and not validate_namespace(str(namespace)): + ctx.fail("Invalid Namespace entered {}".format(str(namespace))) - ctx.obj = {'namespace': namespace} + ctx.obj = {'namespace': str(namespace)} # # 'startup' subcommand @@ -2401,7 +2401,7 @@ def speed(ctx, interface_name, interface_speed, verbose): log.log_info("'interface speed {} {}' executing...".format(interface_name, interface_speed)) - command = "portconfig -p {} -s {} -n {}".format(interface_name, interface_speed, namespace) + command = "portconfig -p {} -s {} -n {}".format(interface_name, interface_speed, ctx.obj['namespace']) if verbose: command += " -vv" clicommon.run_command(command, display_cmd=verbose) @@ -2566,7 +2566,7 @@ def mtu(ctx, interface_name, interface_mtu, verbose): if interface_name is None: ctx.fail("'interface_name' is None!") - command = "portconfig -p {} -m {} -n {}".format(interface_name, interface_mtu, namespace) + command = "portconfig -p {} -m {} -n {}".format(interface_name, interface_mtu, ctx.obj['namespace']) if verbose: command += " -vv" clicommon.run_command(command, display_cmd=verbose) @@ -2587,7 +2587,7 @@ def fec(ctx, interface_name, interface_fec, verbose): if interface_name is None: ctx.fail("'interface_name' is None!") - command = "portconfig -p {} -f {} -n {}".format(interface_name, interface_fec, namespace) + command = "portconfig -p {} -f {} -n {}".format(interface_name, interface_fec, ctx.obj['namespace']) if verbose: command += " -vv" clicommon.run_command(command, display_cmd=verbose) @@ -2797,7 +2797,7 @@ def bind(ctx, interface_name, vrf_name): config_db.set_entry(table_name, interface_del, None) config_db.set_entry(table_name, interface_name, None) # When config_db del entry and then add entry with same key, the DEL will lost. - state_db = SonicV2Connector(use_unix_socket_path=True, namespace=namespace) + state_db = SonicV2Connector(use_unix_socket_path=True, namespace=ctx.obj['namespace']) state_db.connect(state_db.STATE_DB, False) _hash = '{}{}'.format('INTERFACE_TABLE|', interface_name) while state_db.get(state_db.STATE_DB, _hash, "state") == "ok": From f168ba6523c0177f2322ca87bebdd556ecbcaf89 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Thu, 11 Jun 2020 00:50:16 -0700 Subject: [PATCH 10/29] Update comments and changes in namespace usage in interface config commands. --- config/main.py | 72 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/config/main.py b/config/main.py index 744cfad7e5..4fec7bd8fb 100755 --- a/config/main.py +++ b/config/main.py @@ -415,6 +415,7 @@ def validate_namespace(namespace): else: return False +# Get the table name based on the interface type def get_port_table_name(interface_name): """Get table name by port_name prefix """ @@ -435,10 +436,8 @@ def get_port_table_name(interface_name): # Return the namespace where an interface belongs def get_port_namespace(port): - """If it is a non multi-asic device, or if the interface is management interface - return '' ( DEFAULT_NAMESPACE ) which maps to current namespace ( in case of config commands - it is linux host ) - """ + # If it is a non multi-asic platform, or if the interface is management interface + # return DEFAULT_NAMESPACE if sonic_device_util.is_multi_npu() == False or port == 'eth0': return DEFAULT_NAMESPACE @@ -458,14 +457,14 @@ def get_port_namespace(port): return None -# Return the config_db connector based on the input interface and namespace -def get_interface_configDB_connector(ctx, interface_name, namespace): - # In multi ASIC platforms, if the user don't give the namespace, try to derive the - # namespace using interface name. +# Return the derived namespace and config_db connector based on the input interface and namespace +def get_namespace_configDB_connector(ctx, interface_name, namespace): + # In multi ASIC platforms, if the user don't give the namespace as input parameter, + # we derive the namespace using interface name. if sonic_device_util.is_multi_npu() == True and namespace == DEFAULT_NAMESPACE: ns_name = get_port_namespace(interface_name) if ns_name is None: - # If namespace cannot be derived from interface name, exit with message to user + # If namespace cannot be derived from interface name, need input from user ctx.fail("Input the namespace [-n] option to configure interface {}".format(interface_name)) else: ns_name = namespace @@ -474,7 +473,7 @@ def get_interface_configDB_connector(ctx, interface_name, namespace): config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=ns_name) config_db.connect() - return config_db + return ns_name, config_db def del_interface_bind_to_vrf(config_db, vrf_name): """del interface bind to vrf @@ -2310,7 +2309,8 @@ def interface(ctx, namespace): @click.pass_context def startup(ctx, interface_name): """Start up interface""" - config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + # Get the namespace and config_db connector + namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2365,7 +2365,7 @@ def shutdown(ctx, interface_name): intf_fs = parse_interface_in_filter(interface_name) if len(intf_fs) == 1 and interface_name_is_valid(config_db, interface_name) is False: ctx.fail("Interface name is invalid. Please enter a valid interface name!!") - +- port_dict = config_db.get_table('PORT') for port_name in port_dict.keys(): if port_name in intf_fs: @@ -2392,7 +2392,8 @@ def shutdown(ctx, interface_name): @click.option('-v', '--verbose', is_flag=True, help="Enable verbose output") def speed(ctx, interface_name, interface_speed, verbose): """Set interface speed""" - config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + # Get the namespace and config_db connector + namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2401,7 +2402,7 @@ def speed(ctx, interface_name, interface_speed, verbose): log.log_info("'interface speed {} {}' executing...".format(interface_name, interface_speed)) - command = "portconfig -p {} -s {} -n {}".format(interface_name, interface_speed, ctx.obj['namespace']) + command = "portconfig -p {} -s {} -n {}".format(interface_name, interface_speed, namespace) if verbose: command += " -vv" clicommon.run_command(command, display_cmd=verbose) @@ -2559,14 +2560,15 @@ def mgmt_ip_restart_services(): @click.option('-v', '--verbose', is_flag=True, help="Enable verbose output") def mtu(ctx, interface_name, interface_mtu, verbose): """Set interface mtu""" - config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + # Get the namespace and config_db connector + namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) 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!") - command = "portconfig -p {} -m {} -n {}".format(interface_name, interface_mtu, ctx.obj['namespace']) + command = "portconfig -p {} -m {} -n {}".format(interface_name, interface_mtu, namespace) if verbose: command += " -vv" clicommon.run_command(command, display_cmd=verbose) @@ -2578,7 +2580,8 @@ def mtu(ctx, interface_name, interface_mtu, verbose): @click.option('-v', '--verbose', is_flag=True, help="Enable verbose output") def fec(ctx, interface_name, interface_fec, verbose): """Set interface fec""" - config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + # Get the namespace and config_db connector + namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if interface_fec not in ["rs", "fc", "none"]: ctx.fail("'fec not in ['rs', 'fc', 'none']!") @@ -2587,7 +2590,7 @@ def fec(ctx, interface_name, interface_fec, verbose): if interface_name is None: ctx.fail("'interface_name' is None!") - command = "portconfig -p {} -f {} -n {}".format(interface_name, interface_fec, ctx.obj['namespace']) + command = "portconfig -p {} -f {} -n {}".format(interface_name, interface_fec, namespace) if verbose: command += " -vv" clicommon.run_command(command, display_cmd=verbose) @@ -2613,7 +2616,8 @@ def ip(ctx): @click.pass_context def add(ctx, interface_name, ip_addr, gw): """Add an IP address towards the interface""" - config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + # Get the namespace and config_db connector + namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2673,7 +2677,8 @@ def add(ctx, interface_name, ip_addr, gw): @click.pass_context def remove(ctx, interface_name, ip_addr): """Remove an IP address from the interface""" - config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + # Get the namespace and config_db connector + namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2698,8 +2703,11 @@ def remove(ctx, interface_name, ip_addr): if len(interface_dependent) == 0 and is_interface_bind_to_vrf(config_db, interface_name) is False: config_db.set_entry(table_name, interface_name, None) - command = "ip neigh flush dev {} {}".format(interface_name, ip_addr) - clicommon.run_command(command) + if sonic_device_util.is_multi_npu(): + command = "sudo ip netns exec {} ip neigh flush dev {} {}".format(namespace, interface_name, ip_addr) + else: + command = "ip neigh flush dev {} {}".format(interface_name, ip_addr) + run_command(command) except ValueError: ctx.fail("'ip_addr' is not valid.") @@ -2723,7 +2731,8 @@ def transceiver(ctx): @click.pass_context def lpmode(ctx, interface_name, state): """Enable/disable low-power mode for SFP transceiver module""" - config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + # Get the namespace and config_db connector + namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2745,7 +2754,8 @@ def lpmode(ctx, interface_name, state): @click.pass_context def reset(ctx, interface_name): """Reset SFP transceiver module""" - config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + # Get the namespace and config_db connector + namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2778,7 +2788,8 @@ def vrf(ctx): @click.pass_context def bind(ctx, interface_name, vrf_name): """Bind the interface to VRF""" - config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + # Get the namespace and config_db connector + namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2797,7 +2808,7 @@ def bind(ctx, interface_name, vrf_name): config_db.set_entry(table_name, interface_del, None) config_db.set_entry(table_name, interface_name, None) # When config_db del entry and then add entry with same key, the DEL will lost. - state_db = SonicV2Connector(use_unix_socket_path=True, namespace=ctx.obj['namespace']) + state_db = SonicV2Connector(use_unix_socket_path=True, namespace=namespace) state_db.connect(state_db.STATE_DB, False) _hash = '{}{}'.format('INTERFACE_TABLE|', interface_name) while state_db.get(state_db.STATE_DB, _hash, "state") == "ok": @@ -2814,7 +2825,8 @@ def bind(ctx, interface_name, vrf_name): @click.pass_context def unbind(ctx, interface_name): """Unbind the interface to VRF""" - config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + # Get the namespace and config_db connector + namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -3245,7 +3257,8 @@ def pfc(ctx): @click.pass_context def asymmetric(ctx, interface_name, status): """Set asymmetric PFC configuration.""" - config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + # Get the namespace and config_db connector + namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -3265,7 +3278,8 @@ def asymmetric(ctx, interface_name, status): @click.pass_context def priority(ctx, interface_name, priority, status): """Set PFC priority configuration.""" - config_db = get_interface_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + # Get the namespace and config_db connector + namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) if get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) From 6bee93a2dc26469028d2347c5a87c33ade179b10 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Thu, 11 Jun 2020 01:01:34 -0700 Subject: [PATCH 11/29] Correcting a stray '-' character in teh earlier diff. --- config/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/main.py b/config/main.py index 4fec7bd8fb..a69a01023e 100755 --- a/config/main.py +++ b/config/main.py @@ -2365,7 +2365,7 @@ def shutdown(ctx, interface_name): intf_fs = parse_interface_in_filter(interface_name) if len(intf_fs) == 1 and interface_name_is_valid(config_db, interface_name) is False: ctx.fail("Interface name is invalid. Please enter a valid interface name!!") -- + port_dict = config_db.get_table('PORT') for port_name in port_dict.keys(): if port_name in intf_fs: From d0a90f8e5dfc1da2c6eea6aa9f18c532e2c7dd05 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Sun, 19 Jul 2020 15:38:05 -0700 Subject: [PATCH 12/29] Updates of additional parameters needed in the NEW CLI's after rebase. --- config/main.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/config/main.py b/config/main.py index a69a01023e..373e77e272 100755 --- a/config/main.py +++ b/config/main.py @@ -846,7 +846,7 @@ def validate_mirror_session_config(config_db, session_name, dst_port, src_port, portchannel_member_table = config_db.get_table('PORTCHANNEL_MEMBER') if dst_port: - if not interface_name_is_valid(dst_port): + if not interface_name_is_valid(config_db, dst_port): click.echo("Error: Destination Interface {} is invalid".format(dst_port)) return False @@ -868,7 +868,7 @@ def validate_mirror_session_config(config_db, session_name, dst_port, src_port, if src_port: for port in src_port.split(","): - if not interface_name_is_valid(port): + if not interface_name_is_valid(config_db, port): click.echo("Error: Source Interface {} is invalid".format(port)) return False if dst_port and dst_port == port: @@ -1403,7 +1403,7 @@ def add(session_name, src_ip, dst_ip, dscp, ttl, gre_type, queue, policer, src_p """ Add ERSPAN mirror session """ add_erspan(session_name, src_ip, dst_ip, dscp, ttl, gre_type, queue, policer, src_port, direction) -def gather_session_info(session_info, policer, queue, src_port, direction): +def gather_session_info(config_db, session_info, policer, queue, src_port, direction): if policer: session_info['policer'] = policer @@ -1414,7 +1414,7 @@ def gather_session_info(session_info, policer, queue, src_port, direction): if clicommon.get_interface_naming_mode() == "alias": src_port_list = [] for port in src_port.split(","): - src_port_list.append(interface_alias_to_name(port)) + src_port_list.append(interface_alias_to_name(config_db, port)) src_port=",".join(src_port_list) session_info['src_port'] = src_port @@ -1436,8 +1436,6 @@ def add_erspan(session_name, src_ip, dst_ip, dscp, ttl, gre_type, queue, policer if gre_type: session_info['gre_type'] = gre_type - session_info = gather_session_info(session_info, policer, queue, src_port, direction) - """ For multi-npu platforms we need to program all front asic namespaces """ @@ -1445,6 +1443,7 @@ def add_erspan(session_name, src_ip, dst_ip, dscp, ttl, gre_type, queue, policer if not namespaces['front_ns']: config_db = ConfigDBConnector() config_db.connect() + session_info = gather_session_info(config_db, session_info, policer, queue, src_port, direction) if validate_mirror_session_config(config_db, session_name, None, src_port, direction) is False: return config_db.set_entry("MIRROR_SESSION", session_name, session_info) @@ -1453,6 +1452,7 @@ def add_erspan(session_name, src_ip, dst_ip, dscp, ttl, gre_type, queue, policer for front_asic_namespaces in namespaces['front_ns']: per_npu_configdb[front_asic_namespaces] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces) per_npu_configdb[front_asic_namespaces].connect() + session_info = gather_session_info(config_db, session_info, policer, queue, src_port, direction) if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, None, src_port, direction) is False: return per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, session_info) @@ -1486,8 +1486,6 @@ def add_span(session_name, dst_port, src_port, direction, queue, policer): "dst_port": dst_port, } - session_info = gather_session_info(session_info, policer, queue, src_port, direction) - """ For multi-npu platforms we need to program all front asic namespaces """ @@ -1495,6 +1493,7 @@ def add_span(session_name, dst_port, src_port, direction, queue, policer): if not namespaces['front_ns']: config_db = ConfigDBConnector() config_db.connect() + session_info = gather_session_info(config_db, session_info, policer, queue, src_port, direction) if validate_mirror_session_config(config_db, session_name, dst_port, src_port, direction) is False: return config_db.set_entry("MIRROR_SESSION", session_name, session_info) @@ -1503,6 +1502,7 @@ def add_span(session_name, dst_port, src_port, direction, queue, policer): for front_asic_namespaces in namespaces['front_ns']: per_npu_configdb[front_asic_namespaces] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces) per_npu_configdb[front_asic_namespaces].connect() + session_info = gather_session_info(config_db, session_info, policer, queue, src_port, direction) if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, dst_port, src_port, direction) is False: return per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, session_info) From d08ac2e02dc3254e523a0fd7b734904e9a14ba36 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Sun, 19 Jul 2020 16:13:45 -0700 Subject: [PATCH 13/29] Updates to add span mirror session for multi-asic platforms --- config/main.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/config/main.py b/config/main.py index 373e77e272..6338487191 100755 --- a/config/main.py +++ b/config/main.py @@ -1493,6 +1493,12 @@ def add_span(session_name, dst_port, src_port, direction, queue, policer): if not namespaces['front_ns']: config_db = ConfigDBConnector() config_db.connect() + + if get_interface_naming_mode() == "alias": + dst_port = interface_alias_to_name(config_db, dst_port) + if dst_port is None: + click.echo("Error: Destination Interface {} is invalid".format(dst_port)) + return session_info = gather_session_info(config_db, session_info, policer, queue, src_port, direction) if validate_mirror_session_config(config_db, session_name, dst_port, src_port, direction) is False: return @@ -1502,6 +1508,12 @@ def add_span(session_name, dst_port, src_port, direction, queue, policer): for front_asic_namespaces in namespaces['front_ns']: per_npu_configdb[front_asic_namespaces] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces) per_npu_configdb[front_asic_namespaces].connect() + + if get_interface_naming_mode() == "alias": + dst_port = interface_alias_to_name(config_db, dst_port) + if dst_port is None: + click.echo("Error: Destination Interface {} is invalid".format(dst_port)) + return session_info = gather_session_info(config_db, session_info, policer, queue, src_port, direction) if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, dst_port, src_port, direction) is False: return From 964babb520b542c419f093b6ea491b7d04f16d01 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Fri, 24 Jul 2020 14:30:22 -0700 Subject: [PATCH 14/29] Changes including 1. Fix in sfputil scripts for config interface transceiver commands 2. Interface range not supported in multi-asic platforms - check added for now. Will add this support in future. 3. Added a new dictionary which is the Sonic interface name prefix. If this approach is ok, to mode to a common file where all scripts/utilities to use. --- config/main.py | 48 +++++++++++++++++++++++++++++++++++++----------- sfputil/main.py | 14 ++++++++++++-- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/config/main.py b/config/main.py index 6338487191..89818cb205 100755 --- a/config/main.py +++ b/config/main.py @@ -52,6 +52,25 @@ CFG_LOOPBACK_ID_MAX_VAL = 999 CFG_LOOPBACK_NO="<0-999>" +asic_type = None +config_db = None + +# TODO move to a common file like sonic_device_util.py +# Dictionary of SONIC interface name prefixes. +SONIC_INTERFACE_PREFIXES = { + "Ethernet": "Ethernet", + "PortChannel": "PortChannel", + "Vlan": "Vlan", + "Loopback": "Loopback", + "Ethernet-backplane": "Ethernet-BP" +} + +# ========================== Syslog wrappers ========================== + +def log_debug(msg): + syslog.openlog(SYSLOG_IDENTIFIER) + syslog.syslog(syslog.LOG_DEBUG, msg) + syslog.closelog() asic_type = None @@ -365,17 +384,17 @@ def interface_name_to_alias(config_db, interface_name): def get_interface_table_name(interface_name): """Get table name by interface_name prefix """ - if interface_name.startswith("Ethernet"): + if interface_name.startswith(SONIC_INTERFACE_PREFIXES["Ethernet"]): if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: return "VLAN_SUB_INTERFACE" return "INTERFACE" - elif interface_name.startswith("PortChannel"): + elif interface_name.startswith(SONIC_INTERFACE_PREFIXES["PortChannel"]): if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: return "VLAN_SUB_INTERFACE" return "PORTCHANNEL_INTERFACE" - elif interface_name.startswith("Vlan"): + elif interface_name.startswith(SONIC_INTERFACE_PREFIXES["Vlan"]): return "VLAN_INTERFACE" - elif interface_name.startswith("Loopback"): + elif interface_name.startswith(SONIC_INTERFACE_PREFIXES["Loopback"]): return "LOOPBACK_INTERFACE" else: return "" @@ -404,6 +423,7 @@ def is_interface_bind_to_vrf(config_db, interface_name): return True return False +# TODO move to a common file like sonic_device_util.py # Validate whether a given namespace name is valid in the device. def validate_namespace(namespace): if not sonic_device_util.is_multi_npu(): @@ -419,17 +439,17 @@ def validate_namespace(namespace): def get_port_table_name(interface_name): """Get table name by port_name prefix """ - if interface_name.startswith("Ethernet"): + if interface_name.startswith(SONIC_INTERFACE_PREFIXES["Ethernet"]): if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: return "VLAN_SUB_INTERFACE" return "PORT" - elif interface_name.startswith("PortChannel"): + elif interface_name.startswith(SONIC_INTERFACE_PREFIXES["PortChannel"]): if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: return "VLAN_SUB_INTERFACE" return "PORTCHANNEL" - elif interface_name.startswith("Vlan"): + elif interface_name.startswith(SONIC_INTERFACE_PREFIXES["Vlan"]): return "VLAN_INTERFACE" - elif interface_name.startswith("Loopback"): + elif interface_name.startswith(SONIC_INTERFACE_PREFIXES["Loopback"]): return "LOOPBACK_INTERFACE" else: return "" @@ -948,7 +968,7 @@ def save(filename): # various namespaces created per ASIC. {NS} is the namespace index. for inst in range(-1, num_cfg_file-1): #inst = -1, refers to the linux host where there is no namespace. - if inst is -1: + if inst == -1: namespace = None else: namespace = "{}{}".format(NAMESPACE_PREFIX, inst) @@ -1004,7 +1024,7 @@ def load(filename, yes): # various namespaces created per ASIC. {NS} is the namespace index. for inst in range(-1, num_cfg_file-1): #inst = -1, refers to the linux host where there is no namespace. - if inst is -1: + if inst == -1: namespace = None else: namespace = "{}{}".format(NAMESPACE_PREFIX, inst) @@ -1088,7 +1108,7 @@ def reload(db, filename, yes, load_sysinfo, no_service_restart): # denoting the current namespace which we are in ( the linux host ) for inst in range(-1, num_cfg_file-1): # Get the namespace name, for linux host it is None - if inst is -1: + if inst == -1: namespace = None else: namespace = "{}{}".format(NAMESPACE_PREFIX, inst) @@ -2330,6 +2350,9 @@ def startup(ctx, interface_name): ctx.fail("'interface_name' is None!") intf_fs = parse_interface_in_filter(interface_name) + if len(intf_fs) > 1 and sonic_device_util.is_multi_npu(): + ctx.fail("Interface range not supported in multi-asic platforms !!") + if len(intf_fs) == 1 and interface_name_is_valid(config_db, interface_name) is False: ctx.fail("Interface name is invalid. Please enter a valid interface name!!") @@ -2375,6 +2398,9 @@ def shutdown(ctx, interface_name): ctx.fail("'interface_name' is None!") intf_fs = parse_interface_in_filter(interface_name) + if len(intf_fs) > 1 and sonic_device_util.is_multi_npu(): + ctx.fail("Interface range not supported in multi-asic platforms !!") + if len(intf_fs) == 1 and interface_name_is_valid(config_db, interface_name) is False: ctx.fail("Interface name is invalid. Please enter a valid interface name!!") diff --git a/sfputil/main.py b/sfputil/main.py index 7dfd56b1a5..4eae0adb6a 100644 --- a/sfputil/main.py +++ b/sfputil/main.py @@ -305,8 +305,18 @@ def cli(): # Load port info try: - port_config_file_path = device_info.get_path_to_port_config_file() - platform_sfputil.read_porttab_mappings(port_config_file_path) + if sonic_device_util.is_multi_npu(): + # For multi ASIC platforms we pass DIR of port_config_file_path and the number of asics + (platform, hwsku) = device_info.get_platform_and_hwsku() + + # Load platform module from source + platform_path = "/".join([PLATFORM_ROOT_PATH, platform]) + hwsku_path = "/".join([platform_path, hwsku]) + platform_sfputil.read_all_porttab_mappings(hwsku_path, sonic_device_util.get_num_npus()) + else: + # For single ASIC platforms we pass port_config_file_path and the asic_inst as 0 + port_config_file_path = device_info.get_path_to_port_config_file() + platform_sfputil.read_porttab_mappings(port_config_file_path, 0) except Exception as e: log.log_error("Error reading port info (%s)" % str(e), True) sys.exit(3) From c44a74193d8180d22473f8427f6507df983ca895 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Tue, 28 Jul 2020 00:28:19 -0700 Subject: [PATCH 15/29] Updates for sonic-py-common TODO's --- config/main.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/config/main.py b/config/main.py index 89818cb205..5ec0b4a1d4 100755 --- a/config/main.py +++ b/config/main.py @@ -55,7 +55,7 @@ asic_type = None config_db = None -# TODO move to a common file like sonic_device_util.py +# TODO move to sonic-py-common package # Dictionary of SONIC interface name prefixes. SONIC_INTERFACE_PREFIXES = { "Ethernet": "Ethernet", @@ -381,6 +381,7 @@ def interface_name_to_alias(config_db, interface_name): return None +# TODO move to sonic-py-common package def get_interface_table_name(interface_name): """Get table name by interface_name prefix """ @@ -423,7 +424,7 @@ def is_interface_bind_to_vrf(config_db, interface_name): return True return False -# TODO move to a common file like sonic_device_util.py +# TODO move to sonic-py-common package # Validate whether a given namespace name is valid in the device. def validate_namespace(namespace): if not sonic_device_util.is_multi_npu(): @@ -435,6 +436,7 @@ def validate_namespace(namespace): else: return False +# TODO move to sonic-py-common package # Get the table name based on the interface type def get_port_table_name(interface_name): """Get table name by port_name prefix @@ -454,6 +456,7 @@ def get_port_table_name(interface_name): else: return "" +# TODO move to sonic-py-common package # Return the namespace where an interface belongs def get_port_namespace(port): # If it is a non multi-asic platform, or if the interface is management interface From 4c519a50adac9355d5caedf21941c2aa9e02eb35 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Tue, 28 Jul 2020 09:53:16 -0700 Subject: [PATCH 16/29] Updating the multi-asic changes for the new command "config interface break-out" with got introduced. --- config/main.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/config/main.py b/config/main.py index 5ec0b4a1d4..884587d447 100755 --- a/config/main.py +++ b/config/main.py @@ -130,12 +130,12 @@ def shutdown_interfaces(ctx, del_intf_dict): for intf in del_intf_dict.keys(): config_db = ctx.obj['config_db'] if clicommon.get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(intf) + interface_name = interface_alias_to_name(config_db, intf) if interface_name is None: click.echo("[ERROR] interface name is None!") return False - if interface_name_is_valid(intf) is False: + if interface_name_is_valid(config_db, intf) is False: click.echo("[ERROR] Interface name is invalid. Please enter a valid interface name!!") return False @@ -2468,9 +2468,8 @@ def breakout(ctx, interface_name, mode, verbose, force_remove_dependencies, load click.secho("[ERROR] Breakout feature is not available without platform.json file", fg='red') raise click.Abort() - # Connect to config db and get the context - config_db = ConfigDBConnector() - config_db.connect() + # Get the namespace and config_db connector + namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) ctx.obj['config_db'] = config_db target_brkout_mode = mode From 7dbb20aa66a4fb8ab64a340e3e2cb0e5f29308b5 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Tue, 28 Jul 2020 10:39:40 -0700 Subject: [PATCH 17/29] Updates to internal API name, so that it alligns to its functionality. --- config/main.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/config/main.py b/config/main.py index 884587d447..4bd2bbdc65 100755 --- a/config/main.py +++ b/config/main.py @@ -481,7 +481,7 @@ def get_port_namespace(port): return None # Return the derived namespace and config_db connector based on the input interface and namespace -def get_namespace_configDB_connector(ctx, interface_name, namespace): +def get_derived_namespace_and_config_db(ctx, interface_name, namespace): # In multi ASIC platforms, if the user don't give the namespace as input parameter, # we derive the namespace using interface name. if sonic_device_util.is_multi_npu() == True and namespace == DEFAULT_NAMESPACE: @@ -2345,7 +2345,7 @@ def interface(ctx, namespace): def startup(ctx, interface_name): """Start up interface""" # Get the namespace and config_db connector - namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2434,7 +2434,7 @@ def shutdown(ctx, interface_name): def speed(ctx, interface_name, interface_speed, verbose): """Set interface speed""" # Get the namespace and config_db connector - namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2469,7 +2469,7 @@ def breakout(ctx, interface_name, mode, verbose, force_remove_dependencies, load raise click.Abort() # Get the namespace and config_db connector - namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) ctx.obj['config_db'] = config_db target_brkout_mode = mode @@ -2601,7 +2601,7 @@ def mgmt_ip_restart_services(): def mtu(ctx, interface_name, interface_mtu, verbose): """Set interface mtu""" # Get the namespace and config_db connector - namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2621,7 +2621,7 @@ def mtu(ctx, interface_name, interface_mtu, verbose): def fec(ctx, interface_name, interface_fec, verbose): """Set interface fec""" # Get the namespace and config_db connector - namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) if interface_fec not in ["rs", "fc", "none"]: ctx.fail("'fec not in ['rs', 'fc', 'none']!") @@ -2657,7 +2657,7 @@ def ip(ctx): def add(ctx, interface_name, ip_addr, gw): """Add an IP address towards the interface""" # Get the namespace and config_db connector - namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2718,7 +2718,7 @@ def add(ctx, interface_name, ip_addr, gw): def remove(ctx, interface_name, ip_addr): """Remove an IP address from the interface""" # Get the namespace and config_db connector - namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2772,7 +2772,7 @@ def transceiver(ctx): def lpmode(ctx, interface_name, state): """Enable/disable low-power mode for SFP transceiver module""" # Get the namespace and config_db connector - namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2795,7 +2795,7 @@ def lpmode(ctx, interface_name, state): def reset(ctx, interface_name): """Reset SFP transceiver module""" # Get the namespace and config_db connector - namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2829,7 +2829,7 @@ def vrf(ctx): def bind(ctx, interface_name, vrf_name): """Bind the interface to VRF""" # Get the namespace and config_db connector - namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -2866,7 +2866,7 @@ def bind(ctx, interface_name, vrf_name): def unbind(ctx, interface_name): """Unbind the interface to VRF""" # Get the namespace and config_db connector - namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -3298,7 +3298,7 @@ def pfc(ctx): def asymmetric(ctx, interface_name, status): """Set asymmetric PFC configuration.""" # Get the namespace and config_db connector - namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) if get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -3319,7 +3319,7 @@ def asymmetric(ctx, interface_name, status): def priority(ctx, interface_name, priority, status): """Set PFC priority configuration.""" # Get the namespace and config_db connector - namespace, config_db = get_namespace_configDB_connector(ctx, interface_name, ctx.obj['namespace']) + namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) if get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) From f838c60dfe35f33d120b8598b1661e8cb9ae5b43 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Wed, 29 Jul 2020 17:23:20 -0700 Subject: [PATCH 18/29] Updates to take care of following 1. Make namespace option "required" for interface commandsi also, in addition to portchannel, vlan commands 2. Add the choice list of namesapces for user to provide as input. Else user don't know namespaces present. --- config/main.py | 129 ++++++++++++++++++++++--------------------------- 1 file changed, 58 insertions(+), 71 deletions(-) diff --git a/config/main.py b/config/main.py index 4bd2bbdc65..253808f2ec 100755 --- a/config/main.py +++ b/config/main.py @@ -480,24 +480,6 @@ def get_port_namespace(port): return None -# Return the derived namespace and config_db connector based on the input interface and namespace -def get_derived_namespace_and_config_db(ctx, interface_name, namespace): - # In multi ASIC platforms, if the user don't give the namespace as input parameter, - # we derive the namespace using interface name. - if sonic_device_util.is_multi_npu() == True and namespace == DEFAULT_NAMESPACE: - ns_name = get_port_namespace(interface_name) - if ns_name is None: - # If namespace cannot be derived from interface name, need input from user - ctx.fail("Input the namespace [-n] option to configure interface {}".format(interface_name)) - else: - ns_name = namespace - - # Create the ConfigDBConnector object and connect - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=ns_name) - config_db.connect() - - return ns_name, config_db - def del_interface_bind_to_vrf(config_db, vrf_name): """del interface bind to vrf """ @@ -1301,15 +1283,16 @@ def hostname(new_hostname): # 'portchannel' group ('config portchannel ...') # @config.group(cls=clicommon.AbbreviationGroup) -@click.option('-n', '--namespace', help='Namespace name', default=None) +# TODO add "hidden=True if not sonic_device_util.is_multi_npu() else False", once we have click 7.0 in all branches. +# This will help to hide namespace option for single asic platforms where it is ignored. +@click.option('-n', '--namespace', help='Namespace name', + required=True if sonic_device_util.is_multi_npu() else False, + type=click.Choice(sonic_device_util.get_namespaces() if sonic_device_util.is_multi_npu() else [DEFAULT_NAMESPACE])) @click.pass_context def portchannel(ctx, namespace): - # If multi ASIC platform, check if the namespace entered by user is valid - if sonic_device_util.is_multi_npu(): - if str(namespace) == DEFAULT_NAMESPACE: - ctx.fail("namespace [-n] option required for portchannel/member (add/del)") - if not validate_namespace(str(namespace)): - ctx.fail("Invalid Namespace entered {}".format(str(namespace))) + # Set namespace to default_namespace if it is None. + if namespace is None: + namespace = DEFAULT_NAMESPACE config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=str(namespace)) config_db.connect() @@ -1823,7 +1806,11 @@ def warm_restart_bgp_eoiu(ctx, enable): # @config.group(cls=AbbreviationGroup) @click.pass_context -@click.option('-n', '--namespace', help='Namespace name', default=DEFAULT_NAMESPACE) +# TODO add "hidden=True if not sonic_device_util.is_multi_npu() else False", once we have click 7.0 in all branches. +# This will help to hide namespace option for single asic platforms where it is ignored. +@click.option('-n', '--namespace', help='Namespace name', + required=True if sonic_device_util.is_multi_npu() else False, + type=click.Choice(sonic_device_util.get_namespaces() if sonic_device_util.is_multi_npu() else [DEFAULT_NAMESPACE])) @click.option('-s', '--redis-unix-socket-path', help='unix socket path for redis connection') def vlan(ctx, redis_unix_socket_path, namespace): """VLAN-related configuration tasks""" @@ -1831,12 +1818,9 @@ def vlan(ctx, redis_unix_socket_path, namespace): if redis_unix_socket_path: kwargs['unix_socket_path'] = redis_unix_socket_path - # If multi ASIC platform, check if the namespace entered by user is valid - if sonic_device_util.is_multi_npu(): - if str(namespace) == DEFAULT_NAMESPACE: - ctx.fail("namespace [-n] option required for vlan/member (add/del)") - if not validate_namespace(str(namespace)): - ctx.fail("Invalid Namespace entered {}".format(str(namespace))) + # Set namespace to default_namespace if it is None. + if namespace is None: + namespace = DEFAULT_NAMESPACE config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=str(namespace), **kwargs) config_db.connect(wait_for_init=False) @@ -2324,16 +2308,20 @@ def remove_neighbor(neighbor_ip_or_hostname): # @config.group(cls=clicommon.AbbreviationGroup) -@click.option('-n', '--namespace', help='Namespace name', default=None) +# TODO add "hidden=True if not sonic_device_util.is_multi_npu() else False", once we have click 7.0 in all branches. +# This will help to hide namespace option for single asic platforms where it is ignored. +@click.option('-n', '--namespace', help='Namespace name', + required=True if sonic_device_util.is_multi_npu() else False, + type=click.Choice(sonic_device_util.get_namespaces() if sonic_device_util.is_multi_npu() else [DEFAULT_NAMESPACE])) @click.pass_context def interface(ctx, namespace): """Interface-related configuration tasks""" - # Check if the namespace entered by user is valid - if sonic_device_util.is_multi_npu(): - if str(namespace) != DEFAULT_NAMESPACE and not validate_namespace(str(namespace)): - ctx.fail("Invalid Namespace entered {}".format(str(namespace))) - - ctx.obj = {'namespace': str(namespace)} + # Set namespace to default_namespace if it is None. + if namespace is None: + namespace = DEFAULT_NAMESPACE + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=str(namespace)) + config_db.connect() + ctx.obj = {'config_db': config_db, 'namespace': str(namespace)} # # 'startup' subcommand @@ -2344,8 +2332,8 @@ def interface(ctx, namespace): @click.pass_context def startup(ctx, interface_name): """Start up interface""" - # Get the namespace and config_db connector - namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) + # 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) @@ -2433,8 +2421,8 @@ def shutdown(ctx, interface_name): @click.option('-v', '--verbose', is_flag=True, help="Enable verbose output") def speed(ctx, interface_name, interface_speed, verbose): """Set interface speed""" - # Get the namespace and config_db connector - namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) + # 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) @@ -2443,7 +2431,7 @@ def speed(ctx, interface_name, interface_speed, verbose): log.log_info("'interface speed {} {}' executing...".format(interface_name, interface_speed)) - command = "portconfig -p {} -s {} -n {}".format(interface_name, interface_speed, namespace) + command = "portconfig -p {} -s {} -n {}".format(interface_name, interface_speed, ctx.obj['namespace']) if verbose: command += " -vv" clicommon.run_command(command, display_cmd=verbose) @@ -2468,9 +2456,8 @@ def breakout(ctx, interface_name, mode, verbose, force_remove_dependencies, load click.secho("[ERROR] Breakout feature is not available without platform.json file", fg='red') raise click.Abort() - # Get the namespace and config_db connector - namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) - ctx.obj['config_db'] = config_db + # Get the config_db connector + config_db = ctx.obj['config_db'] target_brkout_mode = mode @@ -2600,15 +2587,15 @@ def mgmt_ip_restart_services(): @click.option('-v', '--verbose', is_flag=True, help="Enable verbose output") def mtu(ctx, interface_name, interface_mtu, verbose): """Set interface mtu""" - # Get the namespace and config_db connector - namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) + # 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!") - command = "portconfig -p {} -m {} -n {}".format(interface_name, interface_mtu, namespace) + command = "portconfig -p {} -m {} -n {}".format(interface_name, interface_mtu, ctx.obj['namespace']) if verbose: command += " -vv" clicommon.run_command(command, display_cmd=verbose) @@ -2620,8 +2607,8 @@ def mtu(ctx, interface_name, interface_mtu, verbose): @click.option('-v', '--verbose', is_flag=True, help="Enable verbose output") def fec(ctx, interface_name, interface_fec, verbose): """Set interface fec""" - # Get the namespace and config_db connector - namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) + # Get the config_db connector + config_db = ctx.obj['config_db'] if interface_fec not in ["rs", "fc", "none"]: ctx.fail("'fec not in ['rs', 'fc', 'none']!") @@ -2630,7 +2617,7 @@ def fec(ctx, interface_name, interface_fec, verbose): if interface_name is None: ctx.fail("'interface_name' is None!") - command = "portconfig -p {} -f {} -n {}".format(interface_name, interface_fec, namespace) + command = "portconfig -p {} -f {} -n {}".format(interface_name, interface_fec, ctx.obj['namespace']) if verbose: command += " -vv" clicommon.run_command(command, display_cmd=verbose) @@ -2656,8 +2643,8 @@ def ip(ctx): @click.pass_context def add(ctx, interface_name, ip_addr, gw): """Add an IP address towards the interface""" - # Get the namespace and config_db connector - namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) + # 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) @@ -2717,8 +2704,8 @@ def add(ctx, interface_name, ip_addr, gw): @click.pass_context def remove(ctx, interface_name, ip_addr): """Remove an IP address from the interface""" - # Get the namespace and config_db connector - namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) + # 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) @@ -2744,7 +2731,7 @@ def remove(ctx, interface_name, ip_addr): config_db.set_entry(table_name, interface_name, None) if sonic_device_util.is_multi_npu(): - command = "sudo ip netns exec {} ip neigh flush dev {} {}".format(namespace, interface_name, ip_addr) + command = "sudo ip netns exec {} ip neigh flush dev {} {}".format(ctx.obj['namespace'], interface_name, ip_addr) else: command = "ip neigh flush dev {} {}".format(interface_name, ip_addr) run_command(command) @@ -2771,8 +2758,8 @@ def transceiver(ctx): @click.pass_context def lpmode(ctx, interface_name, state): """Enable/disable low-power mode for SFP transceiver module""" - # Get the namespace and config_db connector - namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) + # 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) @@ -2794,8 +2781,8 @@ def lpmode(ctx, interface_name, state): @click.pass_context def reset(ctx, interface_name): """Reset SFP transceiver module""" - # Get the namespace and config_db connector - namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) + # 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) @@ -2828,8 +2815,8 @@ def vrf(ctx): @click.pass_context def bind(ctx, interface_name, vrf_name): """Bind the interface to VRF""" - # Get the namespace and config_db connector - namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) + # 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) @@ -2848,7 +2835,7 @@ def bind(ctx, interface_name, vrf_name): config_db.set_entry(table_name, interface_del, None) config_db.set_entry(table_name, interface_name, None) # When config_db del entry and then add entry with same key, the DEL will lost. - state_db = SonicV2Connector(use_unix_socket_path=True, namespace=namespace) + state_db = SonicV2Connector(use_unix_socket_path=True, namespace=ctx.obj['namespace']) state_db.connect(state_db.STATE_DB, False) _hash = '{}{}'.format('INTERFACE_TABLE|', interface_name) while state_db.get(state_db.STATE_DB, _hash, "state") == "ok": @@ -2865,8 +2852,8 @@ def bind(ctx, interface_name, vrf_name): @click.pass_context def unbind(ctx, interface_name): """Unbind the interface to VRF""" - # Get the namespace and config_db connector - namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) + # 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) @@ -3297,8 +3284,8 @@ def pfc(ctx): @click.pass_context def asymmetric(ctx, interface_name, status): """Set asymmetric PFC configuration.""" - # Get the namespace and config_db connector - namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) + # Get the config_db connector + config_db = ctx.obj['config_db'] if get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) @@ -3318,8 +3305,8 @@ def asymmetric(ctx, interface_name, status): @click.pass_context def priority(ctx, interface_name, priority, status): """Set PFC priority configuration.""" - # Get the namespace and config_db connector - namespace, config_db = get_derived_namespace_and_config_db(ctx, interface_name, ctx.obj['namespace']) + # Get the config_db connector + config_db = ctx.obj['config_db'] if get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, interface_name) From dd449dca7a1ef61a2631cbc16690465cc9088da8 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Wed, 29 Jul 2020 19:55:58 -0700 Subject: [PATCH 19/29] Updates to mirror session commands. Add # TODO for API's in mirror CLI to be enhanced to support multi-asic. --- config/main.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/config/main.py b/config/main.py index 253808f2ec..16c0f763eb 100755 --- a/config/main.py +++ b/config/main.py @@ -58,7 +58,7 @@ # TODO move to sonic-py-common package # Dictionary of SONIC interface name prefixes. SONIC_INTERFACE_PREFIXES = { - "Ethernet": "Ethernet", + "Ethernet-FrontPanel": "Ethernet", "PortChannel": "PortChannel", "Vlan": "Vlan", "Loopback": "Loopback", @@ -385,7 +385,7 @@ def interface_name_to_alias(config_db, interface_name): def get_interface_table_name(interface_name): """Get table name by interface_name prefix """ - if interface_name.startswith(SONIC_INTERFACE_PREFIXES["Ethernet"]): + if interface_name.startswith(SONIC_INTERFACE_PREFIXES["Ethernet-FrontPanel"]): if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: return "VLAN_SUB_INTERFACE" return "INTERFACE" @@ -441,7 +441,7 @@ def validate_namespace(namespace): def get_port_table_name(interface_name): """Get table name by port_name prefix """ - if interface_name.startswith(SONIC_INTERFACE_PREFIXES["Ethernet"]): + if interface_name.startswith(SONIC_INTERFACE_PREFIXES["Ethernet-FrontPanel"]): if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: return "VLAN_SUB_INTERFACE" return "PORT" @@ -1458,9 +1458,12 @@ def add_erspan(session_name, src_ip, dst_ip, dscp, ttl, gre_type, queue, policer for front_asic_namespaces in namespaces['front_ns']: per_npu_configdb[front_asic_namespaces] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces) per_npu_configdb[front_asic_namespaces].connect() + # TODO Need to work on API's gather_session_info/validate_mirror_session_config to support multi-asic + # as src_port which is a list of ports, dst_port all could be in different asics ? session_info = gather_session_info(config_db, session_info, policer, queue, src_port, direction) if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, None, src_port, direction) is False: return + per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, session_info) @mirror_session.group(cls=clicommon.AbbreviationGroup, name='span') @@ -1482,7 +1485,12 @@ def add(session_name, dst_port, src_port, direction, queue, policer): def add_span(session_name, dst_port, src_port, direction, queue, policer): if clicommon.get_interface_naming_mode() == "alias": - dst_port = interface_alias_to_name(dst_port) + # Get namespace where the port belongs, in case of Single ASIC it is DEFAULT_NAMESPACE + namespace = get_port_namespace(dst_port) + db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + db.connect() + + dst_port = interface_alias_to_name(db, dst_port) if dst_port is None: click.echo("Error: Destination Interface {} is invalid".format(dst_port)) return @@ -1499,12 +1507,6 @@ def add_span(session_name, dst_port, src_port, direction, queue, policer): if not namespaces['front_ns']: config_db = ConfigDBConnector() config_db.connect() - - if get_interface_naming_mode() == "alias": - dst_port = interface_alias_to_name(config_db, dst_port) - if dst_port is None: - click.echo("Error: Destination Interface {} is invalid".format(dst_port)) - return session_info = gather_session_info(config_db, session_info, policer, queue, src_port, direction) if validate_mirror_session_config(config_db, session_name, dst_port, src_port, direction) is False: return @@ -1514,15 +1516,12 @@ def add_span(session_name, dst_port, src_port, direction, queue, policer): for front_asic_namespaces in namespaces['front_ns']: per_npu_configdb[front_asic_namespaces] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces) per_npu_configdb[front_asic_namespaces].connect() - - if get_interface_naming_mode() == "alias": - dst_port = interface_alias_to_name(config_db, dst_port) - if dst_port is None: - click.echo("Error: Destination Interface {} is invalid".format(dst_port)) - return + # TODO Need to work on API's gather_session_info/validate_mirror_session_config to support multi-asic + # as src_port which is a list of ports, dst_port all could be in different asics ? session_info = gather_session_info(config_db, session_info, policer, queue, src_port, direction) if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, dst_port, src_port, direction) is False: return + per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, session_info) From 28fcae0511be3d8673436b3506a8b222668b8ef6 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Fri, 31 Jul 2020 12:57:26 -0700 Subject: [PATCH 20/29] Updates includes the following 1. The API's interface_alias_to_name(), interface_name_is_valid(), interface_name_to_alias(), to handle the case when the input config_db is passed as "None" 2. The API get_port_namespace() API to derive the namesapce if the input interface name is in alias mode. 3. Revert changes made to mirror_session CLI's, to handle multi-asic separately. --- config/main.py | 85 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 25 deletions(-) diff --git a/config/main.py b/config/main.py index 16c0f763eb..641e486ecb 100755 --- a/config/main.py +++ b/config/main.py @@ -315,8 +315,6 @@ def validate_namespace(namespace): def interface_alias_to_name(config_db, interface_alias): """Return default interface name if alias name is given as argument """ - port_dict = config_db.get_table('PORT') - vlan_id = "" sub_intf_sep_idx = -1 if interface_alias is not None: @@ -326,6 +324,19 @@ def interface_alias_to_name(config_db, interface_alias): # interface_alias holds the parent port name so the subsequent logic still applies interface_alias = interface_alias[:sub_intf_sep_idx] + # If the input parameter config_db is None, derive it from interface. + # In single ASIC platform, get_port_namespace() returns DEFAULT_NAMESPACE. + if config_db is None: + namespace = get_port_namespace(interface_alias) + if namespace is None: + return None + + db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + db.connect() + else: + db = config_db + port_dict = db.get_table('PORT') + if interface_alias is not None: if not port_dict: click.echo("port_dict is None!") @@ -338,16 +349,26 @@ def interface_alias_to_name(config_db, interface_alias): # portchannel is passed in as argument, which does not have an alias return interface_alias if sub_intf_sep_idx == -1 else interface_alias + VLAN_SUB_INTERFACE_SEPARATOR + vlan_id - def interface_name_is_valid(config_db, interface_name): """Check if the interface name is valid """ - port_dict = config_db.get_table('PORT') - port_channel_dict = config_db.get_table('PORTCHANNEL') - sub_port_intf_dict = config_db.get_table('VLAN_SUB_INTERFACE') + # If the input parameter config_db is None, derive it from interface. + # In single ASIC platform, get_port_namespace() returns DEFAULT_NAMESPACE. + if config_db is None: + namespace = get_port_namespace(interface_name) + if namespace is None: + return False + + db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + db.connect() + else: + db = config_db + port_dict = db.get_table('PORT') + port_channel_dict = db.get_table('PORTCHANNEL') + sub_port_intf_dict = db.get_table('VLAN_SUB_INTERFACE') if clicommon.get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(config_db, interface_name) + interface_name = interface_alias_to_name(db, interface_name) if interface_name is not None: if not port_dict: @@ -369,7 +390,18 @@ def interface_name_is_valid(config_db, interface_name): def interface_name_to_alias(config_db, interface_name): """Return alias interface name if default name is given as argument """ - port_dict = config_db.get_table('PORT') + # If the input parameter config_db is None, derive it from interface. + # In single ASIC platform, get_port_namespace() returns DEFAULT_NAMESPACE. + if config_db is None: + namespace = get_port_namespace(interface_name) + if namespace is None: + return None + + db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + db.connect() + else: + db = config_db + port_dict = db.get_table('PORT') if interface_name is not None: if not port_dict: @@ -436,7 +468,6 @@ def validate_namespace(namespace): else: return False -# TODO move to sonic-py-common package # Get the table name based on the interface type def get_port_table_name(interface_name): """Get table name by port_name prefix @@ -456,8 +487,8 @@ def get_port_table_name(interface_name): else: return "" -# TODO move to sonic-py-common package # Return the namespace where an interface belongs +# The port name input could be in default mode or in alias mode. def get_port_namespace(port): # If it is a non multi-asic platform, or if the interface is management interface # return DEFAULT_NAMESPACE @@ -474,9 +505,18 @@ def get_port_namespace(port): for namespace in namespaces: config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) config_db.connect() - entry = config_db.get_entry(table_name, port) - if entry: - return namespace + + # If the interface naming mode is alias, search the tables for alias_name. + if get_interface_naming_mode() == "alias": + port_dict = config_db.get_table(table_name) + if port_dict: + for port_name in port_dict.keys(): + if port == port_dict[port_name]['alias']: + return namespace + else: + entry = config_db.get_entry(table_name, port) + if entry: + return namespace return None @@ -1359,6 +1399,7 @@ def del_portchannel_member(ctx, portchannel_name, port_name): db.set_entry('PORTCHANNEL_MEMBER', (portchannel_name, port_name), None) db.set_entry('PORTCHANNEL_MEMBER', portchannel_name + '|' + port_name, None) + # # 'mirror_session' group ('config mirror_session ...') # @@ -1409,7 +1450,7 @@ def add(session_name, src_ip, dst_ip, dscp, ttl, gre_type, queue, policer, src_p """ Add ERSPAN mirror session """ add_erspan(session_name, src_ip, dst_ip, dscp, ttl, gre_type, queue, policer, src_port, direction) -def gather_session_info(config_db, session_info, policer, queue, src_port, direction): +def gather_session_info(session_info, policer, queue, src_port, direction): if policer: session_info['policer'] = policer @@ -1420,7 +1461,7 @@ def gather_session_info(config_db, session_info, policer, queue, src_port, direc if clicommon.get_interface_naming_mode() == "alias": src_port_list = [] for port in src_port.split(","): - src_port_list.append(interface_alias_to_name(config_db, port)) + src_port_list.append(interface_alias_to_name(None, port)) src_port=",".join(src_port_list) session_info['src_port'] = src_port @@ -1442,6 +1483,8 @@ def add_erspan(session_name, src_ip, dst_ip, dscp, ttl, gre_type, queue, policer if gre_type: session_info['gre_type'] = gre_type + session_info = gather_session_info(session_info, policer, queue, src_port, direction) + """ For multi-npu platforms we need to program all front asic namespaces """ @@ -1449,7 +1492,6 @@ def add_erspan(session_name, src_ip, dst_ip, dscp, ttl, gre_type, queue, policer if not namespaces['front_ns']: config_db = ConfigDBConnector() config_db.connect() - session_info = gather_session_info(config_db, session_info, policer, queue, src_port, direction) if validate_mirror_session_config(config_db, session_name, None, src_port, direction) is False: return config_db.set_entry("MIRROR_SESSION", session_name, session_info) @@ -1458,12 +1500,8 @@ def add_erspan(session_name, src_ip, dst_ip, dscp, ttl, gre_type, queue, policer for front_asic_namespaces in namespaces['front_ns']: per_npu_configdb[front_asic_namespaces] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces) per_npu_configdb[front_asic_namespaces].connect() - # TODO Need to work on API's gather_session_info/validate_mirror_session_config to support multi-asic - # as src_port which is a list of ports, dst_port all could be in different asics ? - session_info = gather_session_info(config_db, session_info, policer, queue, src_port, direction) if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, None, src_port, direction) is False: return - per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, session_info) @mirror_session.group(cls=clicommon.AbbreviationGroup, name='span') @@ -1500,6 +1538,8 @@ def add_span(session_name, dst_port, src_port, direction, queue, policer): "dst_port": dst_port, } + session_info = gather_session_info(session_info, policer, queue, src_port, direction) + """ For multi-npu platforms we need to program all front asic namespaces """ @@ -1507,7 +1547,6 @@ def add_span(session_name, dst_port, src_port, direction, queue, policer): if not namespaces['front_ns']: config_db = ConfigDBConnector() config_db.connect() - session_info = gather_session_info(config_db, session_info, policer, queue, src_port, direction) if validate_mirror_session_config(config_db, session_name, dst_port, src_port, direction) is False: return config_db.set_entry("MIRROR_SESSION", session_name, session_info) @@ -1516,12 +1555,8 @@ def add_span(session_name, dst_port, src_port, direction, queue, policer): for front_asic_namespaces in namespaces['front_ns']: per_npu_configdb[front_asic_namespaces] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces) per_npu_configdb[front_asic_namespaces].connect() - # TODO Need to work on API's gather_session_info/validate_mirror_session_config to support multi-asic - # as src_port which is a list of ports, dst_port all could be in different asics ? - session_info = gather_session_info(config_db, session_info, policer, queue, src_port, direction) if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, dst_port, src_port, direction) is False: return - per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, session_info) From 53eae4c707305f1b80afde5500d06963b28e9fff Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Tue, 4 Aug 2020 23:01:29 -0700 Subject: [PATCH 21/29] Minor updates to variable usage and comments. --- config/main.py | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/config/main.py b/config/main.py index 641e486ecb..b7b94d1784 100755 --- a/config/main.py +++ b/config/main.py @@ -331,11 +331,10 @@ def interface_alias_to_name(config_db, interface_alias): if namespace is None: return None - db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - db.connect() - else: - db = config_db - port_dict = db.get_table('PORT') + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() + + port_dict = config_db.get_table('PORT') if interface_alias is not None: if not port_dict: @@ -359,16 +358,15 @@ def interface_name_is_valid(config_db, interface_name): if namespace is None: return False - db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - db.connect() - else: - db = config_db - port_dict = db.get_table('PORT') - port_channel_dict = db.get_table('PORTCHANNEL') - sub_port_intf_dict = db.get_table('VLAN_SUB_INTERFACE') + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() + + port_dict = config_db.get_table('PORT') + port_channel_dict = config_db.get_table('PORTCHANNEL') + sub_port_intf_dict = config_db.get_table('VLAN_SUB_INTERFACE') if clicommon.get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(db, interface_name) + interface_name = interface_alias_to_name(config_db, interface_name) if interface_name is not None: if not port_dict: @@ -397,11 +395,10 @@ def interface_name_to_alias(config_db, interface_name): if namespace is None: return None - db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - db.connect() - else: - db = config_db - port_dict = db.get_table('PORT') + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + config_db.connect() + + port_dict = config_db.get_table('PORT') if interface_name is not None: if not port_dict: @@ -1840,8 +1837,7 @@ def warm_restart_bgp_eoiu(ctx, enable): # @config.group(cls=AbbreviationGroup) @click.pass_context -# TODO add "hidden=True if not sonic_device_util.is_multi_npu() else False", once we have click 7.0 in all branches. -# This will help to hide namespace option for single asic platforms where it is ignored. +# TODO add "hidden=True" keyword for hiding this option with single asic platform, once click 7.0 is present in all branches. @click.option('-n', '--namespace', help='Namespace name', required=True if sonic_device_util.is_multi_npu() else False, type=click.Choice(sonic_device_util.get_namespaces() if sonic_device_util.is_multi_npu() else [DEFAULT_NAMESPACE])) From 3b147c307bef5edc217ca2ab2061b5111361ba40 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Tue, 4 Aug 2020 23:14:47 -0700 Subject: [PATCH 22/29] Remove one occurence of function which happen to remain defined twice during rebase merge. --- config/main.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/config/main.py b/config/main.py index b7b94d1784..6478245075 100755 --- a/config/main.py +++ b/config/main.py @@ -301,6 +301,7 @@ def _get_device_type(): return device_type +# TODO move to sonic-py-common package # Validate whether a given namespace name is valid in the device. def validate_namespace(namespace): if not device_info.is_multi_npu(): @@ -453,18 +454,6 @@ def is_interface_bind_to_vrf(config_db, interface_name): return True return False -# TODO move to sonic-py-common package -# Validate whether a given namespace name is valid in the device. -def validate_namespace(namespace): - if not sonic_device_util.is_multi_npu(): - return True - - namespaces = sonic_device_util.get_all_namespaces() - if namespace in namespaces['front_ns'] + namespaces['back_ns']: - return True - else: - return False - # Get the table name based on the interface type def get_port_table_name(interface_name): """Get table name by port_name prefix From b5bf202dce4434ec5c52d91a8c671283fa93c4e9 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Fri, 14 Aug 2020 00:04:52 -0700 Subject: [PATCH 23/29] Updates to config/main based on the new common utilities --- config/main.py | 150 ++++++++++++++++++------------------------------- 1 file changed, 54 insertions(+), 96 deletions(-) diff --git a/config/main.py b/config/main.py index 6478245075..5d3442c8c7 100755 --- a/config/main.py +++ b/config/main.py @@ -14,7 +14,7 @@ from minigraph import parse_device_desc_xml from portconfig import get_child_ports, get_port_config_file_name -from sonic_py_common import device_info +from sonic_py_common import device_info, logger, multi_asic, interface from swsssdk import ConfigDBConnector, SonicV2Connector, SonicDBConfig from utilities_common.db import Db from utilities_common.intf_filter import parse_interface_in_filter @@ -52,25 +52,6 @@ CFG_LOOPBACK_ID_MAX_VAL = 999 CFG_LOOPBACK_NO="<0-999>" -asic_type = None -config_db = None - -# TODO move to sonic-py-common package -# Dictionary of SONIC interface name prefixes. -SONIC_INTERFACE_PREFIXES = { - "Ethernet-FrontPanel": "Ethernet", - "PortChannel": "PortChannel", - "Vlan": "Vlan", - "Loopback": "Loopback", - "Ethernet-backplane": "Ethernet-BP" -} - -# ========================== Syslog wrappers ========================== - -def log_debug(msg): - syslog.openlog(SYSLOG_IDENTIFIER) - syslog.syslog(syslog.LOG_DEBUG, msg) - syslog.closelog() asic_type = None @@ -246,7 +227,7 @@ def execute_systemctl_per_asic_instance(inst, event, service, action): # Execute action on list of systemd services def execute_systemctl(list_of_services, action): - num_asic = device_info.get_num_npus() + num_asic = multi_asic.get_num_asics() generated_services_list, generated_multi_instance_services = _get_sonic_generated_services(num_asic) if ((generated_services_list == []) and (generated_multi_instance_services == [])): @@ -264,7 +245,7 @@ def execute_systemctl(list_of_services, action): if (service + '.service' in generated_multi_instance_services): # With Multi NPU, Start a thread per instance to do the "action" on multi instance services. - if device_info.is_multi_npu(): + if multi_asic.is_multi_asic(): threads = [] # Use this event object to co-ordinate if any threads raised exception e = threading.Event() @@ -304,10 +285,10 @@ def _get_device_type(): # TODO move to sonic-py-common package # Validate whether a given namespace name is valid in the device. def validate_namespace(namespace): - if not device_info.is_multi_npu(): + if not multi_asic.is_multi_asic(): return True - namespaces = device_info.get_all_namespaces() + namespaces = multi_asic.get_all_namespaces() if namespace in namespaces['front_ns'] + namespaces['back_ns']: return True else: @@ -415,17 +396,17 @@ def interface_name_to_alias(config_db, interface_name): def get_interface_table_name(interface_name): """Get table name by interface_name prefix """ - if interface_name.startswith(SONIC_INTERFACE_PREFIXES["Ethernet-FrontPanel"]): + if interface_name.startswith(interface.front_panel_prefix()): if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: return "VLAN_SUB_INTERFACE" return "INTERFACE" - elif interface_name.startswith(SONIC_INTERFACE_PREFIXES["PortChannel"]): + elif interface_name.startswith(interface.portchannel_prefix()): if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: return "VLAN_SUB_INTERFACE" return "PORTCHANNEL_INTERFACE" - elif interface_name.startswith(SONIC_INTERFACE_PREFIXES["Vlan"]): + elif interface_name.startswith(interface.vlan_prefix()): return "VLAN_INTERFACE" - elif interface_name.startswith(SONIC_INTERFACE_PREFIXES["Loopback"]): + elif interface_name.startswith(interface.loopback_prefix()): return "LOOPBACK_INTERFACE" else: return "" @@ -458,17 +439,17 @@ def is_interface_bind_to_vrf(config_db, interface_name): def get_port_table_name(interface_name): """Get table name by port_name prefix """ - if interface_name.startswith(SONIC_INTERFACE_PREFIXES["Ethernet-FrontPanel"]): + if interface_name.startswith(interface.front_panel_prefix()): if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: return "VLAN_SUB_INTERFACE" return "PORT" - elif interface_name.startswith(SONIC_INTERFACE_PREFIXES["PortChannel"]): + elif interface_name.startswith(interface.portchannel_prefix()): if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: return "VLAN_SUB_INTERFACE" return "PORTCHANNEL" - elif interface_name.startswith(SONIC_INTERFACE_PREFIXES["Vlan"]): + elif interface_name.startswith(interface.vlan_prefix()): return "VLAN_INTERFACE" - elif interface_name.startswith(SONIC_INTERFACE_PREFIXES["Loopback"]): + elif interface_name.startswith(interface.loopback_prefix()): return "LOOPBACK_INTERFACE" else: return "" @@ -478,7 +459,7 @@ def get_port_table_name(interface_name): def get_port_namespace(port): # If it is a non multi-asic platform, or if the interface is management interface # return DEFAULT_NAMESPACE - if sonic_device_util.is_multi_npu() == False or port == 'eth0': + if not multi_asic.is_multi_asic() or port == 'eth0': return DEFAULT_NAMESPACE # Get the table to check for interface presence @@ -486,7 +467,7 @@ def get_port_namespace(port): if table_name == "": return None - ns_list = sonic_device_util.get_all_namespaces() + ns_list = multi_asic.get_all_namespaces() namespaces = ns_list['front_ns'] + ns_list['back_ns'] for namespace in namespaces: config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) @@ -533,8 +514,8 @@ def set_interface_naming_mode(mode): # created for the front facing ASIC. namespaces = [DEFAULT_NAMESPACE] - if sonic_device_util.is_multi_npu(): - namespaces = sonic_device_util.get_all_namespaces()['front_ns'] + if multi_asic.is_multi_asic(): + namespaces = multi_asic.get_all_namespaces()['front_ns'] # Ensure all interfaces have an 'alias' key in PORT dict config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespaces[0]) @@ -692,8 +673,8 @@ def _clear_qos(): 'BUFFER_QUEUE'] namespace_list = [DEFAULT_NAMESPACE] - if device_info.get_num_npus() > 1: - namespace_list = device_info.get_namespaces() + if multi_asic.get_num_asics() > 1: + namespace_list = multi_asic.get_namespaces_from_linux() for ns in namespace_list: if ns is DEFAULT_NAMESPACE: @@ -941,8 +922,6 @@ def config(ctx): if os.geteuid() != 0: exit("Root privileges are required for this operation") - SonicDBConfig.load_sonic_global_db_config() - ctx.obj = Db() config.add_command(aaa.aaa) @@ -960,11 +939,11 @@ def save(filename): """Export current config DB to a file on disk.\n : Names of configuration file(s) to save, separated by comma with no spaces in between """ - num_asic = device_info.get_num_npus() + num_asic = multi_asic.get_num_asics() cfg_files = [] num_cfg_file = 1 - if device_info.is_multi_npu(): + if multi_asic.is_multi_asic(): num_cfg_file += num_asic # If the user give the filename[s], extract the file names. @@ -1016,11 +995,11 @@ def load(filename, yes): if not yes: click.confirm(message, abort=True) - num_asic = device_info.get_num_npus() + num_asic = multi_asic.get_num_asics() cfg_files = [] num_cfg_file = 1 - if device_info.is_multi_npu(): + if multi_asic.is_multi_asic(): num_cfg_file += num_asic # If the user give the filename[s], extract the file names. @@ -1083,11 +1062,11 @@ def reload(db, filename, yes, load_sysinfo, no_service_restart): log.log_info("'reload' executing...") - num_asic = device_info.get_num_npus() + num_asic = multi_asic.get_num_asics() cfg_files = [] num_cfg_file = 1 - if device_info.is_multi_npu(): + if multi_asic.is_multi_asic(): num_cfg_file += num_asic # If the user give the filename[s], extract the file names. @@ -1229,9 +1208,9 @@ def load_minigraph(db, no_service_restart): # for mulit Asic platform the empty string to generate the config # for host namespace_list = [DEFAULT_NAMESPACE] - num_npus = device_info.get_num_npus() + num_npus = multi_asic.get_num_asics() if num_npus > 1: - namespace_list += device_info.get_namespaces() + namespace_list += multi_asic.get_namespaces_from_linux() for namespace in namespace_list: if namespace is DEFAULT_NAMESPACE: @@ -1312,8 +1291,8 @@ def hostname(new_hostname): # TODO add "hidden=True if not sonic_device_util.is_multi_npu() else False", once we have click 7.0 in all branches. # This will help to hide namespace option for single asic platforms where it is ignored. @click.option('-n', '--namespace', help='Namespace name', - required=True if sonic_device_util.is_multi_npu() else False, - type=click.Choice(sonic_device_util.get_namespaces() if sonic_device_util.is_multi_npu() else [DEFAULT_NAMESPACE])) + required=True if multi_asic.is_multi_asic() else False, + type=click.Choice(sonic_device_util.get_namespaces() if multi_asic.is_multi_asic() else [DEFAULT_NAMESPACE])) @click.pass_context def portchannel(ctx, namespace): # Set namespace to default_namespace if it is None. @@ -1474,7 +1453,7 @@ def add_erspan(session_name, src_ip, dst_ip, dscp, ttl, gre_type, queue, policer """ For multi-npu platforms we need to program all front asic namespaces """ - namespaces = device_info.get_all_namespaces() + namespaces = multi_asic.get_all_namespaces() if not namespaces['front_ns']: config_db = ConfigDBConnector() config_db.connect() @@ -1529,7 +1508,7 @@ def add_span(session_name, dst_port, src_port, direction, queue, policer): """ For multi-npu platforms we need to program all front asic namespaces """ - namespaces = device_info.get_all_namespaces() + namespaces = multi_asic.get_all_namespaces() if not namespaces['front_ns']: config_db = ConfigDBConnector() config_db.connect() @@ -1554,7 +1533,7 @@ def remove(session_name): """ For multi-npu platforms we need to program all front asic namespaces """ - namespaces = device_info.get_all_namespaces() + namespaces = multi_asic.get_all_namespaces() if not namespaces['front_ns']: config_db = ConfigDBConnector() config_db.connect() @@ -1676,14 +1655,14 @@ def reload(): _, hwsku_path = device_info.get_paths_to_platform_and_hwsku_dirs() namespace_list = [DEFAULT_NAMESPACE] - if device_info.get_num_npus() > 1: - namespace_list = device_info.get_namespaces() + if multi_asic.get_num_asics() > 1: + namespace_list = multi_asic.get_namespaces_from_linux() for ns in namespace_list: if ns is DEFAULT_NAMESPACE: asic_id_suffix = "" else: - asic_id = device_info.get_npu_id_from_name(ns) + asic_id = multi_asic.get_asic_id_from_name(ns) if asic_id is None: click.secho( "Command 'qos reload' failed with invalid namespace '{}'". @@ -1828,8 +1807,8 @@ def warm_restart_bgp_eoiu(ctx, enable): @click.pass_context # TODO add "hidden=True" keyword for hiding this option with single asic platform, once click 7.0 is present in all branches. @click.option('-n', '--namespace', help='Namespace name', - required=True if sonic_device_util.is_multi_npu() else False, - type=click.Choice(sonic_device_util.get_namespaces() if sonic_device_util.is_multi_npu() else [DEFAULT_NAMESPACE])) + required=True if multi_asic.is_multi_asic() else False, + type=click.Choice(sonic_device_util.get_namespaces() if multi_asic.is_multi_asic() else [DEFAULT_NAMESPACE])) @click.option('-s', '--redis-unix-socket-path', help='unix socket path for redis connection') def vlan(ctx, redis_unix_socket_path, namespace): """VLAN-related configuration tasks""" @@ -1888,13 +1867,6 @@ def vlan_member(ctx): def add_vlan_member(ctx, vid, interface_name, untagged): """Add VLAN member""" log.log_info("'vlan member add {} {}' executing...".format(vid, interface_name)) - if sonic_device_util.is_multi_npu(): - # Get the namespace based on the member interface given by user. - intf_ns = get_intf_namespace(interface_name) - if intf_ns is None: - ctx.fail("member interface {} is invalid".format(interface_name)) - elif intf_ns != ctx.obj['namespace']: - ctx.fail("member interface {} doesn't exist in namespace {}".format(interface_name, ctx.obj['namespace'])) db = ctx.obj['db'] @@ -1944,13 +1916,6 @@ def add_vlan_member(ctx, vid, interface_name, untagged): def del_vlan_member(ctx, vid, interface_name): """Delete VLAN member""" log.log_info("'vlan member del {} {}' executing...".format(vid, interface_name)) - if sonic_device_util.is_multi_npu(): - # Get the namespace based on the member interface given by user. - intf_ns = get_intf_namespace(interface_name) - if intf_ns is None: - ctx.fail("member interface {} is invalid".format(interface_name)) - elif intf_ns != ctx.obj['namespace']: - ctx.fail("member interface {} doesn't exist in namespace {}".format(interface_name, ctx.obj['namespace'])) db = ctx.obj['db'] @@ -2191,8 +2156,8 @@ def all(verbose): namespaces = [DEFAULT_NAMESPACE] ignore_local_hosts = False - if device_info.is_multi_npu(): - ns_list = device_info.get_all_namespaces() + if multi_asic.is_multi_asic(): + ns_list = multi_asic.get_all_namespaces() namespaces = ns_list['front_ns'] ignore_local_hosts = True @@ -2217,8 +2182,8 @@ def neighbor(ipaddr_or_hostname, verbose): namespaces = [DEFAULT_NAMESPACE] found_neighbor = False - if device_info.is_multi_npu(): - ns_list = device_info.get_all_namespaces() + if multi_asic.is_multi_asic(): + ns_list = multi_asic.get_all_namespaces() namespaces = ns_list['front_ns'] + ns_list['back_ns'] # Connect to CONFIG_DB in linux host (in case of single ASIC) or CONFIG_DB in all the @@ -2248,8 +2213,8 @@ def all(verbose): namespaces = [DEFAULT_NAMESPACE] ignore_local_hosts = False - if device_info.is_multi_npu(): - ns_list = device_info.get_all_namespaces() + if multi_asic.is_multi_asic(): + ns_list = multi_asic.get_all_namespaces() namespaces = ns_list['front_ns'] ignore_local_hosts = True @@ -2274,8 +2239,8 @@ def neighbor(ipaddr_or_hostname, verbose): namespaces = [DEFAULT_NAMESPACE] found_neighbor = False - if device_info.is_multi_npu(): - ns_list = device_info.get_all_namespaces() + if multi_asic.is_multi_asic(): + ns_list = multi_asic.get_all_namespaces() namespaces = ns_list['front_ns'] + ns_list['back_ns'] # Connect to CONFIG_DB in linux host (in case of single ASIC) or CONFIG_DB in all the @@ -2307,8 +2272,8 @@ def remove_neighbor(neighbor_ip_or_hostname): namespaces = [DEFAULT_NAMESPACE] removed_neighbor = False - if device_info.is_multi_npu(): - ns_list = device_info.get_all_namespaces() + if multi_asic.is_multi_asic(): + ns_list = multi_asic.get_all_namespaces() namespaces = ns_list['front_ns'] + ns_list['back_ns'] # Connect to CONFIG_DB in linux host (in case of single ASIC) or CONFIG_DB in all the @@ -2330,8 +2295,8 @@ def remove_neighbor(neighbor_ip_or_hostname): # TODO add "hidden=True if not sonic_device_util.is_multi_npu() else False", once we have click 7.0 in all branches. # This will help to hide namespace option for single asic platforms where it is ignored. @click.option('-n', '--namespace', help='Namespace name', - required=True if sonic_device_util.is_multi_npu() else False, - type=click.Choice(sonic_device_util.get_namespaces() if sonic_device_util.is_multi_npu() else [DEFAULT_NAMESPACE])) + required=True if multi_asic.is_multi_asic() else False, + type=click.Choice(sonic_device_util.get_namespaces() if multi_asic.is_multi_asic() else [DEFAULT_NAMESPACE])) @click.pass_context def interface(ctx, namespace): """Interface-related configuration tasks""" @@ -2360,7 +2325,7 @@ def startup(ctx, interface_name): ctx.fail("'interface_name' is None!") intf_fs = parse_interface_in_filter(interface_name) - if len(intf_fs) > 1 and sonic_device_util.is_multi_npu(): + if len(intf_fs) > 1 and multi_asic.is_multi_asic(): ctx.fail("Interface range not supported in multi-asic platforms !!") if len(intf_fs) == 1 and interface_name_is_valid(config_db, interface_name) is False: @@ -2392,15 +2357,8 @@ def startup(ctx, interface_name): def shutdown(ctx, interface_name): """Shut down interface""" log.log_info("'interface shutdown {}' executing...".format(interface_name)) - namespace = ctx.obj['namespace'] - if sonic_device_util.is_multi_npu() and namespace is None: - ns = get_intf_namespace(interface_name) - if ns is None: - ctx.fail("namespace [-n] option required to configure interface {}".format(interface_name)) - else: - namespace = ns - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - config_db.connect() + # 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) @@ -2408,7 +2366,7 @@ def shutdown(ctx, interface_name): ctx.fail("'interface_name' is None!") intf_fs = parse_interface_in_filter(interface_name) - if len(intf_fs) > 1 and sonic_device_util.is_multi_npu(): + if len(intf_fs) > 1 and multi_asic.is_multi_asic(): ctx.fail("Interface range not supported in multi-asic platforms !!") if len(intf_fs) == 1 and interface_name_is_valid(config_db, interface_name) is False: @@ -2749,7 +2707,7 @@ def remove(ctx, interface_name, ip_addr): if len(interface_dependent) == 0 and is_interface_bind_to_vrf(config_db, interface_name) is False: config_db.set_entry(table_name, interface_name, None) - if sonic_device_util.is_multi_npu(): + if multi_asic.is_multi_asic(): command = "sudo ip netns exec {} ip neigh flush dev {} {}".format(ctx.obj['namespace'], interface_name, ip_addr) else: command = "ip neigh flush dev {} {}".format(interface_name, ip_addr) From 2d2e7c9f8e3ba168db4270ab596dd86691f8f721 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Fri, 14 Aug 2020 12:11:58 -0700 Subject: [PATCH 24/29] Updates to the new common multi_asic API's --- config/main.py | 17 ++++++----------- sfputil/main.py | 6 +++--- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/config/main.py b/config/main.py index 5d3442c8c7..3e3a5b2c27 100755 --- a/config/main.py +++ b/config/main.py @@ -1288,11 +1288,9 @@ def hostname(new_hostname): # 'portchannel' group ('config portchannel ...') # @config.group(cls=clicommon.AbbreviationGroup) -# TODO add "hidden=True if not sonic_device_util.is_multi_npu() else False", once we have click 7.0 in all branches. -# This will help to hide namespace option for single asic platforms where it is ignored. +# TODO add "hidden=True if this is a single ASIC platform, once we have click 7.0 in all branches. @click.option('-n', '--namespace', help='Namespace name', - required=True if multi_asic.is_multi_asic() else False, - type=click.Choice(sonic_device_util.get_namespaces() if multi_asic.is_multi_asic() else [DEFAULT_NAMESPACE])) + required=True if multi_asic.is_multi_asic() else False, type=click.Choice(multi_asic.get_namespace_list())) @click.pass_context def portchannel(ctx, namespace): # Set namespace to default_namespace if it is None. @@ -1805,10 +1803,9 @@ def warm_restart_bgp_eoiu(ctx, enable): # @config.group(cls=AbbreviationGroup) @click.pass_context -# TODO add "hidden=True" keyword for hiding this option with single asic platform, once click 7.0 is present in all branches. +# TODO add "hidden=True if this is a single ASIC platform, once we have click 7.0 in all branches. @click.option('-n', '--namespace', help='Namespace name', - required=True if multi_asic.is_multi_asic() else False, - type=click.Choice(sonic_device_util.get_namespaces() if multi_asic.is_multi_asic() else [DEFAULT_NAMESPACE])) + required=True if multi_asic.is_multi_asic() else False, type=click.Choice(multi_asic.get_namespace_list())) @click.option('-s', '--redis-unix-socket-path', help='unix socket path for redis connection') def vlan(ctx, redis_unix_socket_path, namespace): """VLAN-related configuration tasks""" @@ -2292,11 +2289,9 @@ def remove_neighbor(neighbor_ip_or_hostname): # @config.group(cls=clicommon.AbbreviationGroup) -# TODO add "hidden=True if not sonic_device_util.is_multi_npu() else False", once we have click 7.0 in all branches. -# This will help to hide namespace option for single asic platforms where it is ignored. +# TODO add "hidden=True if this is a single ASIC platform, once we have click 7.0 in all branches. @click.option('-n', '--namespace', help='Namespace name', - required=True if multi_asic.is_multi_asic() else False, - type=click.Choice(sonic_device_util.get_namespaces() if multi_asic.is_multi_asic() else [DEFAULT_NAMESPACE])) + required=True if multi_asic.is_multi_asic() else False, type=click.Choice(multi_asic.get_namespace_list())) @click.pass_context def interface(ctx, namespace): """Interface-related configuration tasks""" diff --git a/sfputil/main.py b/sfputil/main.py index 4eae0adb6a..e44952d714 100644 --- a/sfputil/main.py +++ b/sfputil/main.py @@ -11,7 +11,7 @@ import sys import click - from sonic_py_common import device_info, logger + from sonic_py_common import device_info, logger, multi_asic from tabulate import tabulate except ImportError as e: raise ImportError("%s - required module not found" % str(e)) @@ -305,14 +305,14 @@ def cli(): # Load port info try: - if sonic_device_util.is_multi_npu(): + if multi_asic.is_multi_asic(): # For multi ASIC platforms we pass DIR of port_config_file_path and the number of asics (platform, hwsku) = device_info.get_platform_and_hwsku() # Load platform module from source platform_path = "/".join([PLATFORM_ROOT_PATH, platform]) hwsku_path = "/".join([platform_path, hwsku]) - platform_sfputil.read_all_porttab_mappings(hwsku_path, sonic_device_util.get_num_npus()) + platform_sfputil.read_all_porttab_mappings(hwsku_path, multi_asic.get_num_asics()) else: # For single ASIC platforms we pass port_config_file_path and the asic_inst as 0 port_config_file_path = device_info.get_path_to_port_config_file() From 07b24e356f1b132397a6acfe3d250edf6a6c3586 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Fri, 14 Aug 2020 14:13:07 -0700 Subject: [PATCH 25/29] Vlan command moved to a different file vlan.py, and some updates while rebasing. --- config/main.py | 167 ++----------------------------------------------- 1 file changed, 5 insertions(+), 162 deletions(-) diff --git a/config/main.py b/config/main.py index 3e3a5b2c27..b1accab2c8 100755 --- a/config/main.py +++ b/config/main.py @@ -14,7 +14,7 @@ from minigraph import parse_device_desc_xml from portconfig import get_child_ports, get_port_config_file_name -from sonic_py_common import device_info, logger, multi_asic, interface +from sonic_py_common import device_info, multi_asic, interface from swsssdk import ConfigDBConnector, SonicV2Connector, SonicDBConfig from utilities_common.db import Db from utilities_common.intf_filter import parse_interface_in_filter @@ -312,10 +312,9 @@ def interface_alias_to_name(config_db, interface_alias): namespace = get_port_namespace(interface_alias) if namespace is None: return None - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - config_db.connect() + config_db.connect() port_dict = config_db.get_table('PORT') if interface_alias is not None: @@ -339,10 +338,9 @@ def interface_name_is_valid(config_db, interface_name): namespace = get_port_namespace(interface_name) if namespace is None: return False - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - config_db.connect() + config_db.connect() port_dict = config_db.get_table('PORT') port_channel_dict = config_db.get_table('PORTCHANNEL') sub_port_intf_dict = config_db.get_table('VLAN_SUB_INTERFACE') @@ -376,10 +374,9 @@ def interface_name_to_alias(config_db, interface_name): namespace = get_port_namespace(interface_name) if namespace is None: return None - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - config_db.connect() + config_db.connect() port_dict = config_db.get_table('PORT') if interface_name is not None: @@ -1486,12 +1483,7 @@ def add(session_name, dst_port, src_port, direction, queue, policer): def add_span(session_name, dst_port, src_port, direction, queue, policer): if clicommon.get_interface_naming_mode() == "alias": - # Get namespace where the port belongs, in case of Single ASIC it is DEFAULT_NAMESPACE - namespace = get_port_namespace(dst_port) - db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) - db.connect() - - dst_port = interface_alias_to_name(db, dst_port) + dst_port = interface_alias_to_name(None, dst_port) if dst_port is None: click.echo("Error: Destination Interface {} is invalid".format(dst_port)) return @@ -1798,155 +1790,6 @@ def warm_restart_bgp_eoiu(ctx, enable): db = ctx.obj['db'] db.mod_entry('WARM_RESTART', 'bgp', {'bgp_eoiu': enable}) -# -# 'vlan' group ('config vlan ...') -# -@config.group(cls=AbbreviationGroup) -@click.pass_context -# TODO add "hidden=True if this is a single ASIC platform, once we have click 7.0 in all branches. -@click.option('-n', '--namespace', help='Namespace name', - required=True if multi_asic.is_multi_asic() else False, type=click.Choice(multi_asic.get_namespace_list())) -@click.option('-s', '--redis-unix-socket-path', help='unix socket path for redis connection') -def vlan(ctx, redis_unix_socket_path, namespace): - """VLAN-related configuration tasks""" - kwargs = {} - if redis_unix_socket_path: - kwargs['unix_socket_path'] = redis_unix_socket_path - - # Set namespace to default_namespace if it is None. - if namespace is None: - namespace = DEFAULT_NAMESPACE - - config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=str(namespace), **kwargs) - config_db.connect(wait_for_init=False) - ctx.obj = {'db': config_db, 'namespace': str(namespace)} - -@vlan.command('add') -@click.argument('vid', metavar='', required=True, type=int) -@click.pass_context -def add_vlan(ctx, vid): - if vid >= 1 and vid <= 4094: - db = ctx.obj['db'] - vlan = 'Vlan{}'.format(vid) - if len(db.get_entry('VLAN', vlan)) != 0: - ctx.fail("{} already exists".format(vlan)) - db.set_entry('VLAN', vlan, {'vlanid': vid}) - else : - ctx.fail("Invalid VLAN ID {} (1-4094)".format(vid)) - -@vlan.command('del') -@click.argument('vid', metavar='', required=True, type=int) -@click.pass_context -def del_vlan(ctx, vid): - """Delete VLAN""" - log.log_info("'vlan del {}' executing...".format(vid)) - db = ctx.obj['db'] - keys = [ (k, v) for k, v in db.get_table('VLAN_MEMBER') if k == 'Vlan{}'.format(vid) ] - for k in keys: - db.set_entry('VLAN_MEMBER', k, None) - db.set_entry('VLAN', 'Vlan{}'.format(vid), None) - - -# -# 'member' group ('config vlan member ...') -# -@vlan.group(cls=AbbreviationGroup, name='member') -@click.pass_context -def vlan_member(ctx): - pass - - -@vlan_member.command('add') -@click.argument('vid', metavar='', required=True, type=int) -@click.argument('interface_name', metavar='', required=True) -@click.option('-u', '--untagged', is_flag=True) -@click.pass_context -def add_vlan_member(ctx, vid, interface_name, untagged): - """Add VLAN member""" - log.log_info("'vlan member add {} {}' executing...".format(vid, interface_name)) - - db = ctx.obj['db'] - - # Check if the member interface given by user is valid in the namespace. - if interface_name_is_valid(db, interface_name) is False: - ctx.fail("Interface name is invalid. Please enter a valid interface name!!") - - vlan_name = 'Vlan{}'.format(vid) - vlan = db.get_entry('VLAN', vlan_name) - interface_table = db.get_table('INTERFACE') - - if get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(db, interface_name) - if interface_name is None: - ctx.fail("'interface_name' is None!") - - if len(vlan) == 0: - ctx.fail("{} doesn't exist".format(vlan_name)) - if interface_is_mirror_dst_port(db, interface_name): - ctx.fail("{} is configured as mirror destination port".format(interface_name)) - - members = vlan.get('members', []) - if interface_name in members: - if get_interface_naming_mode() == "alias": - interface_name = interface_name_to_alias(db, interface_name) - if interface_name is None: - ctx.fail("'interface_name' is None!") - ctx.fail("{} is already a member of {}".format(interface_name, - vlan_name)) - else: - ctx.fail("{} is already a member of {}".format(interface_name, - vlan_name)) - for entry in interface_table: - if (interface_name == entry[0]): - ctx.fail("{} is a L3 interface!".format(interface_name)) - - members.append(interface_name) - vlan['members'] = members - db.set_entry('VLAN', vlan_name, vlan) - db.set_entry('VLAN_MEMBER', (vlan_name, interface_name), {'tagging_mode': "untagged" if untagged else "tagged" }) - - -@vlan_member.command('del') -@click.argument('vid', metavar='', required=True, type=int) -@click.argument('interface_name', metavar='', required=True) -@click.pass_context -def del_vlan_member(ctx, vid, interface_name): - """Delete VLAN member""" - log.log_info("'vlan member del {} {}' executing...".format(vid, interface_name)) - - db = ctx.obj['db'] - - # Check if the member interface given by user is valid in the namespace. - if interface_name_is_valid(db, interface_name) is False: - ctx.fail("Interface name is invalid. Please enter a valid interface name!!") - - vlan_name = 'Vlan{}'.format(vid) - vlan = db.get_entry('VLAN', vlan_name) - - if get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(db, interface_name) - if interface_name is None: - ctx.fail("'interface_name' is None!") - - if len(vlan) == 0: - ctx.fail("{} doesn't exist".format(vlan_name)) - members = vlan.get('members', []) - if interface_name not in members: - if get_interface_naming_mode() == "alias": - interface_name = interface_name_to_alias(db, interface_name) - if interface_name is None: - ctx.fail("'interface_name' is None!") - ctx.fail("{} is not a member of {}".format(interface_name, vlan_name)) - else: - ctx.fail("{} is not a member of {}".format(interface_name, vlan_name)) - members.remove(interface_name) - if len(members) == 0: - del vlan['members'] - else: - vlan['members'] = members - db.set_entry('VLAN', vlan_name, vlan) - db.set_entry('VLAN_MEMBER', (vlan_name, interface_name), None) - def mvrf_restart_services(): """Restart interfaces-config service and NTP service when mvrf is changed""" """ From e956e3856cabaafbe30a2ab4b64e5cab86dd616c Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Mon, 24 Aug 2020 14:47:15 -0700 Subject: [PATCH 26/29] Fixes needed to get in sync with the common library changes. Verified on both single-asic and multi-asic platforms. --- config/main.py | 52 +++++++++++++++++++++++++++++++------------------ sfputil/main.py | 4 +--- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/config/main.py b/config/main.py index b1accab2c8..c41f7d18e4 100755 --- a/config/main.py +++ b/config/main.py @@ -14,7 +14,8 @@ from minigraph import parse_device_desc_xml from portconfig import get_child_ports, get_port_config_file_name -from sonic_py_common import device_info, multi_asic, interface +from sonic_py_common import device_info, multi_asic +from sonic_py_common.interface import * from swsssdk import ConfigDBConnector, SonicV2Connector, SonicDBConfig from utilities_common.db import Db from utilities_common.intf_filter import parse_interface_in_filter @@ -393,17 +394,17 @@ def interface_name_to_alias(config_db, interface_name): def get_interface_table_name(interface_name): """Get table name by interface_name prefix """ - if interface_name.startswith(interface.front_panel_prefix()): + if interface_name.startswith(front_panel_prefix()): if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: return "VLAN_SUB_INTERFACE" return "INTERFACE" - elif interface_name.startswith(interface.portchannel_prefix()): + elif interface_name.startswith(portchannel_prefix()): if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: return "VLAN_SUB_INTERFACE" return "PORTCHANNEL_INTERFACE" - elif interface_name.startswith(interface.vlan_prefix()): + elif interface_name.startswith(vlan_prefix()): return "VLAN_INTERFACE" - elif interface_name.startswith(interface.loopback_prefix()): + elif interface_name.startswith(loopback_prefix()): return "LOOPBACK_INTERFACE" else: return "" @@ -436,17 +437,17 @@ def is_interface_bind_to_vrf(config_db, interface_name): def get_port_table_name(interface_name): """Get table name by port_name prefix """ - if interface_name.startswith(interface.front_panel_prefix()): + if interface_name.startswith(front_panel_prefix()): if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: return "VLAN_SUB_INTERFACE" return "PORT" - elif interface_name.startswith(interface.portchannel_prefix()): + elif interface_name.startswith(portchannel_prefix()): if VLAN_SUB_INTERFACE_SEPARATOR in interface_name: return "VLAN_SUB_INTERFACE" return "PORTCHANNEL" - elif interface_name.startswith(interface.vlan_prefix()): + elif interface_name.startswith(vlan_prefix()): return "VLAN_INTERFACE" - elif interface_name.startswith(interface.loopback_prefix()): + elif interface_name.startswith(loopback_prefix()): return "LOOPBACK_INTERFACE" else: return "" @@ -471,7 +472,7 @@ def get_port_namespace(port): config_db.connect() # If the interface naming mode is alias, search the tables for alias_name. - if get_interface_naming_mode() == "alias": + if clicommon.get_interface_naming_mode() == "alias": port_dict = config_db.get_table(table_name) if port_dict: for port_name in port_dict.keys(): @@ -2144,7 +2145,6 @@ def interface(ctx, namespace): config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=str(namespace)) config_db.connect() ctx.obj = {'config_db': config_db, 'namespace': str(namespace)} - # # 'startup' subcommand # @@ -2246,7 +2246,11 @@ def speed(ctx, interface_name, interface_speed, verbose): log.log_info("'interface speed {} {}' executing...".format(interface_name, interface_speed)) - command = "portconfig -p {} -s {} -n {}".format(interface_name, interface_speed, ctx.obj['namespace']) + if ctx.obj['namespace'] is DEFAULT_NAMESPACE: + command = "portconfig -p {} -s {}".format(interface_name, interface_speed) + else: + command = "portconfig -p {} -s {} -n {}".format(interface_name, interface_speed, ctx.obj['namespace']) + if verbose: command += " -vv" clicommon.run_command(command, display_cmd=verbose) @@ -2404,13 +2408,16 @@ def mtu(ctx, interface_name, interface_mtu, verbose): """Set interface mtu""" # 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!") - command = "portconfig -p {} -m {} -n {}".format(interface_name, interface_mtu, ctx.obj['namespace']) + if ctx.obj['namespace'] is DEFAULT_NAMESPACE: + command = "portconfig -p {} -m {}".format(interface_name, interface_mtu) + else: + command = "portconfig -p {} -m {} -n {}".format(interface_name, interface_mtu, ctx.obj['namespace']) + if verbose: command += " -vv" clicommon.run_command(command, display_cmd=verbose) @@ -2432,7 +2439,11 @@ def fec(ctx, interface_name, interface_fec, verbose): if interface_name is None: ctx.fail("'interface_name' is None!") - command = "portconfig -p {} -f {} -n {}".format(interface_name, interface_fec, ctx.obj['namespace']) + if ctx.obj['namespace'] is DEFAULT_NAMESPACE: + command = "portconfig -p {} -f {}".format(interface_name, interface_fec) + else: + command = "portconfig -p {} -f {} -n {}".format(interface_name, interface_fec, ctx.obj['namespace']) + if verbose: command += " -vv" clicommon.run_command(command, display_cmd=verbose) @@ -2549,7 +2560,7 @@ def remove(ctx, interface_name, ip_addr): command = "sudo ip netns exec {} ip neigh flush dev {} {}".format(ctx.obj['namespace'], interface_name, ip_addr) else: command = "ip neigh flush dev {} {}".format(interface_name, ip_addr) - run_command(command) + clicommon.run_command(command) except ValueError: ctx.fail("'ip_addr' is not valid.") @@ -2650,7 +2661,10 @@ def bind(ctx, interface_name, vrf_name): config_db.set_entry(table_name, interface_del, None) config_db.set_entry(table_name, interface_name, None) # When config_db del entry and then add entry with same key, the DEL will lost. - state_db = SonicV2Connector(use_unix_socket_path=True, namespace=ctx.obj['namespace']) + if ctx.obj['namespace'] is DEFAULT_NAMESPACE: + state_db = SonicV2Connector(use_unix_socket_path=True) + else: + state_db = SonicV2Connector(use_unix_socket_path=True, namespace=ctx.obj['namespace']) state_db.connect(state_db.STATE_DB, False) _hash = '{}{}'.format('INTERFACE_TABLE|', interface_name) while state_db.get(state_db.STATE_DB, _hash, "state") == "ok": @@ -3102,7 +3116,7 @@ def asymmetric(ctx, interface_name, status): # Get the config_db connector config_db = ctx.obj['config_db'] - if get_interface_naming_mode() == "alias": + 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!") @@ -3123,7 +3137,7 @@ def priority(ctx, interface_name, priority, status): # Get the config_db connector config_db = ctx.obj['config_db'] - if get_interface_naming_mode() == "alias": + 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!") diff --git a/sfputil/main.py b/sfputil/main.py index e44952d714..f86c5043f2 100644 --- a/sfputil/main.py +++ b/sfputil/main.py @@ -307,11 +307,9 @@ def cli(): try: if multi_asic.is_multi_asic(): # For multi ASIC platforms we pass DIR of port_config_file_path and the number of asics - (platform, hwsku) = device_info.get_platform_and_hwsku() + (platform_path, hwsku_path) = device_info.get_paths_to_platform_and_hwsku_dirs() # Load platform module from source - platform_path = "/".join([PLATFORM_ROOT_PATH, platform]) - hwsku_path = "/".join([platform_path, hwsku]) platform_sfputil.read_all_porttab_mappings(hwsku_path, multi_asic.get_num_asics()) else: # For single ASIC platforms we pass port_config_file_path and the asic_inst as 0 From 4f068faeda05abe0e83b08bc8d7f264196b90f08 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Mon, 24 Aug 2020 16:05:32 -0700 Subject: [PATCH 27/29] Fix the lgtm warning --- config/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/main.py b/config/main.py index c41f7d18e4..3fd230eb98 100755 --- a/config/main.py +++ b/config/main.py @@ -15,7 +15,7 @@ from minigraph import parse_device_desc_xml from portconfig import get_child_ports, get_port_config_file_name from sonic_py_common import device_info, multi_asic -from sonic_py_common.interface import * +from sonic_py_common.interface import front_panel_prefix, portchannel_prefix, vlan_prefix, loopback_prefix from swsssdk import ConfigDBConnector, SonicV2Connector, SonicDBConfig from utilities_common.db import Db from utilities_common.intf_filter import parse_interface_in_filter From 01139963ef71522ae4e057cdef41ed6e73e845d9 Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Mon, 24 Aug 2020 18:49:21 -0700 Subject: [PATCH 28/29] Update TODO comments for API's which we plan to move to sonic-py-common --- config/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/config/main.py b/config/main.py index 3fd230eb98..d90296ec23 100755 --- a/config/main.py +++ b/config/main.py @@ -433,6 +433,7 @@ def is_interface_bind_to_vrf(config_db, interface_name): return True return False +# TODO move to sonic-py-common package # Get the table name based on the interface type def get_port_table_name(interface_name): """Get table name by port_name prefix From 78162bf9d2e3ff4f874495571ab6fb57a186c2cc Mon Sep 17 00:00:00 2001 From: Judy Joseph Date: Tue, 25 Aug 2020 18:53:15 -0700 Subject: [PATCH 29/29] Removing adding line while merge --- config/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/config/main.py b/config/main.py index 5da7d10b2e..fb039d6c28 100755 --- a/config/main.py +++ b/config/main.py @@ -13,7 +13,6 @@ import time from minigraph import parse_device_desc_xml - from portconfig import get_child_ports from sonic_py_common import device_info, multi_asic from sonic_py_common.interface import front_panel_prefix, portchannel_prefix, vlan_prefix, loopback_prefix