aboutsummaryrefslogtreecommitdiffstats
path: root/test/vpp_qemu_utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/vpp_qemu_utils.py')
-rw-r--r--test/vpp_qemu_utils.py308
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