diff options
Diffstat (limited to 'tests/topotests/lib/common_config.py')
| -rw-r--r-- | tests/topotests/lib/common_config.py | 592 |
1 files changed, 407 insertions, 185 deletions
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 6a02e50127..81c7ba4d5c 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -22,20 +22,20 @@ from collections import OrderedDict from datetime import datetime, timedelta from time import sleep from copy import deepcopy -from subprocess import call -from subprocess import STDOUT as SUB_STDOUT -from subprocess import PIPE as SUB_PIPE -from subprocess import Popen from functools import wraps from re import search as re_search from tempfile import mkdtemp +import json +import logging import os import sys import traceback import socket +import subprocess import ipaddress import platform +import pytest try: # Imports from python2 @@ -235,14 +235,12 @@ def run_frr_cmd(rnode, cmd, isjson=False): if True: if isjson: - logger.debug(ret_data) - print_data = rnode.vtysh_cmd(cmd.rstrip("json"), isjson=False) + print_data = json.dumps(ret_data) else: print_data = ret_data - logger.info( - "Output for command [ %s] on router %s:\n%s", - cmd.rstrip("json"), + "Output for command [%s] on router %s:\n%s", + cmd, rnode.name, print_data, ) @@ -278,7 +276,8 @@ def apply_raw_config(tgen, input_dict): True or errormsg """ - result = True + rlist = [] + for router_name in input_dict.keys(): config_cmd = input_dict[router_name]["raw_config"] @@ -290,13 +289,14 @@ def apply_raw_config(tgen, input_dict): for cmd in config_cmd: cfg.write("{}\n".format(cmd)) - result = load_config_to_router(tgen, router_name) + rlist.append(router_name) - return result + # Load config on all routers + return load_config_to_routers(tgen, rlist) -def create_common_configuration( - tgen, router, data, config_type=None, build=False, load_config=True +def create_common_configurations( + tgen, config_dict, config_type=None, build=False, load_config=True ): """ API to create object of class FRRConfig and also create frr_json.conf @@ -305,8 +305,8 @@ def create_common_configuration( Parameters ---------- * `tgen`: tgen object - * `data`: Configuration data saved in a list. - * `router` : router id to be configured. + * `config_dict`: Configuration data saved in a dict of { router: config-list } + * `routers` : list of router id to be configured. * `config_type` : Syntactic information while writing configuration. Should be one of the value as mentioned in the config_map below. * `build` : Only for initial setup phase this is set as True @@ -316,8 +316,6 @@ def create_common_configuration( """ TMPDIR = os.path.join(LOGDIR, tgen.modname) - fname = "{}/{}/{}".format(TMPDIR, router, FRRCFG_FILE) - config_map = OrderedDict( { "general_config": "! FRR General Config\n", @@ -342,27 +340,55 @@ def create_common_configuration( else: mode = "w" - try: - frr_cfg_fd = open(fname, mode) - if config_type: - frr_cfg_fd.write(config_map[config_type]) - for line in data: - frr_cfg_fd.write("{} \n".format(str(line))) - frr_cfg_fd.write("\n") - - except IOError as err: - logger.error( - "Unable to open FRR Config File. error(%s): %s" % (err.errno, err.strerror) - ) - return False - finally: - frr_cfg_fd.close() + routers = config_dict.keys() + for router in routers: + fname = "{}/{}/{}".format(TMPDIR, router, FRRCFG_FILE) + try: + frr_cfg_fd = open(fname, mode) + if config_type: + frr_cfg_fd.write(config_map[config_type]) + for line in config_dict[router]: + frr_cfg_fd.write("{} \n".format(str(line))) + frr_cfg_fd.write("\n") + + except IOError as err: + logger.error( + "Unable to open FRR Config '%s': %s" % (fname, str(err)) + ) + return False + finally: + frr_cfg_fd.close() # If configuration applied from build, it will done at last + result = True if not build and load_config: - load_config_to_router(tgen, router) + result = load_config_to_routers(tgen, routers) - return True + return result + + +def create_common_configuration( + tgen, router, data, config_type=None, build=False, load_config=True +): + """ + API to create object of class FRRConfig and also create frr_json.conf + file. It will create interface and common configurations and save it to + frr_json.conf and load to router + Parameters + ---------- + * `tgen`: tgen object + * `data`: Configuration data saved in a list. + * `router` : router id to be configured. + * `config_type` : Syntactic information while writing configuration. Should + be one of the value as mentioned in the config_map below. + * `build` : Only for initial setup phase this is set as True + Returns + ------- + True or False + """ + return create_common_configurations( + tgen, {router: data}, config_type, build, load_config + ) def kill_router_daemons(tgen, router, daemons, save_config=True): @@ -470,110 +496,149 @@ def reset_config_on_routers(tgen, routerName=None): logger.debug("Entering API: reset_config_on_routers") + # Trim the router list if needed router_list = tgen.routers() - for rname in ROUTER_LIST: - if routerName and routerName != rname: - continue - - router = router_list[rname] - logger.info("Configuring router %s to initial test configuration", rname) - - cfg = router.run("vtysh -c 'show running'") - fname = "{}/{}/frr.sav".format(TMPDIR, rname) - dname = "{}/{}/delta.conf".format(TMPDIR, rname) - f = open(fname, "w") - for line in cfg.split("\n"): - line = line.strip() - - if ( - line == "Building configuration..." - or line == "Current configuration:" - or not line - ): - continue - f.write(line) - f.write("\n") - - f.close() - run_cfg_file = "{}/{}/frr.sav".format(TMPDIR, rname) - init_cfg_file = "{}/{}/frr_json_initial.conf".format(TMPDIR, rname) - command = "/usr/lib/frr/frr-reload.py --test --test-reset --input {} {} > {}".format( - run_cfg_file, init_cfg_file, dname + if routerName: + if ((routerName not in ROUTER_LIST) or (routerName not in router_list)): + logger.debug("Exiting API: reset_config_on_routers: no routers") + return True + router_list = { routerName: router_list[routerName] } + + delta_fmt = TMPDIR + "/{}/delta.conf" + init_cfg_fmt = TMPDIR + "/{}/frr_json_initial.conf" + run_cfg_fmt = TMPDIR + "/{}/frr.sav" + + # + # Get all running configs in parallel + # + procs = {} + for rname in router_list: + logger.info("Fetching running config for router %s", rname) + procs[rname] = router_list[rname].popen( + ["/usr/bin/env", "vtysh", "-c", "show running-config no-header"], + stdin=None, + stdout=open(run_cfg_fmt.format(rname), "w"), + stderr=subprocess.PIPE, ) - result = call(command, shell=True, stderr=SUB_STDOUT, stdout=SUB_PIPE) - - # Assert if command fail - if result > 0: - logger.error("Delta file creation failed. Command executed %s", command) - with open(run_cfg_file, "r") as fd: - logger.info( - "Running configuration saved in %s is:\n%s", run_cfg_file, fd.read() - ) - with open(init_cfg_file, "r") as fd: - logger.info( - "Test configuration saved in %s is:\n%s", init_cfg_file, fd.read() - ) - - err_cmd = ["/usr/bin/vtysh", "-m", "-f", run_cfg_file] - result = Popen(err_cmd, stdout=SUB_PIPE, stderr=SUB_PIPE) - output = result.communicate() - for out_data in output: - temp_data = out_data.decode("utf-8").lower() - for out_err in ERROR_LIST: - if out_err.lower() in temp_data: - logger.error( - "Found errors while validating data in" " %s", run_cfg_file - ) - raise InvalidCLIError(out_data) - raise InvalidCLIError("Unknown error in %s", output) - - delta = StringIO() - with open(dname, "r") as f: - delta.write(f.read()) - - output = router.vtysh_multicmd(delta.getvalue(), pretty_output=False) - - delta.close() - delta = StringIO() - cfg = router.run("vtysh -c 'show running'") - for line in cfg.split("\n"): - line = line.strip() - delta.write(line) - delta.write("\n") - - # Router current configuration to log file or console if - # "show_router_config" is defined in "pytest.ini" - if show_router_config: - logger.info("Configuration on router {} after reset:".format(rname)) - logger.info(delta.getvalue()) - delta.close() + for rname, p in procs.items(): + _, error = p.communicate() + if p.returncode: + logger.error("Get running config for %s failed %d: %s", rname, p.returncode, error) + raise InvalidCLIError("vtysh show running error on {}: {}".format(rname, error)) + + # + # Get all delta's in parallel + # + procs = {} + for rname in router_list: + logger.info("Generating delta for router %s to new configuration", rname) + procs[rname] = subprocess.Popen( + [ "/usr/lib/frr/frr-reload.py", + "--test-reset", + "--input", + run_cfg_fmt.format(rname), + "--test", + init_cfg_fmt.format(rname) ], + stdin=None, + stdout=open(delta_fmt.format(rname), "w"), + stderr=subprocess.PIPE, + ) + for rname, p in procs.items(): + _, error = p.communicate() + if p.returncode: + logger.error("Delta file creation for %s failed %d: %s", rname, p.returncode, error) + raise InvalidCLIError("frr-reload error for {}: {}".format(rname, error)) + + # + # Apply all the deltas in parallel + # + procs = {} + for rname in router_list: + logger.info("Applying delta config on router %s", rname) + + procs[rname] = router_list[rname].popen( + ["/usr/bin/env", "vtysh", "-f", delta_fmt.format(rname)], + stdin=None, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + for rname, p in procs.items(): + output, _ = p.communicate() + vtysh_command = "vtysh -f {}".format(delta_fmt.format(rname)) + if not p.returncode: + router_list[rname].logger.info( + '\nvtysh config apply => "{}"\nvtysh output <= "{}"'.format(vtysh_command, output) + ) + else: + router_list[rname].logger.warning( + '\nvtysh config apply failed => "{}"\nvtysh output <= "{}"'.format(vtysh_command, output) + ) + logger.error("Delta file apply for %s failed %d: %s", rname, p.returncode, output) + + # We really need to enable this failure; however, currently frr-reload.py + # producing invalid "no" commands as it just preprends "no", but some of the + # command forms lack matching values (e.g., final values). Until frr-reload + # is fixed to handle this (or all the CLI no forms are adjusted) we can't + # fail tests. + # raise InvalidCLIError("frr-reload error for {}: {}".format(rname, output)) + + # + # Optionally log all new running config if "show_router_config" is defined in + # "pytest.ini" + # + if show_router_config: + procs = {} + for rname in router_list: + logger.info("Fetching running config for router %s", rname) + procs[rname] = router_list[rname].popen( + ["/usr/bin/env", "vtysh", "-c", "show running-config no-header"], + stdin=None, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + for rname, p in procs.items(): + output, _ = p.communicate() + if p.returncode: + logger.warning("Get running config for %s failed %d: %s", rname, p.returncode, output) + else: + logger.info("Configuration on router %s after reset:\n%s", rname, output) logger.debug("Exiting API: reset_config_on_routers") return True -def load_config_to_router(tgen, routerName, save_bkup=False): +def load_config_to_routers(tgen, routers, save_bkup=False): """ - Loads configuration on router from the file FRRCFG_FILE. + Loads configuration on routers from the file FRRCFG_FILE. Parameters ---------- * `tgen` : Topogen object - * `routerName` : router for which configuration to be loaded + * `routers` : routers for which configuration is to be loaded * `save_bkup` : If True, Saves snapshot of FRRCFG_FILE to FRRCFG_BKUP_FILE + Returns + ------- + True or False """ - logger.debug("Entering API: load_config_to_router") + logger.debug("Entering API: load_config_to_routers") - router_list = tgen.routers() - for rname in ROUTER_LIST: - if routerName and rname != routerName: + base_router_list = tgen.routers() + router_list = {} + for router in routers: + if (router not in ROUTER_LIST) or (router not in base_router_list): continue + router_list[router] = base_router_list[router] + frr_cfg_file_fmt = TMPDIR + "/{}/" + FRRCFG_FILE + frr_cfg_bkup_fmt = TMPDIR + "/{}/" + FRRCFG_BKUP_FILE + + procs = {} + for rname in router_list: router = router_list[rname] try: - frr_cfg_file = "{}/{}/{}".format(TMPDIR, rname, FRRCFG_FILE) - frr_cfg_bkup = "{}/{}/{}".format(TMPDIR, rname, FRRCFG_BKUP_FILE) + frr_cfg_file = frr_cfg_file_fmt.format(rname) + frr_cfg_bkup = frr_cfg_bkup_fmt.format(rname) with open(frr_cfg_file, "r+") as cfg: data = cfg.read() logger.info( @@ -583,31 +648,76 @@ def load_config_to_router(tgen, routerName, save_bkup=False): if save_bkup: with open(frr_cfg_bkup, "w") as bkup: bkup.write(data) - - output = router.vtysh_multicmd(data, pretty_output=False) - for out_err in ERROR_LIST: - if out_err.lower() in output.lower(): - raise InvalidCLIError("%s" % output) - - cfg.truncate(0) - + procs[rname] = router_list[rname].popen( + ["/usr/bin/env", "vtysh", "-f", frr_cfg_file], + stdin=None, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) except IOError as err: - errormsg = ( - "Unable to open config File. error(%s):" " %s", - (err.errno, err.strerror), + logging.error( + "Unable to open config File. error(%s): %s", + err.errno, err.strerror ) - return errormsg + return False + except Exception as error: + logging.error("Unable to apply config on %s: %s", rname, str(error)) + return False + + errors = [] + for rname, p in procs.items(): + output, _ = p.communicate() + frr_cfg_file = frr_cfg_file_fmt.format(rname) + vtysh_command = "vtysh -f " + frr_cfg_file + if not p.returncode: + router_list[rname].logger.info( + '\nvtysh config apply => "{}"\nvtysh output <= "{}"'.format(vtysh_command, output) + ) + else: + router_list[rname].logger.error( + '\nvtysh config apply failed => "{}"\nvtysh output <= "{}"'.format(vtysh_command, output) + ) + logger.error("Config apply for %s failed %d: %s", rname, p.returncode, output) + # We can't thorw an exception here as we won't clear the config file. + errors.append(InvalidCLIError("load_config_to_routers error for {}: {}".format(rname, output))) + + # Empty the config file or we append to it next time through. + with open(frr_cfg_file, "r+") as cfg: + cfg.truncate(0) + + # Router current configuration to log file or console if + # "show_router_config" is defined in "pytest.ini" + if show_router_config: + procs = {} + for rname in router_list: + procs[rname] = router_list[rname].popen( + ["/usr/bin/env", "vtysh", "-c", "show running-config no-header"], + stdin=None, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + for rname, p in procs.items(): + output, _ = p.communicate() + if p.returncode: + logger.warning("Get running config for %s failed %d: %s", rname, p.returncode, output) + else: + logger.info("New configuration for router %s:\n%s", rname,output) - # Router current configuration to log file or console if - # "show_router_config" is defined in "pytest.ini" - if show_router_config: - logger.info("New configuration for router {}:".format(rname)) - new_config = router.run("vtysh -c 'show running'") - logger.info(new_config) + logger.debug("Exiting API: load_config_to_routers") + return not errors - logger.debug("Exiting API: load_config_to_router") - return True +def load_config_to_router(tgen, routerName, save_bkup=False): + """ + Loads configuration on router from the file FRRCFG_FILE. + + Parameters + ---------- + * `tgen` : Topogen object + * `routerName` : router for which configuration to be loaded + * `save_bkup` : If True, Saves snapshot of FRRCFG_FILE to FRRCFG_BKUP_FILE + """ + return load_config_to_routers(tgen, [routerName], save_bkup) def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None): @@ -707,8 +817,8 @@ def generate_support_bundle(): bundle_procs[rname] = tgen.net[rname].popen( "/usr/lib/frr/generate_support_bundle.py", stdin=None, - stdout=SUB_PIPE, - stderr=SUB_PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, ) for rname, rnode in router_list.items(): @@ -944,22 +1054,31 @@ def add_interfaces_to_vlan(tgen, input_dict): for intf_dict in interfaces: for interface, data in intf_dict.items(): # Adding interface to VLAN - cmd = "vconfig add {} {}".format(interface, vlan) + vlan_intf = "{}.{}".format(interface, vlan) + cmd = "ip link add link {} name {} type vlan id {}".format( + interface, + vlan_intf, + vlan + ) logger.info("[DUT: %s]: Running command: %s", dut, cmd) rnode.run(cmd) - vlan_intf = "{}.{}".format(interface, vlan) - - ip = data["ip"] - subnet = data["subnet"] - # Bringing interface up - cmd = "ip link set up {}".format(vlan_intf) + cmd = "ip link set {} up".format(vlan_intf) logger.info("[DUT: %s]: Running command: %s", dut, cmd) rnode.run(cmd) # Assigning IP address - cmd = "ifconfig {} {} netmask {}".format(vlan_intf, ip, subnet) + ifaddr = ipaddress.ip_interface( + u"{}/{}".format( + frr_unicode(data["ip"]), + frr_unicode(data["subnet"]) + ) + ) + + cmd = "ip -{0} a flush {1} scope global && ip a add {2} dev {1} && ip l set {1} up".format( + ifaddr.version, vlan_intf, ifaddr + ) logger.info("[DUT: %s]: Running command: %s", dut, cmd) rnode.run(cmd) @@ -1137,6 +1256,8 @@ def create_debug_log_config(tgen, input_dict, build=False): result = False try: + debug_config_dict = {} + for router in input_dict.keys(): debug_config = [] if "debug" in input_dict[router]: @@ -1167,10 +1288,12 @@ def create_debug_log_config(tgen, input_dict, build=False): for daemon, debug_logs in disable_logs.items(): for debug_log in debug_logs: debug_config.append("no {}".format(debug_log)) + if debug_config: + debug_config_dict[router] = debug_config - result = create_common_configuration( - tgen, router, debug_config, "debug_log_config", build=build - ) + result = create_common_configurations( + tgen, debug_config_dict, "debug_log_config", build=build + ) except InvalidCLIError: # Traceback errormsg = traceback.format_exc() @@ -1248,11 +1371,14 @@ def create_vrf_cfg(tgen, topo, input_dict=None, build=False): input_dict = deepcopy(input_dict) try: + config_data_dict = {} + for c_router, c_data in input_dict.items(): rnode = tgen.routers()[c_router] + config_data = [] + if "vrfs" in c_data: for vrf in c_data["vrfs"]: - config_data = [] del_action = vrf.setdefault("delete", False) name = vrf.setdefault("name", None) table_id = vrf.setdefault("id", None) @@ -1329,9 +1455,12 @@ def create_vrf_cfg(tgen, topo, input_dict=None, build=False): cmd = "no vni {}".format(del_vni) config_data.append(cmd) - result = create_common_configuration( - tgen, c_router, config_data, "vrf", build=build - ) + if config_data: + config_data_dict[c_router] = config_data + + result = create_common_configurations( + tgen, config_data_dict, "vrf", build=build + ) except InvalidCLIError: # Traceback @@ -1364,15 +1493,20 @@ def create_interface_in_kernel( rnode = tgen.routers()[dut] if create: - cmd = "sudo ip link add name {} type dummy".format(name) + cmd = "ip link show {0} >/dev/null || ip link add {0} type dummy".format(name) rnode.run(cmd) - addr_type = validate_ip_address(ip_addr) - if addr_type == "ipv4": - cmd = "ifconfig {} {} netmask {}".format(name, ip_addr, netmask) + if not netmask: + ifaddr = ipaddress.ip_interface(frr_unicode(ip_addr)) else: - cmd = "ifconfig {} inet6 add {}/{}".format(name, ip_addr, netmask) - + ifaddr = ipaddress.ip_interface(u"{}/{}".format( + frr_unicode(ip_addr), + frr_unicode(netmask) + )) + cmd = "ip -{0} a flush {1} scope global && ip a add {2} dev {1} && ip l set {1} up".format( + ifaddr.version, name, ifaddr + ) + logger.info("[DUT: %s]: Running command: %s", dut, cmd) rnode.run(cmd) if vrf: @@ -1560,7 +1694,7 @@ def find_interface_with_greater_ip(topo, router, loopback=True, interface=True): def write_test_header(tc_name): - """ Display message at beginning of test case""" + """Display message at beginning of test case""" count = 20 logger.info("*" * (len(tc_name) + count)) step("START -> Testcase : %s" % tc_name, reset=True) @@ -1568,7 +1702,7 @@ def write_test_header(tc_name): def write_test_footer(tc_name): - """ Display message at end of test case""" + """Display message at end of test case""" count = 21 logger.info("=" * (len(tc_name) + count)) logger.info("Testcase : %s -> PASSED", tc_name) @@ -1596,7 +1730,8 @@ def interface_status(tgen, topo, input_dict): logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) try: - global frr_cfg + rlist = [] + for router in input_dict.keys(): interface_list = input_dict[router]["interface_list"] @@ -1605,8 +1740,10 @@ def interface_status(tgen, topo, input_dict): rnode = tgen.routers()[router] interface_set_status(rnode, intf, status) - # Load config to router - load_config_to_router(tgen, router) + rlist.append(router) + + # Load config to routers + load_config_to_routers(tgen, rlist) except Exception as e: errormsg = traceback.format_exc() @@ -1795,6 +1932,8 @@ def create_interfaces_cfg(tgen, topo, build=False): topo = deepcopy(topo) try: + interface_data_dict = {} + for c_router, c_data in topo.items(): interface_data = [] for destRouterLink, data in sorted(c_data["links"].items()): @@ -1851,7 +1990,7 @@ def create_interfaces_cfg(tgen, topo, build=False): "network", "priority", "cost", - "mtu_ignore" + "mtu_ignore", ] if "ospf" in data: interface_data += _create_interfaces_ospf_cfg( @@ -1859,12 +1998,14 @@ def create_interfaces_cfg(tgen, topo, build=False): ) if "ospf6" in data: interface_data += _create_interfaces_ospf_cfg( - "ospf6", c_data, data, ospf_keywords + "ospf6", c_data, data, ospf_keywords + ["area"] ) + if interface_data: + interface_data_dict[c_router] = interface_data - result = create_common_configuration( - tgen, c_router, interface_data, "interface_config", build=build - ) + result = create_common_configurations( + tgen, interface_data_dict, "interface_config", build=build + ) except InvalidCLIError: # Traceback @@ -1923,6 +2064,8 @@ def create_static_routes(tgen, input_dict, build=False): input_dict = deepcopy(input_dict) try: + static_routes_list_dict = {} + for router in input_dict.keys(): if "static_routes" not in input_dict[router]: errormsg = "static_routes not present in input_dict" @@ -1978,9 +2121,12 @@ def create_static_routes(tgen, input_dict, build=False): static_routes_list.append(cmd) - result = create_common_configuration( - tgen, router, static_routes_list, "static_route", build=build - ) + if static_routes_list: + static_routes_list_dict[router] = static_routes_list + + result = create_common_configurations( + tgen, static_routes_list_dict, "static_route", build=build + ) except InvalidCLIError: # Traceback @@ -2037,6 +2183,8 @@ def create_prefix_lists(tgen, input_dict, build=False): logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) result = False try: + config_data_dict = {} + for router in input_dict.keys(): if "prefix_lists" not in input_dict[router]: errormsg = "prefix_lists not present in input_dict" @@ -2083,9 +2231,12 @@ def create_prefix_lists(tgen, input_dict, build=False): cmd = "no {}".format(cmd) config_data.append(cmd) - result = create_common_configuration( - tgen, router, config_data, "prefix_list", build=build - ) + if config_data: + config_data_dict[router] = config_data + + result = create_common_configurations( + tgen, config_data_dict, "prefix_list", build=build + ) except InvalidCLIError: # Traceback @@ -2181,6 +2332,8 @@ def create_route_maps(tgen, input_dict, build=False): logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) input_dict = deepcopy(input_dict) try: + rmap_data_dict = {} + for router in input_dict.keys(): if "route_maps" not in input_dict[router]: logger.debug("route_maps not present in input_dict") @@ -2458,9 +2611,12 @@ def create_route_maps(tgen, input_dict, build=False): cmd = "match metric {}".format(metric) rmap_data.append(cmd) - result = create_common_configuration( - tgen, router, rmap_data, "route_maps", build=build - ) + if rmap_data: + rmap_data_dict[router] = rmap_data + + result = create_common_configurations( + tgen, rmap_data_dict, "route_maps", build=build + ) except InvalidCLIError: # Traceback @@ -2535,6 +2691,8 @@ def create_bgp_community_lists(tgen, input_dict, build=False): logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) input_dict = deepcopy(input_dict) try: + config_data_dict = {} + for router in input_dict.keys(): if "bgp_community_lists" not in input_dict[router]: errormsg = "bgp_community_lists not present in input_dict" @@ -2571,9 +2729,12 @@ def create_bgp_community_lists(tgen, input_dict, build=False): config_data.append(cmd) - result = create_common_configuration( - tgen, router, config_data, "bgp_community_list", build=build - ) + if config_data: + config_data_dict[router] = config_data + + result = create_common_configurations( + tgen, config_data_dict, "bgp_community_list", build=build + ) except InvalidCLIError: # Traceback @@ -2906,7 +3067,7 @@ def configure_interface_mac(tgen, input_dict): rnode = tgen.routers()[dut] for intf, mac in input_dict[dut].items(): - cmd = "ifconfig {} hw ether {}".format(intf, mac) + cmd = "ip link set {} address {}".format(intf, mac) logger.info("[DUT: %s]: Running command: %s", dut, cmd) try: @@ -4550,3 +4711,64 @@ def verify_ip_nht(tgen, input_dict): logger.debug("Exiting lib API: verify_ip_nht()") return False + + +def scapy_send_raw_packet( + tgen, topo, senderRouter, intf, packet=None, interval=1, count=1 +): + """ + Using scapy Raw() method to send BSR raw packet from one FRR + to other + + Parameters: + ----------- + * `tgen` : Topogen object + * `topo` : json file data + * `senderRouter` : Sender router + * `packet` : packet in raw format + * `interval` : Interval between the packets + * `count` : Number of packets to be sent + + returns: + -------- + errormsg or True + """ + + global CD + result = "" + logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) + sender_interface = intf + rnode = tgen.routers()[senderRouter] + + for destLink, data in topo["routers"][senderRouter]["links"].items(): + if "type" in data and data["type"] == "loopback": + continue + + if not packet: + packet = topo["routers"][senderRouter]["pkt"]["test_packets"][packet][ + "data" + ] + + if interval > 1 or count > 1: + cmd = ( + "nohup /usr/bin/python {}/send_bsr_packet.py '{}' '{}' " + "--interval={} --count={} &".format( + CD, packet, sender_interface, interval, count + ) + ) + else: + cmd = ( + "/usr/bin/python {}/send_bsr_packet.py '{}' '{}' " + "--interval={} --count={}".format( + CD, packet, sender_interface, interval, count + ) + ) + + logger.info("Scapy cmd: \n %s", cmd) + result = rnode.run(cmd) + + if result == "": + return result + + logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) + return True |
