blob: 03b8632b15f45e0add2fc22c6469a2fc5ea07234 [file] [log] [blame]
Naveen Joy7ea7ab52021-05-11 10:31:18 -07001#!/usr/bin/env python
2
3# Utility functions for QEMU tests ##
4
5import subprocess
Naveen Joye4168932022-10-04 14:22:05 -07006import sys
Naveen Joy70335e82023-07-28 16:33:30 -07007import os
8import multiprocessing as mp
Naveen Joy7ea7ab52021-05-11 10:31:18 -07009
10
adrianvillin30f26002023-10-24 12:53:10 +020011def can_create_namespaces(namespace="vpp_chk_4212"):
Andrew Yourtchenko9ba6dcf2023-06-20 14:52:08 +000012 """Check if the environment allows creating the namespaces"""
13
14 try:
Andrew Yourtchenko9ba6dcf2023-06-20 14:52:08 +000015 result = subprocess.run(["ip", "netns", "add", namespace], capture_output=True)
16 if result.returncode != 0:
17 return False
18 result = subprocess.run(["ip", "netns", "del", namespace], capture_output=True)
19 if result.returncode != 0:
20 return False
21 return True
adrianvillin30f26002023-10-24 12:53:10 +020022 except Exception:
Andrew Yourtchenko9ba6dcf2023-06-20 14:52:08 +000023 return False
24
25
Naveen Joy7ea7ab52021-05-11 10:31:18 -070026def create_namespace(ns):
Naveen Joye4168932022-10-04 14:22:05 -070027 """create one or more namespaces.
28
29 arguments:
30 ns -- a string value or an iterable of namespace names
31 """
32 if isinstance(ns, str):
33 namespaces = [ns]
34 else:
35 namespaces = ns
Naveen Joy7ea7ab52021-05-11 10:31:18 -070036 try:
Naveen Joye4168932022-10-04 14:22:05 -070037 for namespace in namespaces:
Andrew Yourtchenko9ba6dcf2023-06-20 14:52:08 +000038 result = subprocess.run(["ip", "netns", "add", namespace])
39 if result.returncode != 0:
40 raise Exception(f"Error while creating namespace {namespace}")
Naveen Joy7ea7ab52021-05-11 10:31:18 -070041 except subprocess.CalledProcessError as e:
42 raise Exception("Error creating namespace:", e.output)
43
44
Naveen Joye4168932022-10-04 14:22:05 -070045def add_namespace_route(ns, prefix, gw_ip):
46 """Add a route to a namespace.
47
48 arguments:
49 ns -- namespace string value
50 prefix -- NETWORK/MASK or "default"
51 gw_ip -- Gateway IP
52 """
53 try:
54 subprocess.run(
55 ["ip", "netns", "exec", ns, "ip", "route", "add", prefix, "via", gw_ip],
56 capture_output=True,
57 )
58 except subprocess.CalledProcessError as e:
59 raise Exception("Error adding route to namespace:", e.output)
60
61
62def delete_host_interfaces(*host_interface_names):
63 """Delete host interfaces.
64
65 arguments:
66 host_interface_names - sequence of host interface names to be deleted
67 """
68 for host_interface_name in host_interface_names:
69 try:
70 subprocess.run(
71 ["ip", "link", "del", host_interface_name], capture_output=True
72 )
73 except subprocess.CalledProcessError as e:
74 raise Exception("Error deleting host interface:", e.output)
75
76
77def create_host_interface(
78 host_interface_name, vpp_interface_name, host_namespace, *host_ip_prefixes
79):
80 """Create a host interface of type veth.
81
82 arguments:
83 host_interface_name -- name of the veth interface on the host side
84 vpp_interface_name -- name of the veth interface on the VPP side
85 host_namespace -- host namespace into which the host_interface needs to be set
86 host_ip_prefixes -- a sequence of ip/prefix-lengths to be set
87 on the host_interface
88 """
89 try:
90 process = subprocess.run(
91 [
92 "ip",
93 "link",
94 "add",
95 "name",
96 vpp_interface_name,
97 "type",
98 "veth",
99 "peer",
100 "name",
101 host_interface_name,
102 ],
103 capture_output=True,
104 )
105 if process.returncode != 0:
106 print(f"Error creating host interface: {process.stderr}")
107 sys.exit(1)
108
109 process = subprocess.run(
110 ["ip", "link", "set", host_interface_name, "netns", host_namespace],
111 capture_output=True,
112 )
113 if process.returncode != 0:
114 print(f"Error setting host interface namespace: {process.stderr}")
115 sys.exit(1)
116
117 process = subprocess.run(
118 ["ip", "link", "set", "dev", vpp_interface_name, "up"], capture_output=True
119 )
120 if process.returncode != 0:
121 print(f"Error bringing up the host interface: {process.stderr}")
122 sys.exit(1)
123
124 process = subprocess.run(
125 [
126 "ip",
127 "netns",
128 "exec",
129 host_namespace,
130 "ip",
131 "link",
132 "set",
133 "dev",
134 host_interface_name,
135 "up",
136 ],
137 capture_output=True,
138 )
139 if process.returncode != 0:
140 print(
141 f"Error bringing up the host interface in namespace: "
142 f"{process.stderr}"
143 )
144 sys.exit(1)
145
146 for host_ip_prefix in host_ip_prefixes:
147 process = subprocess.run(
148 [
149 "ip",
150 "netns",
151 "exec",
152 host_namespace,
153 "ip",
154 "addr",
155 "add",
156 host_ip_prefix,
157 "dev",
158 host_interface_name,
159 ],
160 capture_output=True,
161 )
162 if process.returncode != 0:
163 print(
164 f"Error setting ip prefix on the host interface: "
165 f"{process.stderr}"
166 )
167 sys.exit(1)
168 except subprocess.CalledProcessError as e:
169 raise Exception("Error adding route to namespace:", e.output)
170
171
172def set_interface_mtu(namespace, interface, mtu, logger):
173 """set an mtu number on a linux device interface."""
174 args = ["ip", "link", "set", "mtu", str(mtu), "dev", interface]
175 if namespace:
176 args = ["ip", "netns", "exec", namespace] + args
177 try:
178 logger.debug(
179 f"Setting mtu:{mtu} on linux interface:{interface} "
180 f"in namespace:{namespace}"
181 )
182 subprocess.run(args)
183 except subprocess.CalledProcessError as e:
184 raise Exception("Error updating mtu:", e.output)
185
186
187def enable_interface_gso(namespace, interface):
188 """enable gso offload on a linux device interface."""
189 args = ["ethtool", "-K", interface, "rx", "on", "tx", "on"]
190 if namespace:
191 args = ["ip", "netns", "exec", namespace] + args
192 try:
193 process = subprocess.run(args, capture_output=True)
194 if process.returncode != 0:
195 print(
196 f"Error enabling GSO offload on linux device interface: "
197 f"{process.stderr}"
198 )
199 sys.exit(1)
200 except subprocess.CalledProcessError as e:
201 raise Exception("Error enabling gso:", e.output)
202
203
204def disable_interface_gso(namespace, interface):
205 """disable gso offload on a linux device interface."""
206 args = ["ethtool", "-K", interface, "rx", "off", "tx", "off"]
207 if namespace:
208 args = ["ip", "netns", "exec", namespace] + args
209 try:
210 process = subprocess.run(args, capture_output=True)
211 if process.returncode != 0:
212 print(
213 f"Error disabling GSO offload on linux device interface: "
214 f"{process.stderr}"
215 )
216 sys.exit(1)
217 except subprocess.CalledProcessError as e:
218 raise Exception("Error disabling gso:", e.output)
219
220
adrianvillin098ee3a2023-11-08 15:17:14 +0100221def delete_namespace(ns):
Naveen Joye4168932022-10-04 14:22:05 -0700222 """delete one or more namespaces.
223
224 arguments:
225 namespaces -- a list of namespace names
226 """
adrianvillin098ee3a2023-11-08 15:17:14 +0100227 if isinstance(ns, str):
228 namespaces = [ns]
229 else:
230 namespaces = ns
Naveen Joye4168932022-10-04 14:22:05 -0700231 try:
232 for namespace in namespaces:
Andrew Yourtchenko9ba6dcf2023-06-20 14:52:08 +0000233 result = subprocess.run(
234 ["ip", "netns", "del", namespace], capture_output=True
235 )
236 if result.returncode != 0:
237 raise Exception(f"Error while deleting namespace {namespace}")
Naveen Joye4168932022-10-04 14:22:05 -0700238 except subprocess.CalledProcessError as e:
239 raise Exception("Error deleting namespace:", e.output)
240
241
Naveen Joy7ea7ab52021-05-11 10:31:18 -0700242def list_namespace(ns):
243 """List the IP address of a namespace"""
244 try:
245 subprocess.run(["ip", "netns", "exec", ns, "ip", "addr"])
246 except subprocess.CalledProcessError as e:
247 raise Exception("Error listing namespace IP:", e.output)
Naveen Joy70335e82023-07-28 16:33:30 -0700248
249
250def libmemif_test_app(memif_sock_path, logger):
251 """Build & run the libmemif test_app for memif interface testing."""
252 test_dir = os.path.dirname(os.path.realpath(__file__))
253 ws_root = os.path.dirname(test_dir)
254 libmemif_app = os.path.join(
255 ws_root, "extras", "libmemif", "build", "examples", "test_app"
256 )
257
258 def build_libmemif_app():
259 if not os.path.exists(libmemif_app):
260 print(f"Building app:{libmemif_app} for memif interface testing")
261 libmemif_app_dir = os.path.join(ws_root, "extras", "libmemif", "build")
262 if not os.path.exists(libmemif_app_dir):
263 os.makedirs(libmemif_app_dir)
264 os.chdir(libmemif_app_dir)
265 try:
266 p = subprocess.run(["cmake", ".."], capture_output=True)
267 logger.debug(p.stdout)
268 if p.returncode != 0:
269 print(f"libmemif app:{libmemif_app} cmake error:{p.stderr}")
270 sys.exit(1)
271 p = subprocess.run(["make"], capture_output=True)
272 logger.debug(p.stdout)
273 if p.returncode != 0:
274 print(f"Error building libmemif app:{p.stderr}")
275 sys.exit(1)
276 except subprocess.CalledProcessError as e:
277 raise Exception("Error building libmemif_test_app:", e.output)
278
279 def start_libmemif_app():
280 """Restart once if the initial run fails."""
281 max_tries = 2
282 run = 0
283 if not os.path.exists(libmemif_app):
284 raise Exception(
285 f"Error could not locate the libmemif test app:{libmemif_app}"
286 )
287 args = [libmemif_app, "-b", "9216", "-s", memif_sock_path]
288 while run < max_tries:
289 try:
290 process = subprocess.run(args, capture_output=True)
291 logger.debug(process.stdout)
292 if process.returncode != 0:
293 msg = f"Error starting libmemif app:{libmemif_app}"
294 logger.error(msg)
295 raise Exception(msg)
296 except Exception:
297 msg = f"re-starting libmemif app:{libmemif_app}"
298 logger.error(msg)
299 continue
300 else:
301 break
302 finally:
303 run += 1
304
305 build_libmemif_app()
306 process = mp.Process(target=start_libmemif_app)
307 process.start()
308 return process