#!/usr/bin/env python # Start an iPerf connection stream between two Linux namespaces ## import subprocess import os import sys class VppIperf: """ "Create an iPerf connection stream between two namespaces. Usage: iperf = VppIperf() # Create the iPerf Object iperf.client_ns = 'ns1' # Client Namespace iperf.server_ns = 'ns2' # Server Namespace iperf.server_ip = '10.0.0.102' # Server IP Address iperf.start() # Start the connection stream Optional: iperf.duration = 15 # Time to transmit for in seconds (Default=10) ## Optionally set any iperf client & server args Example: # Run 4 parallel streams, write to logfile & bind to port 5202 iperf.client_args='-P 4 --logfile /tmp/vpp-vm-tests/vpp_iperf.log -p 5202' iperf.server_args='-p 5202' """ def __init__(self, server_ns=None, client_ns=None, server_ip=None, logger=None): self.server_ns = server_ns self.client_ns = client_ns self.server_ip = server_ip self.duration = 10 self.client_args = "" self.server_args = "" self.logger = logger # Set the iperf executable self.iperf = self.get_iperf() def ensure_init(self): if self.server_ns and self.client_ns and self.server_ip: return True else: raise Exception( "Error: Cannot Start." "iPerf object has not been initialized" ) def get_iperf(self): """Return the iperf executable for running tests. Look for the iperf executable in the following order 1. ${TEST_DATA_DIR}/usr/bin/iperf # running tests inside the VM 2. /usr/bin/iperf3 # running tests on the host """ vm_test_dir = os.getenv("TEST_DATA_DIR", "/tmp/vpp-vm-tests") if os.path.isdir(vm_test_dir): iperf = os.path.join(vm_test_dir, "/usr/bin/iperf") else: iperf = "/usr/bin/iperf3" if os.path.exists(iperf): return iperf else: self.logger.error(f"Could not find an iperf executable for running tests") sys.exit(1) def start_iperf_server(self): """Starts the iperf server and returns the process cmdline args.""" args = [ "ip", "netns", "exec", self.server_ns, self.iperf, "-s", "-D", ] args.extend(self.server_args.split()) cmd = " ".join(args) self.logger.debug(f"Starting iperf server: {cmd}") try: subprocess.run( cmd, timeout=self.duration + 5, encoding="utf-8", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) except subprocess.TimeoutExpired as e: raise Exception("Error: Timeout expired for iPerf", e.output) return args[4:] def start_iperf_client(self): args = [ "ip", "netns", "exec", self.client_ns, self.iperf, "-c", self.server_ip, "-t", str(self.duration), ] args.extend(self.client_args.split()) args = " ".join(args) try: return subprocess.run( args, timeout=self.duration + 5, encoding="utf-8", capture_output=True, shell=True, ) except subprocess.TimeoutExpired as e: raise Exception("Error: Timeout expired for iPerf", e.output) def start(self, server_only=False, client_only=False): """Runs iPerf. Starts the iperf server daemon & runs the iperf client. arguments:- server_only -- start the iperf server daemon only client_only -- run the iperf client only Return True if we have no errors in iPerf client, else False. """ self.ensure_init() if not client_only: return self.start_iperf_server() if not server_only: result = self.start_iperf_client() self.logger.debug(f"Iperf client args: {result.args}") self.logger.debug(result.stdout) if result.stderr: self.logger.error( f"Error starting Iperf Client in Namespace: {self.client_ns}" ) self.logger.error(f"Iperf client args: {result.args}") self.logger.error(f"Iperf client has errors: {result.stderr}") return False else: return True ## Functions to start and stop iPerf using the iPerf object def start_iperf( ip_version, client_ns="iprf_client_ns", server_ns="iprf_server_ns", server_ipv4_address="10.0.0.102", server_ipv6_address="2001:1::2", client_args="", server_args="", duration=10, server_only=False, client_only=False, logger=None, ): """Start an iperf connection stream using the iPerf object. Starts iPerf an connection stream between an iPerf client in the client namespace (client_ns) and a server in another namespace (server_ns). Parameters: ip_version - 4 or 6 client_ns - iPerf client namespace server_ns - iPerf server namespace server_ipv4_address - ipv4 address of the server, if ip_version=4 server_ipv6_address - ipv6 address of the server, if ip_version=6 client_args - Additonal iperf control arguments to be passed to the iperf client from the test (str) server_args - Additonal iperf control arguments to be passed to the iperf server from the test (str) duration - Iperf duration in seconds server_only - start iperf server only client_only - start the iperf client only logger - test logger """ if ip_version == 4: iperf_server_ip = server_ipv4_address elif ip_version == 6: iperf_server_ip = server_ipv6_address client_args = "-V" + " " + client_args server_args = "-V" + " " + server_args iperf = VppIperf() iperf.client_ns = client_ns iperf.server_ns = server_ns iperf.server_ip = iperf_server_ip iperf.client_args = client_args iperf.server_args = server_args iperf.duration = duration iperf.logger = logger return iperf.start(server_only=server_only, client_only=client_only) def stop_iperf(iperf_cmd): """Stop the iperf process matching the iperf_cmd string.""" args = ["pgrep", "-x", "-f", iperf_cmd] p = subprocess.Popen( args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8" ) stdout, _ = p.communicate() for pid in stdout.split(): try: subprocess.run( f"kill -9 {pid}", encoding="utf-8", shell=True, ) except Exception: pass if __name__ == "__main__": # Run iPerf using default settings iperf = VppIperf() iperf.client_ns = "ns1" iperf.server_ns = "ns2" iperf.server_ip = "10.0.0.102" iperf.duration = 20 iperf.start()