def tablelize(keys, data): table = [] for k in natsorted(keys): members = set(data[k].get('members', [])) for (vlan, interface_name) in member_data: if vlan == k: members.add(interface_name) for m in members: r = [] r.append(k) r.append(data[k]['vlanid']) if clicommon.get_interface_naming_mode() == "alias": alias = clicommon.InterfaceAliasConverter( db).name_to_alias(m) r.append(alias) else: r.append(m) entry = db.cfgdb.get_entry('VLAN_MEMBER', (k, m)) mode = entry.get('tagging_mode') if mode is None: r.append('?') else: r.append(mode) table.append(r) return table
def del_vlan_member(db, vid, port): """Delete VLAN member""" ctx = click.get_current_context() log.log_info("'vlan member del {} {}' executing...".format(vid, port)) if not clicommon.is_vlanid_in_range(vid): ctx.fail("Invalid VLAN ID {} (1-4094)".format(vid)) vlan = 'Vlan{}'.format(vid) if clicommon.check_if_vlanid_exist(db.cfgdb, vlan) == False: ctx.fail("{} does not exist".format(vlan)) if clicommon.get_interface_naming_mode() == "alias": alias = port iface_alias_converter = clicommon.InterfaceAliasConverter(db) port = iface_alias_converter.alias_to_name(alias) if port is None: ctx.fail("cannot find port name for alias {}".format(alias)) if not clicommon.is_port_vlan_member(db.cfgdb, port, vlan): ctx.fail("{} is not a member of {}".format(port, vlan)) db.cfgdb.set_entry('VLAN_MEMBER', (vlan, port), None)
def expected(db, interfacename): """Show expected neighbor information by interfaces""" neighbor_dict = db.cfgdb.get_table("DEVICE_NEIGHBOR") if neighbor_dict is None: click.echo("DEVICE_NEIGHBOR information is not present.") return neighbor_metadata_dict = db.cfgdb.get_table("DEVICE_NEIGHBOR_METADATA") if neighbor_metadata_dict is None: click.echo("DEVICE_NEIGHBOR_METADATA information is not present.") return #Swap Key and Value from interface: name to name: interface device2interface_dict = {} for port in natsorted(neighbor_dict.keys()): temp_port = port if clicommon.get_interface_naming_mode() == "alias": port = clicommon.InterfaceAliasConverter().name_to_alias(port) neighbor_dict[port] = neighbor_dict.pop(temp_port) device2interface_dict[neighbor_dict[port]['name']] = { 'localPort': port, 'neighborPort': neighbor_dict[port]['port'] } header = [ 'LocalPort', 'Neighbor', 'NeighborPort', 'NeighborLoopback', 'NeighborMgmt', 'NeighborType' ] body = [] if interfacename: try: device = neighbor_dict[interfacename]['name'] body.append([ interfacename, device, neighbor_dict[interfacename]['port'], neighbor_metadata_dict[device]['lo_addr'], neighbor_metadata_dict[device]['mgmt_addr'], neighbor_metadata_dict[device]['type'] ]) except KeyError: click.echo( "No neighbor information available for interface {}".format( interfacename)) return else: for port in natsorted(neighbor_dict.keys()): try: device = neighbor_dict[port]['name'] body.append([ port, device, neighbor_dict[port]['port'], neighbor_metadata_dict[device]['lo_addr'], neighbor_metadata_dict[device]['mgmt_addr'], neighbor_metadata_dict[device]['type'] ]) except KeyError: pass click.echo(tabulate(body, header))
def try_convert_interfacename_from_alias(ctx, interfacename): """try to convert interface name from alias""" if clicommon.get_interface_naming_mode() == "alias": alias = interfacename interfacename = clicommon.InterfaceAliasConverter().alias_to_name(alias) # TODO: ideally alias_to_name should return None when it cannot find # the port name for the alias if interfacename == alias: ctx.fail("cannot find interface name for alias {}".format(alias)) return interfacename
def add_vlan_member(db, vid, port, untagged): """Add VLAN member""" ctx = click.get_current_context() log.log_info("'vlan member add {} {}' executing...".format(vid, port)) if not clicommon.is_vlanid_in_range(vid): ctx.fail("Invalid VLAN ID {} (1-4094)".format(vid)) vlan = 'Vlan{}'.format(vid) if clicommon.check_if_vlanid_exist(db.cfgdb, vlan) == False: ctx.fail("{} does not exist".format(vlan)) if clicommon.get_interface_naming_mode() == "alias": alias = port iface_alias_converter = clicommon.InterfaceAliasConverter(db) port = iface_alias_converter.alias_to_name(alias) if port is None: ctx.fail("cannot find port name for alias {}".format(alias)) if clicommon.is_port_mirror_dst_port(db.cfgdb, port): ctx.fail("{} is configured as mirror destination port".format(port)) if clicommon.is_port_vlan_member(db.cfgdb, port, vlan): ctx.fail("{} is already a member of {}".format(port, vlan)) if clicommon.is_valid_port(db.cfgdb, port): is_port = True elif clicommon.is_valid_portchannel(db.cfgdb, port): is_port = False else: ctx.fail("{} does not exist".format(port)) if (is_port and clicommon.is_port_router_interface(db.cfgdb, port)) or \ (not is_port and clicommon.is_pc_router_interface(db.cfgdb, port)): ctx.fail("{} is a router interface!".format(port)) portchannel_member_table = db.cfgdb.get_table('PORTCHANNEL_MEMBER') if (is_port and clicommon.interface_is_in_portchannel( portchannel_member_table, port)): ctx.fail("{} is part of portchannel!".format(port)) if (clicommon.interface_is_untagged_member(db.cfgdb, port) and untagged): ctx.fail("{} is already untagged member!".format(port)) db.cfgdb.set_entry('VLAN_MEMBER', (vlan, port), {'tagging_mode': "untagged" if untagged else "tagged"})
def get_teamshow_result(self): """ Get teamshow results by parsing the output of teamdctl and combining port channel status. """ for team in self.teams: info = {} team_id = self.get_team_id(team) if team_id not in self.teamsraw: info['protocol'] = 'N/A' self.summary[team_id] = info self.summary[team_id]['ports'] = '' continue state = self.teamsraw[team_id] info['protocol'] = "LACP" info['protocol'] += "(A)" if state['runner.active'] == "true" else '(I)' portchannel_status = self.get_portchannel_status(team) if portchannel_status is None: info['protocol'] += '(N/A)' elif portchannel_status.lower() == 'up': info['protocol'] += '(Up)' elif portchannel_status.lower() == 'down': info['protocol'] += '(Dw)' else: info['protocol'] += '(N/A)' info['ports'] = "" member_keys = self.db.keys(self.db.STATE_DB, PORT_CHANNEL_MEMBER_STATE_TABLE_PREFIX+team+'|*') if member_keys is None: info['ports'] = 'N/A' else: ports = [key[len(PORT_CHANNEL_MEMBER_STATE_TABLE_PREFIX+team+'|'):] for key in member_keys] for port in ports: status = self.get_portchannel_member_status(team, port) pstate = self.db.get_all(self.db.STATE_DB, PORT_CHANNEL_MEMBER_STATE_TABLE_PREFIX+team+'|'+port) selected = True if pstate['runner.aggregator.selected'] == "true" else False if clicommon.get_interface_naming_mode() == "alias": alias = clicommon.InterfaceAliasConverter(self.db2).name_to_alias(port) info["ports"] += alias + "(" else: info["ports"] += port + "(" info["ports"] += "S" if selected else "D" if status is None or (status == "enabled" and not selected) or (status == "disabled" and selected): info["ports"] += "*" info["ports"] += ") " self.summary[team_id] = info
def config(db): data = db.cfgdb.get_table('VLAN') keys = list(data.keys()) member_data = db.cfgdb.get_table('VLAN_MEMBER') interface_naming_mode = clicommon.get_interface_naming_mode() iface_alias_converter = clicommon.InterfaceAliasConverter(db) def get_iface_name_for_display(member): name_for_display = member if interface_naming_mode == "alias" and member: name_for_display = iface_alias_converter.name_to_alias(member) return name_for_display def get_tagging_mode(vlan, member): if not member: return '' tagging_mode = db.cfgdb.get_entry('VLAN_MEMBER', (vlan, member)).get('tagging_mode') return '?' if tagging_mode is None else tagging_mode def tablelize(keys, data): table = [] for k in natsorted(keys): members = set([(vlan, member) for vlan, member in member_data if vlan == k] + [(k, member) for member in set(data[k].get('members', []))]) # vlan with no members if not members: members = [(k, '')] for vlan, member in natsorted(members): r = [ vlan, data[vlan]['vlanid'], get_iface_name_for_display(member), get_tagging_mode(vlan, member) ] table.append(r) return table header = ['Name', 'VID', 'Member', 'Mode'] click.echo(tabulate(tablelize(keys, data), header))
def del_port(db, port): """ Delete MACsec port """ ctx = click.get_current_context() if clicommon.get_interface_naming_mode() == "alias": alias = port iface_alias_converter = clicommon.InterfaceAliasConverter(db) port = iface_alias_converter.alias_to_name(alias) if port is None: ctx.fail("cannot find port name for alias {}".format(alias)) port_entry = db.cfgdb.get_entry('PORT', port) if len(port_entry) == 0: ctx.fail("port {} doesn't exist".format(port)) del port_entry['macsec'] db.cfgdb.set_entry("PORT", port, port_entry)
def mpls(ctx, interfacename): """Show Interface MPLS status""" appl_db = SonicV2Connector() appl_db.connect(appl_db.APPL_DB) if interfacename is not None: interfacename = try_convert_interfacename_from_alias(ctx, interfacename) # Fetching data from appl_db for intfs keys = appl_db.keys(appl_db.APPL_DB, "INTF_TABLE:*") intfs_data = {} for key in keys if keys else []: tokens = key.split(":") # Skip INTF_TABLE entries with address information if len(tokens) != 2: continue if (interfacename is not None) and (interfacename != tokens[1]): continue mpls = appl_db.get(appl_db.APPL_DB, key, 'mpls') if mpls is None or mpls == '': intfs_data.update({tokens[1]: 'disable'}) else: intfs_data.update({tokens[1]: mpls}) header = ['Interface', 'MPLS State'] body = [] # Output name and alias for all interfaces for intf_name in natsorted(list(intfs_data.keys())): if clicommon.get_interface_naming_mode() == "alias": alias = clicommon.InterfaceAliasConverter().name_to_alias(intf_name) body.append([alias, intfs_data[intf_name]]) else: body.append([intf_name, intfs_data[intf_name]]) click.echo(tabulate(body, header))
def get_vlan_ports(ctx, vlan): cfg, db = ctx _, _, vlan_ports_data = cfg vlan_ports = [] iface_alias_converter = clicommon.InterfaceAliasConverter(db) # Here natsorting is important in relation to another # column which prints port tagging mode. # If we sort both in the same way using same keys # we will result in right order in both columns. # This should be fixed by cli code autogeneration tool # and we won't need this specific approach with # VlanBrief.COLUMNS anymore. for key in natsorted(list(vlan_ports_data.keys())): ports_key, ports_value = key if vlan != ports_key: continue if clicommon.get_interface_naming_mode() == "alias": ports_value = iface_alias_converter.name_to_alias(ports_value) vlan_ports.append(ports_value) return '\n'.join(vlan_ports)
if return_cmd: output = proc.communicate()[0] return output output = proc.stdout.readline() if output == "" and proc.poll() is not None: break if output: click.echo(output.rstrip('\n')) rc = proc.poll() if rc != 0: sys.exit(rc) # Global class instance for SONiC interface name to alias conversion iface_alias_converter = clicommon.InterfaceAliasConverter() def connect_config_db(): """ Connects to config_db """ config_db = ConfigDBConnector() config_db.connect() return config_db CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help', '-?']) # # 'cli' group (root group)
def brief(db, verbose): """Show all bridge information""" header = [ 'VLAN ID', 'IP Address', 'Ports', 'Port Tagging', 'DHCP Helper Address', 'Proxy ARP' ] body = [] # Fetching data from config db for VLAN, VLAN_INTERFACE and VLAN_MEMBER vlan_dhcp_helper_data = db.cfgdb.get_table('VLAN') vlan_ip_data = db.cfgdb.get_table('VLAN_INTERFACE') vlan_ports_data = db.cfgdb.get_table('VLAN_MEMBER') # Defining dictionaries for DHCP Helper address, Interface Gateway IP, # VLAN ports and port tagging vlan_dhcp_helper_dict = {} vlan_ip_dict = {} vlan_ports_dict = {} vlan_tagging_dict = {} vlan_proxy_arp_dict = {} # Parsing DHCP Helpers info for key in natsorted(list(vlan_dhcp_helper_data.keys())): try: if vlan_dhcp_helper_data[key]['dhcp_servers']: vlan_dhcp_helper_dict[key.strip( 'Vlan')] = vlan_dhcp_helper_data[key]['dhcp_servers'] except KeyError: vlan_dhcp_helper_dict[key.strip('Vlan')] = " " # Parsing VLAN Gateway info for key in vlan_ip_data: if clicommon.is_ip_prefix_in_key(key): interface_key = key[0].strip("Vlan") interface_value = key[1] if interface_key in vlan_ip_dict: vlan_ip_dict[interface_key].append(interface_value) else: vlan_ip_dict[interface_key] = [interface_value] else: interface_key = key.strip("Vlan") if 'proxy_arp' in vlan_ip_data[key]: proxy_arp_status = vlan_ip_data[key]['proxy_arp'] else: proxy_arp_status = "disabled" vlan_proxy_arp_dict[interface_key] = proxy_arp_status iface_alias_converter = clicommon.InterfaceAliasConverter(db) # Parsing VLAN Ports info for key in natsorted(list(vlan_ports_data.keys())): ports_key = key[0].strip("Vlan") ports_value = key[1] ports_tagging = vlan_ports_data[key]['tagging_mode'] if ports_key in vlan_ports_dict: if clicommon.get_interface_naming_mode() == "alias": ports_value = iface_alias_converter.name_to_alias(ports_value) vlan_ports_dict[ports_key].append(ports_value) else: if clicommon.get_interface_naming_mode() == "alias": ports_value = iface_alias_converter.name_to_alias(ports_value) vlan_ports_dict[ports_key] = [ports_value] if ports_key in vlan_tagging_dict: vlan_tagging_dict[ports_key].append(ports_tagging) else: vlan_tagging_dict[ports_key] = [ports_tagging] # Printing the following dictionaries in tablular forms: # vlan_dhcp_helper_dict={}, vlan_ip_dict = {}, vlan_ports_dict = {} # vlan_tagging_dict = {} for key in natsorted(list(vlan_dhcp_helper_dict.keys())): if key not in vlan_ip_dict: ip_address = "" else: ip_address = ','.replace(',', '\n').join(vlan_ip_dict[key]) if key not in vlan_ports_dict: vlan_ports = "" else: vlan_ports = ','.replace(',', '\n').join((vlan_ports_dict[key])) if key not in vlan_dhcp_helper_dict: dhcp_helpers = "" else: dhcp_helpers = ','.replace(',', '\n').join(vlan_dhcp_helper_dict[key]) if key not in vlan_tagging_dict: vlan_tagging = "" else: vlan_tagging = ','.replace(',', '\n').join( (vlan_tagging_dict[key])) vlan_proxy_arp = vlan_proxy_arp_dict.get(key, "disabled") body.append([ key, ip_address, vlan_ports, vlan_tagging, dhcp_helpers, vlan_proxy_arp ]) click.echo(tabulate(body, header, tablefmt="grid"))
def mpls(ctx, interfacename, namespace, display): """Show Interface MPLS status""" #Edge case: Force show frontend interfaces on single asic if not (multi_asic.is_multi_asic()): if (display == 'frontend' or display == 'all' or display is None): display = None else: print("Error: Invalid display option command for single asic") return display = "all" if interfacename else display masic = multi_asic_util.MultiAsic(display_option=display, namespace_option=namespace) ns_list = masic.get_ns_list_based_on_options() intfs_data = {} intf_found = False for ns in ns_list: appl_db = multi_asic.connect_to_all_dbs_for_ns(namespace=ns) if interfacename is not None: interfacename = try_convert_interfacename_from_alias( ctx, interfacename) # Fetching data from appl_db for intfs keys = appl_db.keys(appl_db.APPL_DB, "INTF_TABLE:*") for key in keys if keys else []: tokens = key.split(":") ifname = tokens[1] # Skip INTF_TABLE entries with address information if len(tokens) != 2: continue if (interfacename is not None): if (interfacename != ifname): continue intf_found = True if (display != "all"): if ("Loopback" in ifname): continue if ifname.startswith( "Ethernet") and multi_asic.is_port_internal( ifname, ns): continue if ifname.startswith( "PortChannel") and multi_asic.is_port_channel_internal( ifname, ns): continue mpls_intf = appl_db.get_all(appl_db.APPL_DB, key) if 'mpls' not in mpls_intf or mpls_intf['mpls'] == 'disable': intfs_data.update({ifname: 'disable'}) else: intfs_data.update({ifname: mpls_intf['mpls']}) # Check if interface is valid if (interfacename is not None and not intf_found): ctx.fail('interface {} doesn`t exist'.format(interfacename)) header = ['Interface', 'MPLS State'] body = [] # Output name and alias for all interfaces for intf_name in natsorted(list(intfs_data.keys())): if clicommon.get_interface_naming_mode() == "alias": alias = clicommon.InterfaceAliasConverter().name_to_alias( intf_name) body.append([alias, intfs_data[intf_name]]) else: body.append([intf_name, intfs_data[intf_name]]) click.echo(tabulate(body, header))