tests: run a test inside a QEMU VM

Use the script test/run.py to run a test named test_vm_tap
inside a QEMU VM. The run script builds out a virtual env,
launches a light weight QEMU VM, mounts host directories,
starts VPP inside the VM and runs the test. The test named
test_vm_tap, creates two tap v2 interfaces in separate Linux
namespaces and using iPerf, streams traffic between the VM
and VPP. All data files are stored in the directory named
/tmp/vpp-vm-tests. To clean up, use the make test-wipe
command.
Usage:
test/run.py --vm --debug --test test_vm_tap

Type: improvement

Change-Id: I4425dbef52acee1e5b8af5acaa169b89a2c0f171
Signed-off-by: Naveen Joy <najoy@cisco.com>
diff --git a/test/vpp_iperf.py b/test/vpp_iperf.py
new file mode 100644
index 0000000..78ce9d0
--- /dev/null
+++ b/test/vpp_iperf.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python
+
+# Start an iPerf connection stream between two Linux namespaces ##
+
+import subprocess
+import os
+
+
+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):
+        self.server_ns = server_ns
+        self.client_ns = client_ns
+        self.server_ip = server_ip
+        self.duration = 10
+        self.client_args = ""
+        self.server_args = ""
+        # Set the iperf executable
+        self.iperf = os.path.join(os.getenv("TEST_DATA_DIR") or "/", "usr/bin/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 start_iperf_server(self):
+        print("Starting iPerf Server Daemon in Namespace ", self.server_ns)
+        args = [
+            "ip",
+            "netns",
+            "exec",
+            self.server_ns,
+            self.iperf,
+            "-s",
+            "-D",
+            "-B",
+            self.server_ip,
+        ]
+        args.extend(self.server_args.split())
+        try:
+            subprocess.run(
+                args,
+                stderr=subprocess.STDOUT,
+                timeout=self.duration + 5,
+                encoding="utf-8",
+            )
+        except subprocess.TimeoutExpired as e:
+            raise Exception("Error: Timeout expired for iPerf", e.output)
+
+    def start_iperf_client(self):
+        print("Starting iPerf Client in Namespace ", self.client_ns)
+        args = [
+            "ip",
+            "netns",
+            "exec",
+            self.client_ns,
+            self.iperf,
+            "-c",
+            self.server_ip,
+            "-t",
+            str(self.duration),
+        ]
+        args.extend(self.client_args.split())
+        try:
+            subprocess.run(
+                args,
+                stderr=subprocess.STDOUT,
+                timeout=self.duration + 5,
+                encoding="utf-8",
+            )
+        except subprocess.TimeoutExpired as e:
+            raise Exception("Error: Timeout expired for iPerf", e.output)
+
+    def start(self):
+        """Run iPerf and return True if successful"""
+        self.ensure_init()
+        try:
+            self.start_iperf_server()
+        except Exception as e:
+            subprocess.run(["pkill", "iperf"])
+            raise Exception("Error starting iPerf Server", e)
+
+        try:
+            self.start_iperf_client()
+        except Exception as e:
+            raise Exception("Error starting iPerf Client", e)
+        subprocess.run(["pkill", "iperf"])
+
+
+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()