vlib: interrupt mode support for pre-input nodes
[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         args = [
69             "ip",
70             "netns",
71             "exec",
72             self.server_ns,
73             self.iperf,
74             "-s",
75             "-D",
76         ]
77         args.extend(self.server_args.split())
78         args = " ".join(args)
79         self.logger.debug(f"Starting iperf server: {args}")
80         try:
81             return subprocess.run(
82                 args,
83                 timeout=self.duration + 5,
84                 encoding="utf-8",
85                 shell=True,
86                 stdout=subprocess.PIPE,
87                 stderr=subprocess.STDOUT,
88             )
89         except subprocess.TimeoutExpired as e:
90             raise Exception("Error: Timeout expired for iPerf", e.output)
91
92     def start_iperf_client(self):
93         args = [
94             "ip",
95             "netns",
96             "exec",
97             self.client_ns,
98             self.iperf,
99             "-c",
100             self.server_ip,
101             "-t",
102             str(self.duration),
103         ]
104         args.extend(self.client_args.split())
105         args = " ".join(args)
106         try:
107             return subprocess.run(
108                 args,
109                 timeout=self.duration + 5,
110                 encoding="utf-8",
111                 capture_output=True,
112                 shell=True,
113             )
114         except subprocess.TimeoutExpired as e:
115             raise Exception("Error: Timeout expired for iPerf", e.output)
116
117     def start(self, server_only=False, client_only=False):
118         """Runs iPerf.
119
120         Starts the iperf server daemon & runs the iperf client.
121         arguments:-
122         server_only -- start the iperf server daemon only
123         client_only -- run the iperf client only
124         Return True if we have no errors in iPerf client, else False.
125         """
126         self.ensure_init()
127         if not client_only:
128             self.start_iperf_server()
129         if not server_only:
130             result = self.start_iperf_client()
131             self.logger.debug(f"Iperf client args: {result.args}")
132             self.logger.debug(result.stdout)
133             if result.stderr:
134                 self.logger.error(
135                     f"Error starting Iperf Client in Namespace: {self.client_ns}"
136                 )
137                 self.logger.error(f"Iperf client args: {result.args}")
138                 self.logger.error(f"Iperf client has errors: {result.stderr}")
139                 return False
140             else:
141                 return True
142
143
144 ## Functions to start and stop iPerf using the iPerf object
145 def start_iperf(
146     ip_version,
147     client_ns="iprf_client_ns",
148     server_ns="iprf_server_ns",
149     server_ipv4_address="10.0.0.102",
150     server_ipv6_address="2001:1::2",
151     client_args="",
152     server_args="",
153     duration=10,
154     server_only=False,
155     client_only=False,
156     logger=None,
157 ):
158     """Start an iperf connection stream using the iPerf object.
159
160     Starts iPerf an connection stream between an iPerf client in the
161     client namespace (client_ns) and a server in another
162     namespace (server_ns).
163     Parameters:
164     ip_version - 4 or 6
165     client_ns - iPerf client namespace
166     server_ns - iPerf server namespace
167     server_ipv4_address - ipv4 address of the server, if ip_version=4
168     server_ipv6_address - ipv6 address of the server, if ip_version=6
169     client_args - Additonal iperf control arguments to be passed
170                     to the iperf client from the test (str)
171     server_args - Additonal iperf control arguments to be passed
172                     to the iperf server from the test (str)
173     duration    - Iperf duration in seconds
174     server_only - start iperf server only
175     client_only - start the iperf client only
176     logger - test logger
177     """
178     if ip_version == 4:
179         iperf_server_ip = server_ipv4_address
180     elif ip_version == 6:
181         iperf_server_ip = server_ipv6_address
182         client_args = "-V" + " " + client_args
183         server_args = "-V" + " " + server_args
184     iperf = VppIperf()
185     iperf.client_ns = client_ns
186     iperf.server_ns = server_ns
187     iperf.server_ip = iperf_server_ip
188     iperf.client_args = client_args
189     iperf.server_args = server_args
190     iperf.duration = duration
191     iperf.logger = logger
192     return iperf.start(server_only=server_only, client_only=client_only)
193
194
195 def stop_iperf():
196     args = ["pkill", "iperf"]
197     args = " ".join(args)
198     try:
199         return subprocess.run(
200             args,
201             encoding="utf-8",
202             shell=True,
203         )
204     except Exception:
205         pass
206
207
208 if __name__ == "__main__":
209     # Run iPerf using default settings
210     iperf = VppIperf()
211     iperf.client_ns = "ns1"
212     iperf.server_ns = "ns2"
213     iperf.server_ip = "10.0.0.102"
214     iperf.duration = 20
215     iperf.start()