diff options
Diffstat (limited to 'test/vpp_qemu_utils.py')
-rw-r--r-- | test/vpp_qemu_utils.py | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/test/vpp_qemu_utils.py b/test/vpp_qemu_utils.py new file mode 100644 index 00000000000..03b8632b15f --- /dev/null +++ b/test/vpp_qemu_utils.py @@ -0,0 +1,308 @@ +#!/usr/bin/env python + +# Utility functions for QEMU tests ## + +import subprocess +import sys +import os +import multiprocessing as mp + + +def can_create_namespaces(namespace="vpp_chk_4212"): + """Check if the environment allows creating the namespaces""" + + try: + result = subprocess.run(["ip", "netns", "add", namespace], capture_output=True) + if result.returncode != 0: + return False + result = subprocess.run(["ip", "netns", "del", namespace], capture_output=True) + if result.returncode != 0: + return False + return True + except Exception: + return False + + +def create_namespace(ns): + """create one or more namespaces. + + arguments: + ns -- a string value or an iterable of namespace names + """ + if isinstance(ns, str): + namespaces = [ns] + else: + namespaces = ns + try: + for namespace in namespaces: + result = subprocess.run(["ip", "netns", "add", namespace]) + if result.returncode != 0: + raise Exception(f"Error while creating namespace {namespace}") + except subprocess.CalledProcessError as e: + raise Exception("Error creating namespace:", e.output) + + +def add_namespace_route(ns, prefix, gw_ip): + """Add a route to a namespace. + + arguments: + ns -- namespace string value + prefix -- NETWORK/MASK or "default" + gw_ip -- Gateway IP + """ + try: + subprocess.run( + ["ip", "netns", "exec", ns, "ip", "route", "add", prefix, "via", gw_ip], + capture_output=True, + ) + except subprocess.CalledProcessError as e: + raise Exception("Error adding route to namespace:", e.output) + + +def delete_host_interfaces(*host_interface_names): + """Delete host interfaces. + + arguments: + host_interface_names - sequence of host interface names to be deleted + """ + for host_interface_name in host_interface_names: + try: + subprocess.run( + ["ip", "link", "del", host_interface_name], capture_output=True + ) + except subprocess.CalledProcessError as e: + raise Exception("Error deleting host interface:", e.output) + + +def create_host_interface( + host_interface_name, vpp_interface_name, host_namespace, *host_ip_prefixes +): + """Create a host interface of type veth. + + arguments: + host_interface_name -- name of the veth interface on the host side + vpp_interface_name -- name of the veth interface on the VPP side + host_namespace -- host namespace into which the host_interface needs to be set + host_ip_prefixes -- a sequence of ip/prefix-lengths to be set + on the host_interface + """ + try: + process = subprocess.run( + [ + "ip", + "link", + "add", + "name", + vpp_interface_name, + "type", + "veth", + "peer", + "name", + host_interface_name, + ], + capture_output=True, + ) + if process.returncode != 0: + print(f"Error creating host interface: {process.stderr}") + sys.exit(1) + + process = subprocess.run( + ["ip", "link", "set", host_interface_name, "netns", host_namespace], + capture_output=True, + ) + if process.returncode != 0: + print(f"Error setting host interface namespace: {process.stderr}") + sys.exit(1) + + process = subprocess.run( + ["ip", "link", "set", "dev", vpp_interface_name, "up"], capture_output=True + ) + if process.returncode != 0: + print(f"Error bringing up the host interface: {process.stderr}") + sys.exit(1) + + process = subprocess.run( + [ + "ip", + "netns", + "exec", + host_namespace, + "ip", + "link", + "set", + "dev", + host_interface_name, + "up", + ], + capture_output=True, + ) + if process.returncode != 0: + print( + f"Error bringing up the host interface in namespace: " + f"{process.stderr}" + ) + sys.exit(1) + + for host_ip_prefix in host_ip_prefixes: + process = subprocess.run( + [ + "ip", + "netns", + "exec", + host_namespace, + "ip", + "addr", + "add", + host_ip_prefix, + "dev", + host_interface_name, + ], + capture_output=True, + ) + if process.returncode != 0: + print( + f"Error setting ip prefix on the host interface: " + f"{process.stderr}" + ) + sys.exit(1) + except subprocess.CalledProcessError as e: + raise Exception("Error adding route to namespace:", e.output) + + +def set_interface_mtu(namespace, interface, mtu, logger): + """set an mtu number on a linux device interface.""" + args = ["ip", "link", "set", "mtu", str(mtu), "dev", interface] + if namespace: + args = ["ip", "netns", "exec", namespace] + args + try: + logger.debug( + f"Setting mtu:{mtu} on linux interface:{interface} " + f"in namespace:{namespace}" + ) + subprocess.run(args) + except subprocess.CalledProcessError as e: + raise Exception("Error updating mtu:", e.output) + + +def enable_interface_gso(namespace, interface): + """enable gso offload on a linux device interface.""" + args = ["ethtool", "-K", interface, "rx", "on", "tx", "on"] + if namespace: + args = ["ip", "netns", "exec", namespace] + args + try: + process = subprocess.run(args, capture_output=True) + if process.returncode != 0: + print( + f"Error enabling GSO offload on linux device interface: " + f"{process.stderr}" + ) + sys.exit(1) + except subprocess.CalledProcessError as e: + raise Exception("Error enabling gso:", e.output) + + +def disable_interface_gso(namespace, interface): + """disable gso offload on a linux device interface.""" + args = ["ethtool", "-K", interface, "rx", "off", "tx", "off"] + if namespace: + args = ["ip", "netns", "exec", namespace] + args + try: + process = subprocess.run(args, capture_output=True) + if process.returncode != 0: + print( + f"Error disabling GSO offload on linux device interface: " + f"{process.stderr}" + ) + sys.exit(1) + except subprocess.CalledProcessError as e: + raise Exception("Error disabling gso:", e.output) + + +def delete_namespace(ns): + """delete one or more namespaces. + + arguments: + namespaces -- a list of namespace names + """ + if isinstance(ns, str): + namespaces = [ns] + else: + namespaces = ns + try: + for namespace in namespaces: + result = subprocess.run( + ["ip", "netns", "del", namespace], capture_output=True + ) + if result.returncode != 0: + raise Exception(f"Error while deleting namespace {namespace}") + except subprocess.CalledProcessError as e: + raise Exception("Error deleting namespace:", e.output) + + +def list_namespace(ns): + """List the IP address of a namespace""" + try: + subprocess.run(["ip", "netns", "exec", ns, "ip", "addr"]) + except subprocess.CalledProcessError as e: + raise Exception("Error listing namespace IP:", e.output) + + +def libmemif_test_app(memif_sock_path, logger): + """Build & run the libmemif test_app for memif interface testing.""" + test_dir = os.path.dirname(os.path.realpath(__file__)) + ws_root = os.path.dirname(test_dir) + libmemif_app = os.path.join( + ws_root, "extras", "libmemif", "build", "examples", "test_app" + ) + + def build_libmemif_app(): + if not os.path.exists(libmemif_app): + print(f"Building app:{libmemif_app} for memif interface testing") + libmemif_app_dir = os.path.join(ws_root, "extras", "libmemif", "build") + if not os.path.exists(libmemif_app_dir): + os.makedirs(libmemif_app_dir) + os.chdir(libmemif_app_dir) + try: + p = subprocess.run(["cmake", ".."], capture_output=True) + logger.debug(p.stdout) + if p.returncode != 0: + print(f"libmemif app:{libmemif_app} cmake error:{p.stderr}") + sys.exit(1) + p = subprocess.run(["make"], capture_output=True) + logger.debug(p.stdout) + if p.returncode != 0: + print(f"Error building libmemif app:{p.stderr}") + sys.exit(1) + except subprocess.CalledProcessError as e: + raise Exception("Error building libmemif_test_app:", e.output) + + def start_libmemif_app(): + """Restart once if the initial run fails.""" + max_tries = 2 + run = 0 + if not os.path.exists(libmemif_app): + raise Exception( + f"Error could not locate the libmemif test app:{libmemif_app}" + ) + args = [libmemif_app, "-b", "9216", "-s", memif_sock_path] + while run < max_tries: + try: + process = subprocess.run(args, capture_output=True) + logger.debug(process.stdout) + if process.returncode != 0: + msg = f"Error starting libmemif app:{libmemif_app}" + logger.error(msg) + raise Exception(msg) + except Exception: + msg = f"re-starting libmemif app:{libmemif_app}" + logger.error(msg) + continue + else: + break + finally: + run += 1 + + build_libmemif_app() + process = mp.Process(target=start_libmemif_app) + process.start() + return process |