def __init__(self): self.yang_acl = None self.requested_session = None self.mirror_stage = None self.current_table = None self.tables_db_info = {} self.rules_db_info = {} self.rules_info = {} if multi_asic.is_multi_asic(): # Load global db config SonicDBConfig.load_sonic_global_db_config() else: SonicDBConfig.initialize() self.sessions_db_info = {} self.configdb = ConfigDBConnector() self.configdb.connect() self.statedb = SonicV2Connector(host="127.0.0.1") self.statedb.connect(self.statedb.STATE_DB) # For multi-npu architecture we will have both global and per front asic namespace. # Global namespace will be used for Control plane ACL which are via IPTables. # Per ASIC namespace will be used for Data and Everflow ACL's. # Global Configdb will have all ACL information for both Ctrl and Data/Evereflow ACL's # and will be used as souurce of truth for ACL modification to config DB which will be done to both Global DB and # front asic namespace self.per_npu_configdb = {} # State DB are used for to get mirror Session monitor port. # For multi-npu platforms each asic namespace can have different monitor port # dependinding on which route to session destination ip. So for multi-npu # platforms we get state db for all front asic namespace in addition to self.per_npu_statedb = {} # Getting all front asic namespace and correspding config and state DB connector namespaces = device_info.get_all_namespaces() for front_asic_namespaces in namespaces['front_ns']: self.per_npu_configdb[front_asic_namespaces] = ConfigDBConnector( use_unix_socket_path=True, namespace=front_asic_namespaces) self.per_npu_configdb[front_asic_namespaces].connect() self.per_npu_statedb[front_asic_namespaces] = SonicV2Connector( use_unix_socket_path=True, namespace=front_asic_namespaces) self.per_npu_statedb[front_asic_namespaces].connect( self.per_npu_statedb[front_asic_namespaces].STATE_DB) self.read_tables_info() self.read_rules_info() self.read_sessions_info() self.read_policers_info()
def __init__(self, namespace, socket=None): """ Version string format: version_<major>_<minor>_<build> major: starting from 1, sequentially incrementing in master branch. minor: in github branches, minor version stays in 0. This minor version creates space for private branches derived from github public branches. These private branches shall use none-zero values. build: sequentially increase within a minor version domain. """ self.CURRENT_VERSION = 'version_2_0_5' self.TABLE_NAME = 'VERSIONS' self.TABLE_KEY = 'DATABASE' self.TABLE_FIELD = 'VERSION' db_kwargs = {} if socket: db_kwargs['unix_socket_path'] = socket if namespace is None: self.configDB = ConfigDBConnector(**db_kwargs) else: self.configDB = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace, **db_kwargs) self.configDB.db_connect('CONFIG_DB') if namespace is None: self.appDB = ConfigDBConnector(**db_kwargs) else: self.appDB = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace, **db_kwargs) self.appDB.db_connect('APPL_DB') self.stateDB = SonicV2Connector(host='127.0.0.1') if self.stateDB is not None: self.stateDB.connect(self.stateDB.STATE_DB) version_info = device_info.get_sonic_version_info() asic_type = version_info.get('asic_type') self.asic_type = asic_type self.hwsku = device_info.get_hwsku() if asic_type == "mellanox": from mellanox_buffer_migrator import MellanoxBufferMigrator self.mellanox_buffer_migrator = MellanoxBufferMigrator( self.configDB, self.appDB, self.stateDB)
def vlanvnimap(count): """Show VLAN VNI Mapping Information""" header = ['VLAN', 'VNI'] body = [] config_db = ConfigDBConnector() config_db.connect() if count is not None: vxlan_keys = config_db.keys('CONFIG_DB', "VXLAN_TUNNEL_MAP|*") if not vxlan_keys: vxlan_count = 0 else: vxlan_count = len(vxlan_keys) output = 'Total count : ' output += ('%s \n' % (str(vxlan_count))) click.echo(output) else: vxlan_table = config_db.get_table('VXLAN_TUNNEL_MAP') vxlan_keys = vxlan_table.keys() num = 0 if vxlan_keys is not None: for key in natsorted(vxlan_keys): body.append( [vxlan_table[key]['vlan'], vxlan_table[key]['vni']]) num += 1 click.echo(tabulate(body, header, tablefmt="grid")) output = 'Total count : ' output += ('%s \n' % (str(num))) click.echo(output)
def test_multidb_ConfigDBConnector(): test_dir = os.path.dirname(os.path.abspath(__file__)) global_db_config = os.path.join(test_dir, 'redis_multi_db_ut_config', 'database_global.json') SonicDBConfig.load_sonic_global_db_config(global_db_config) config_db = ConfigDBConnector(use_unix_socket_path=True, namespace='asic1') assert config_db.namespace == 'asic1'
def disable(): """ Disable queue counter query """ configdb = ConfigDBConnector() configdb.connect() queue_info = {} queue_info['FLEX_COUNTER_STATUS'] = 'disable' configdb.mod_entry("FLEX_COUNTER_TABLE", "QUEUE", queue_info)
def disable(): """ Disable port counter query """ configdb = ConfigDBConnector() configdb.connect() port_info = {} port_info['FLEX_COUNTER_STATUS'] = DISABLE configdb.mod_entry("FLEX_COUNTER_TABLE", PORT_BUFFER_DROP, port_info)
def tacacs(): """Show TACACS+ configuration""" config_db = ConfigDBConnector() config_db.connect() output = '' data = config_db.get_table('TACPLUS') tacplus = { 'global': { 'auth_type': 'pap (default)', 'timeout': '5 (default)', 'passkey': '<EMPTY_STRING> (default)' } } if 'global' in data: tacplus['global'].update(data['global']) for key in tacplus['global']: output += ('TACPLUS global %s %s\n' % (str(key), str(tacplus['global'][key]))) data = config_db.get_table('TACPLUS_SERVER') if data != {}: for row in data: entry = data[row] output += ('\nTACPLUS_SERVER address %s\n' % row) for key in entry: output += (' %s %s\n' % (key, str(entry[key]))) click.echo(output)
def get_platform_info(config_db=None): """ This function is used to get the HW info helper function """ from .multi_asic import get_num_asics hw_info_dict = {} version_info = get_sonic_version_info() hw_info_dict['platform'] = get_platform() hw_info_dict['hwsku'] = get_hwsku() if version_info: hw_info_dict['asic_type'] = version_info.get('asic_type') hw_info_dict['asic_count'] = get_num_asics() try: # TODO: enforce caller to provide config_db explicitly and remove its default value if not config_db: config_db = ConfigDBConnector() config_db.connect() metadata = config_db.get_table('DEVICE_METADATA')["localhost"] switch_type = metadata.get('switch_type') if switch_type: hw_info_dict['switch_type'] = switch_type except Exception: pass return hw_info_dict
def remove_interface(ctx, interface_name): """Remove interface related NAT configuration""" config_db = ConfigDBConnector() config_db.connect() if nat_interface_name_is_valid(interface_name) is False: ctx.fail( "Interface name is invalid. Please enter a valid interface name!!" ) if interface_name.startswith("Ethernet"): interface_table_type = "INTERFACE" elif interface_name.startswith("PortChannel"): interface_table_type = "PORTCHANNEL_INTERFACE" elif interface_name.startswith("Vlan"): interface_table_type = "VLAN_INTERFACE" elif interface_name.startswith("Loopback"): interface_table_type = "LOOPBACK_INTERFACE" interface_table_dict = config_db.get_table(interface_table_type) if not interface_table_dict or interface_name not in interface_table_dict: ctx.fail( "Interface table is not present. Ignoring the nat zone configuration" ) config_db.mod_entry(interface_table_type, interface_name, {"nat_zone": "0"})
def add_interface(ctx, interface_name, nat_zone): """Add interface related nat configuration""" config_db = ConfigDBConnector() config_db.connect() if nat_interface_name_is_valid(interface_name) is False: ctx.fail( "Interface name is invalid. Please enter a valid interface name!!" ) if interface_name.startswith("Ethernet"): interface_table_type = "INTERFACE" elif interface_name.startswith("PortChannel"): interface_table_type = "PORTCHANNEL_INTERFACE" elif interface_name.startswith("Vlan"): interface_table_type = "VLAN_INTERFACE" elif interface_name.startswith("Loopback"): interface_table_type = "LOOPBACK_INTERFACE" interface_table_dict = config_db.get_table(interface_table_type) if not interface_table_dict or interface_name not in interface_table_dict: ctx.fail( "Interface table is not present. Please configure ip-address on {} and apply the nat zone !!" .format(interface_name)) config_db.mod_entry(interface_table_type, interface_name, {"nat_zone": nat_zone})
def isOverlappingWithAnyDynamicEntry(ipAddress): """Check if the given ipAddress is overlapping with any dynamic pool entry""" config_db = ConfigDBConnector() config_db.connect() ip = int(ipaddress.IPv4Address(ipAddress)) nat_pool_dict = config_db.get_table('NAT_POOL') if not nat_pool_dict: return False for values in nat_pool_dict.values(): global_ip = values["nat_ip"] ipAddr = global_ip.split('-') if (len(ipAddr) == 1): startIp = int(ipaddress.IPv4Address(ipAddr[0])) endIp = int(ipaddress.IPv4Address(ipAddr[0])) else: startIp = int(ipaddress.IPv4Address(ipAddr[0])) endIp = int(ipaddress.IPv4Address(ipAddr[1])) if ((ip >= startIp) and (ip <= endIp)): return True return False
def remove_pool(ctx, pool_name): """Remove Pool for Dynamic NAT-related configutation""" entryFound = False table = "NAT_POOL" key = pool_name if len(pool_name) > 32: ctx.fail( "Invalid pool name. Maximum allowed pool name is 32 characters !!") config_db = ConfigDBConnector() config_db.connect() data = config_db.get_entry(table, key) if not data: click.echo("Trying to delete pool, which is not present.") entryFound = True binding_dict = config_db.get_table('NAT_BINDINGS') if binding_dict and entryFound == False: for binding_name, binding_values in binding_dict.items(): if binding_values['nat_pool'] == pool_name: click.echo( "Pool is not removed, as it is mapped to Binding {}, remove the pool binding first !!" .format(binding_name)) entryFound = True break if entryFound == False: config_db.set_entry(table, key, None)
def profile(profile): # Check if profile can be changed completed_process = subprocess.run( ['docker', 'exec', '-it', 'syncd', 'test', '-h', '/opt/bfn/install']) if completed_process.returncode != 0: click.echo('Cannot change profile: default one is in use') raise click.Abort() # Get chip family hwsku_dir = device_info.get_path_to_hwsku_dir() with open(hwsku_dir + '/switch-tna-sai.conf') as file: chip_family = json.load(file)['chip_list'][0]['chip_family'].lower() # Check if profile is supported if chip_family == 'tofino' and profile[0] == 'y' or \ chip_family == 'tofino2' and profile[0] == 'x': click.echo('Specified profile is unsupported on the system') raise click.Abort() # Check if profile exists completed_process = subprocess.run([ 'docker', 'exec', '-it', 'syncd', 'test', '-d', '/opt/bfn/install_' + profile + '_profile' ]) if completed_process.returncode != 0: click.echo('No profile with the provided name found') raise click.Abort() # Update configuration config_db = ConfigDBConnector() config_db.connect() config_db.mod_entry('DEVICE_METADATA', 'localhost', {'p4_profile': profile + '_profile'}) subprocess.run(['systemctl', 'restart', 'swss'], check=True)
def show(): """ Show the counter configuration """ configdb = ConfigDBConnector() configdb.connect() queue_info = configdb.get_entry('FLEX_COUNTER_TABLE', 'QUEUE') port_info = configdb.get_entry('FLEX_COUNTER_TABLE', 'PORT') port_drop_info = configdb.get_entry('FLEX_COUNTER_TABLE', PORT_BUFFER_DROP) rif_info = configdb.get_entry('FLEX_COUNTER_TABLE', 'RIF') queue_wm_info = configdb.get_entry('FLEX_COUNTER_TABLE', 'QUEUE_WATERMARK') pg_wm_info = configdb.get_entry('FLEX_COUNTER_TABLE', 'PG_WATERMARK') pg_drop_info = configdb.get_entry('FLEX_COUNTER_TABLE', PG_DROP) buffer_pool_wm_info = configdb.get_entry('FLEX_COUNTER_TABLE', BUFFER_POOL_WATERMARK) header = ("Type", "Interval (in ms)", "Status") data = [] if queue_info: data.append(["QUEUE_STAT", queue_info.get("POLL_INTERVAL", DEFLT_10_SEC), queue_info.get("FLEX_COUNTER_STATUS", DISABLE)]) if port_info: data.append(["PORT_STAT", port_info.get("POLL_INTERVAL", DEFLT_1_SEC), port_info.get("FLEX_COUNTER_STATUS", DISABLE)]) if port_drop_info: data.append([PORT_BUFFER_DROP, port_drop_info.get("POLL_INTERVAL", DEFLT_60_SEC), port_drop_info.get("FLEX_COUNTER_STATUS", DISABLE)]) if rif_info: data.append(["RIF_STAT", rif_info.get("POLL_INTERVAL", DEFLT_1_SEC), rif_info.get("FLEX_COUNTER_STATUS", DISABLE)]) if queue_wm_info: data.append(["QUEUE_WATERMARK_STAT", queue_wm_info.get("POLL_INTERVAL", DEFLT_10_SEC), queue_wm_info.get("FLEX_COUNTER_STATUS", DISABLE)]) if pg_wm_info: data.append(["PG_WATERMARK_STAT", pg_wm_info.get("POLL_INTERVAL", DEFLT_10_SEC), pg_wm_info.get("FLEX_COUNTER_STATUS", DISABLE)]) if pg_drop_info: data.append(['PG_DROP_STAT', pg_drop_info.get("POLL_INTERVAL", DEFLT_10_SEC), pg_drop_info.get("FLEX_COUNTER_STATUS", DISABLE)]) if buffer_pool_wm_info: data.append(["BUFFER_POOL_WATERMARK_STAT", buffer_pool_wm_info.get("POLL_INTERVAL", DEFLT_10_SEC), buffer_pool_wm_info.get("FLEX_COUNTER_STATUS", DISABLE)]) click.echo(tabulate(data, headers=header, tablefmt="simple", missingval=""))
def tunnel(): """Show vxlan tunnel information""" config_db = ConfigDBConnector() config_db.connect() header = [ 'vxlan tunnel name', 'source ip', 'destination ip', 'tunnel map name', 'tunnel map mapping(vni -> vlan)' ] # Fetching data from config_db for VXLAN TUNNEL vxlan_data = config_db.get_table('VXLAN_TUNNEL') vxlan_keys = natsorted(list(vxlan_data.keys())) table = [] for k in vxlan_keys: r = [] r.append(k) r.append(vxlan_data[k].get('src_ip')) r.append(vxlan_data[k].get('dst_ip')) vxlan_map_keys = config_db.keys( config_db.CONFIG_DB, 'VXLAN_TUNNEL_MAP{}{}{}*'.format(config_db.KEY_SEPARATOR, k, config_db.KEY_SEPARATOR)) if vxlan_map_keys: vxlan_map_mapping = config_db.get_all(config_db.CONFIG_DB, vxlan_map_keys[0]) r.append(vxlan_map_keys[0].split(config_db.KEY_SEPARATOR, 2)[2]) r.append("{} -> {}".format(vxlan_map_mapping.get('vni'), vxlan_map_mapping.get('vlan'))) table.append(r) click.echo(tabulate(table, header))
def interval(poll_interval): """ Set tunnel counter query interval """ configdb = ConfigDBConnector() configdb.connect() tunnel_info = {} tunnel_info['POLL_INTERVAL'] = poll_interval configdb.mod_entry("FLEX_COUNTER_TABLE", "TUNNEL", tunnel_info)
def disable(): """ Disable tunnel counter query """ configdb = ConfigDBConnector() configdb.connect() tunnel_info = {} tunnel_info['FLEX_COUNTER_STATUS'] = DISABLE configdb.mod_entry("FLEX_COUNTER_TABLE", "TUNNEL", tunnel_info)
def udp_timeout(ctx): """Reset NAT UDP timeout configuration to default value (300 seconds)""" config_db = ConfigDBConnector() config_db.connect() seconds = 300 config_db.mod_entry("NAT_GLOBAL", "Values", {"nat_udp_timeout": seconds})
def get_all_namespaces(config_db=None): """ In case of Multi-Asic platform, Each ASIC will have a linux network namespace created. So we loop through the databases in different namespaces and depending on the sub_role decide whether this is a front end ASIC/namespace or a back end one. """ front_ns = [] back_ns = [] num_npus = get_num_npus() if is_multi_npu(): for npu in range(num_npus): namespace = "{}{}".format(NPU_NAME_PREFIX, npu) # TODO: enforce caller to provide config_db explicitly and remove its default value if not config_db: config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) config_db.connect() metadata = config_db.get_table('DEVICE_METADATA') if metadata['localhost']['sub_role'] == FRONTEND_ASIC_SUB_ROLE: front_ns.append(namespace) elif metadata['localhost']['sub_role'] == BACKEND_ASIC_SUB_ROLE: back_ns.append(namespace) return {'front_ns': front_ns, 'back_ns': back_ns}
def getTwiceNatIdCountWithDynamicBinding(twice_nat_id, count, dynamic_key): """Get the twice nat id count with dynamic binding""" config_db = ConfigDBConnector() config_db.connect() nat_binding_dict = config_db.get_table('NAT_BINDINGS') twice_id_count = count if not nat_binding_dict: return twice_id_count for key, values in nat_binding_dict.items(): nat_pool_data = config_db.get_entry('NAT_POOL', values["nat_pool"]) twice_id = 0 if dynamic_key is not None: if dynamic_key == key: continue if not nat_pool_data: continue if "twice_nat_id" in values: if values["twice_nat_id"] == "NULL": continue else: twice_id = int(values["twice_nat_id"]) else: continue if twice_id == twice_nat_id: twice_id_count += 1 return twice_id_count
def connect_config_db(): """ Connects to config_db """ config_db = ConfigDBConnector() config_db.connect() return config_db
def remove_basic(ctx, global_ip, local_ip): """Remove Static NAT-related configutation""" # Verify the ip address format if is_valid_ipv4_address(local_ip) is False: ctx.fail( "Given local ip address {} is invalid. Please enter a valid local ip address !!" .format(local_ip)) if is_valid_ipv4_address(global_ip) is False: ctx.fail( "Given global ip address {} is invalid. Please enter a valid global ip address !!" .format(global_ip)) config_db = ConfigDBConnector() config_db.connect() entryFound = False table = 'STATIC_NAT' key = global_ip dataKey = 'local_ip' data = config_db.get_entry(table, key) if data: if data[dataKey] == local_ip: config_db.set_entry(table, key, None) entryFound = True if entryFound is False: click.echo("Trying to delete static nat entry, which is not present.")
def alias(vnet_alias): """Show vnet alias to name information""" config_db = ConfigDBConnector() config_db.connect() header = ['Alias', 'Name'] # Fetching data from config_db for VNET vnet_data = config_db.get_table('VNET') vnet_keys = natsorted(list(vnet_data.keys())) def tablelize(vnet_keys, vnet_data, vnet_alias): table = [] for k in vnet_keys: r = [] if vnet_alias is not None: if vnet_data[k].get('guid') == vnet_alias: r.append(vnet_data[k].get('guid')) r.append(k) table.append(r) return table else: continue r.append(vnet_data[k].get('guid')) r.append(k) table.append(r) return table click.echo(tabulate(tablelize(vnet_keys, vnet_data, vnet_alias), header))
def remove_udp(ctx, global_ip, global_port, local_ip, local_port): """Remove Static UDP Protocol NAPT-related configutation""" # Verify the ip address format if is_valid_ipv4_address(local_ip) is False: ctx.fail( "Given local ip address {} is invalid. Please enter a valid local ip address !!" .format(local_ip)) if is_valid_ipv4_address(global_ip) is False: ctx.fail( "Given global ip address {} is invalid. Please enter a valid global ip address !!" .format(global_ip)) config_db = ConfigDBConnector() config_db.connect() entryFound = False table = "STATIC_NAPT" key = "{}|UDP|{}".format(global_ip, global_port) dataKey1 = 'local_ip' dataKey2 = 'local_port' data = config_db.get_entry(table, key) if data: if data[dataKey1] == local_ip and data[dataKey2] == str(local_port): config_db.set_entry(table, key, None) entryFound = True if entryFound is False: click.echo("Trying to delete static napt entry, which is not present.")
def disable(): """ Disable rif counter query """ configdb = ConfigDBConnector() configdb.connect() rif_info = {} rif_info['FLEX_COUNTER_STATUS'] = 'disable' configdb.mod_entry("FLEX_COUNTER_TABLE", "RIF", rif_info)
def __init__(self): self.cfgdb_clients = {} self.db_clients = {} self.cfgdb = ConfigDBConnector() self.cfgdb.connect() self.cfgdb_pipe = ConfigDBPipeConnector() self.cfgdb_pipe.connect() self.db = SonicV2Connector(host="127.0.0.1") # Skip connecting to chassis databases in line cards self.db_list = list(self.db.get_db_list()) if not device_info.is_supervisor(): try: self.db_list.remove('CHASSIS_APP_DB') self.db_list.remove('CHASSIS_STATE_DB') except Exception: pass for db_id in self.db_list: self.db.connect(db_id) self.cfgdb_clients[constants.DEFAULT_NAMESPACE] = self.cfgdb self.db_clients[constants.DEFAULT_NAMESPACE] = self.db if multi_asic.is_multi_asic(): self.ns_list = multi_asic_ns_choices() for ns in self.ns_list: self.cfgdb_clients[ns] = ( multi_asic.connect_config_db_for_ns(ns)) self.db_clients[ns] = multi_asic.connect_to_all_dbs_for_ns(ns)
def disable(): """ Disable port counter query """ configdb = ConfigDBConnector() configdb.connect() port_info = {} port_info['FLEX_COUNTER_STATUS'] = 'disable' configdb.mod_entry("FLEX_COUNTER_TABLE", "PORT", port_info)
def add(address, timeout, key, auth_type, port, pri, use_mgmt_vrf): """Specify a TACACS+ server""" if not clicommon.is_ipaddress(address): click.echo('Invalid ip address') return config_db = ConfigDBConnector() config_db.connect() old_data = config_db.get_entry('TACPLUS_SERVER', address) if old_data != {}: click.echo('server %s already exists' % address) else: data = { 'tcp_port': str(port), 'priority': pri } if auth_type is not None: data['auth_type'] = auth_type if timeout is not None: data['timeout'] = str(timeout) if key is not None: data['passkey'] = key if use_mgmt_vrf : data['vrf'] = "mgmt" config_db.set_entry('TACPLUS_SERVER', address, data)
def test_ConfigDBConnect(): config_db = ConfigDBConnector() config_db.db_connect('CONFIG_DB') client = config_db.get_redis_client(config_db.CONFIG_DB) client.flushdb() allconfig = config_db.get_config() assert len(allconfig) == 0
def showPfcPrio(interface): """ PFC handler to display PFC enabled priority information. """ header = ('Interface', 'Lossless priorities') table = [] configdb = ConfigDBConnector() configdb.connect() """Get all the interfaces with QoS map information""" intfs = configdb.get_keys('PORT_QOS_MAP') """The user specifies an interface but we cannot find it""" if interface and interface not in intfs: click.echo('Cannot find interface {0}'.format(interface)) return if interface: intfs = [interface] for intf in intfs: entry = configdb.get_entry('PORT_QOS_MAP', intf) table.append([intf, entry.get('pfc_enable', 'N/A')]) sorted_table = natsorted(table) click.echo() click.echo(tabulate(sorted_table, headers=header, tablefmt="simple", missingval="")) click.echo()