hs-test: fixed timed out tests passing in the CI
[vpp.git] / test / vpp_iperf.py
1 #!/usr/bin/env python
2
3 # Start an iPerf connection stream between two Linux namespaces ##
4
5 import subprocess
6 import os
7 import sys
8
9
10 class VppIperf:
11     """ "Create an iPerf connection stream between two namespaces.
12
13     Usage:
14     iperf = VppIperf()                   # Create the iPerf Object
15     iperf.client_ns = 'ns1'              # Client Namespace
16     iperf.server_ns = 'ns2'              # Server Namespace
17     iperf.server_ip = '10.0.0.102'       # Server IP Address
18     iperf.start()                        # Start the connection stream
19
20     Optional:
21     iperf.duration = 15   # Time to transmit for in seconds (Default=10)
22
23     ## Optionally set any iperf client & server args
24     Example:
25     # Run 4 parallel streams, write to logfile & bind to port 5202
26     iperf.client_args='-P 4 --logfile /tmp/vpp-vm-tests/vpp_iperf.log -p 5202'
27     iperf.server_args='-p 5202'
28     """
29
30     def __init__(self, server_ns=None, client_ns=None, server_ip=None, logger=None):
31         self.server_ns = server_ns
32         self.client_ns = client_ns
33         self.server_ip = server_ip
34         self.duration = 10
35         self.client_args = ""
36         self.server_args = ""
37         self.logger = logger
38         # Set the iperf executable
39         self.iperf = self.get_iperf()
40
41     def ensure_init(self):
42         if self.server_ns and self.client_ns and self.server_ip:
43             return True
44         else:
45             raise Exception(
46                 "Error: Cannot Start." "iPerf object has not been initialized"
47             )
48
49     def get_iperf(self):
50         """Return the iperf executable for running tests.
51
52         Look for the iperf executable in the following order
53         1. ${TEST_DATA_DIR}/usr/bin/iperf  # running tests inside the VM
54         2. /usr/bin/iperf3                 # running tests on the host
55         """
56         vm_test_dir = os.getenv("TEST_DATA_DIR", "/tmp/vpp-vm-tests")
57         if os.path.isdir(vm_test_dir):
58             iperf = os.path.join(vm_test_dir, "/usr/bin/iperf")
59         else:
60             iperf = "/usr/bin/iperf3"
61         if os.path.exists(iperf):
62             return iperf
63         else:
64             self.logger.error(f"Could not find an iperf executable for running tests")
65             sys.exit(1)
66
67     def start_iperf_server(self):
68         """Starts the  iperf server and returns the process cmdline args."""
69         args = [
70             "ip",
71             "netns",
72             "exec",
73             self.server_ns,
74             self.iperf,
75             "-s",
76             "-D",
77         ]
78         args.extend(self.server_args.split())
79         cmd = " ".join(args)
80         self.logger.debug(f"Starting iperf server: {cmd}")
81         try:
82             subprocess.run(
83                 cmd,
84                 timeout=self.duration + 5,
85                 encoding="utf-8",
86                 shell=True,
87                 stdout=subprocess.PIPE,
88                 stderr=subprocess.STDOUT,
89             )
90         except subprocess.TimeoutExpired as e:
91             raise Exception("Error: Timeout expired for iPerf", e.output)
92         return args[4:]
93
94     def start_iperf_client(self):
95         args = [
96             "ip",
97             "netns",
98             "exec",
99             self.client_ns,
100             self.iperf,
101             "-c",
102             self.server_ip,
103             "-t",
104             str(self.duration),
105         ]
106         args.extend(self.client_args.split())
107         args = " ".join(args)
108         try:
109             return subprocess.run(
110                 args,
111                 timeout=self.duration + 5,
112                 encoding="utf-8",
113                 capture_output=True,
114                 shell=True,
115             )
116         except subprocess.TimeoutExpired as e:
117             raise Exception("Error: Timeout expired for iPerf", e.output)
118
119     def start(self, server_only=False, client_only=False):
120         """Runs iPerf.
121
122         Starts the iperf server daemon & runs the iperf client.
123         arguments:-
124         server_only -- start the iperf server daemon only
125         client_only -- run the iperf client only
126         Return True if we have no errors in iPerf client, else False.
127         """
128         self.ensure_init()
129         if not client_only:
130             return self.start_iperf_server()
131         if not server_only:
132             result = self.start_iperf_client()
133             self.logger.debug(f"Iperf client args: {result.args}")
134             self.logger.debug(result.stdout)
135             if result.stderr:
136                 self.logger.error(
137                     f"Error starting Iperf Client in Namespace: {self.client_ns}"
138                 )
139                 self.logger.error(f"Iperf client args: {result.args}")
140                 self.logger.error(f"Iperf client has errors: {result.stderr}")
141                 return False
142             else:
143                 return True
144
145
146 ## Functions to start and stop iPerf using the iPerf object
147 def start_iperf(
148     ip_version,
149     client_ns="iprf_client_ns",
150     server_ns="iprf_server_ns",
151     server_ipv4_address="10.0.0.102",
152     server_ipv6_address="2001:1::2",
153     client_args="",
154     server_args="",
155     duration=10,
156     server_only=False,
157     client_only=False,
158     logger=None,
159 ):
160     """Start an iperf connection stream using the iPerf object.
161
162     Starts iPerf an connection stream between an iPerf client in the
163     client namespace (client_ns) and a server in another
164     namespace (server_ns).
165     Parameters:
166     ip_version - 4 or 6
167     client_ns - iPerf client namespace
168     server_ns - iPerf server namespace
169     server_ipv4_address - ipv4 address of the server, if ip_version=4
170     server_ipv6_address - ipv6 address of the server, if ip_version=6
171     client_args - Additonal iperf control arguments to be passed
172                     to the iperf client from the test (str)
173     server_args - Additonal iperf control arguments to be passed
174                     to the iperf server from the test (str)
175     duration    - Iperf duration in seconds
176     server_only - start iperf server only
177     client_only - start the iperf client only
178     logger - test logger
179     """
180     if ip_version == 4:
181         iperf_server_ip = server_ipv4_address
182     elif ip_version == 6:
183         iperf_server_ip = server_ipv6_address
184         client_args = "-V" + " " + client_args
185         server_args = "-V" + " " + server_args
186     iperf = VppIperf()
187     iperf.client_ns = client_ns
188     iperf.server_ns = server_ns
189     iperf.server_ip = iperf_server_ip
190     iperf.client_args = client_args
191     iperf.server_args = server_args
192     iperf.duration = duration
193     iperf.logger = logger
194     return iperf.start(server_only=server_only, client_only=client_only)
195
196
197 def stop_iperf(iperf_cmd):
198     """Stop the iperf process matching the iperf_cmd string."""
199     args = ["pgrep", "-x", "-f", iperf_cmd]
200     p = subprocess.Popen(
201         args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8"
202     )
203     stdout, _ = p.communicate()
204     for pid in stdout.split():
205         try:
206             subprocess.run(
207                 f"kill -9 {pid}",
208                 encoding="utf-8",
209                 shell=True,
210             )
211         except Exception:
212             pass
213
214
215 if __name__ == "__main__":
216     # Run iPerf using default settings
217     iperf = VppIperf()
218     iperf.client_ns = "ns1"
219     iperf.server_ns = "ns2"
220     iperf.server_ip = "10.0.0.102"
221     iperf.duration = 20
222     iperf.start()