vpp/test/vpp_iperf.py

223 lines
7.2 KiB
Python
Raw Normal View History

#!/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()