70335e8e50
Type: test Change-Id: I711dfe65ad542a45acd484f0b4e3e6ade9576f66 Signed-off-by: Naveen Joy <najoy@cisco.com>
309 lines
10 KiB
Python
309 lines
10 KiB
Python
#!/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
|