xref: /freebsd/tests/sys/netmap/ctrl-api-test.c (revision 0957b409)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (C) 2018 Vincenzo Maffione
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *   1. Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions and the following disclaimer.
11  *   2. Redistributions in binary form must reproduce the above copyright
12  *      notice, this list of conditions and the following disclaimer in the
13  *      documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29 
30 #include <sys/ioctl.h>
31 #include <sys/mman.h>
32 #include <sys/wait.h>
33 
34 #include <assert.h>
35 #include <ctype.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <inttypes.h>
39 #include <net/if.h>
40 #include <net/netmap.h>
41 #include <pthread.h>
42 #include <semaphore.h>
43 #include <stdint.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <time.h>
48 #include <unistd.h>
49 #include <signal.h>
50 
51 #ifdef __linux__
52 #include <sys/eventfd.h>
53 #else
54 static int
55 eventfd(int x __unused, int y __unused)
56 {
57 	errno = ENODEV;
58 	return -1;
59 }
60 #endif /* __linux__ */
61 
62 static int
63 exec_command(int argc, const char *const argv[])
64 {
65 	pid_t child_pid;
66 	pid_t wret;
67 	int child_status;
68 	int i;
69 
70 	printf("Executing command: ");
71 	for (i = 0; i < argc - 1; i++) {
72 		if (!argv[i]) {
73 			/* Invalid argument. */
74 			return -1;
75 		}
76 		if (i > 0) {
77 			putchar(' ');
78 		}
79 		printf("%s", argv[i]);
80 	}
81 	putchar('\n');
82 
83 	child_pid = fork();
84 	if (child_pid == 0) {
85 		char **av;
86 		int fds[3];
87 
88 		/* Child process. Redirect stdin, stdout
89 		 * and stderr. */
90 		for (i = 0; i < 3; i++) {
91 			close(i);
92 			fds[i] = open("/dev/null", O_RDONLY);
93 			if (fds[i] < 0) {
94 				for (i--; i >= 0; i--) {
95 					close(fds[i]);
96 				}
97 				return -1;
98 			}
99 		}
100 
101 		/* Make a copy of the arguments, passing them to execvp. */
102 		av = calloc(argc, sizeof(av[0]));
103 		if (!av) {
104 			exit(EXIT_FAILURE);
105 		}
106 		for (i = 0; i < argc - 1; i++) {
107 			av[i] = strdup(argv[i]);
108 			if (!av[i]) {
109 				exit(EXIT_FAILURE);
110 			}
111 		}
112 		execvp(av[0], av);
113 		perror("execvp()");
114 		exit(EXIT_FAILURE);
115 	}
116 
117 	wret = waitpid(child_pid, &child_status, 0);
118 	if (wret < 0) {
119 		fprintf(stderr, "waitpid() failed: %s\n", strerror(errno));
120 		return wret;
121 	}
122 	if (WIFEXITED(child_status)) {
123 		return WEXITSTATUS(child_status);
124 	}
125 
126 	return -1;
127 }
128 
129 
130 #define THRET_SUCCESS	((void *)128)
131 #define THRET_FAILURE	((void *)0)
132 
133 struct TestContext {
134 	char ifname[64];
135 	char ifname_ext[128];
136 	char bdgname[64];
137 	uint32_t nr_tx_slots;   /* slots in tx rings */
138 	uint32_t nr_rx_slots;   /* slots in rx rings */
139 	uint16_t nr_tx_rings;   /* number of tx rings */
140 	uint16_t nr_rx_rings;   /* number of rx rings */
141 	uint16_t nr_mem_id;     /* id of the memory allocator */
142 	uint16_t nr_ringid;     /* ring(s) we care about */
143 	uint32_t nr_mode;       /* specify NR_REG_* modes */
144 	uint32_t nr_extra_bufs; /* number of requested extra buffers */
145 	uint64_t nr_flags;      /* additional flags (see below) */
146 	uint32_t nr_hdr_len; /* for PORT_HDR_SET and PORT_HDR_GET */
147 	uint32_t nr_first_cpu_id;     /* vale polling */
148 	uint32_t nr_num_polling_cpus; /* vale polling */
149 	int fd; /* netmap file descriptor */
150 
151 	void *csb;                    /* CSB entries (atok and ktoa) */
152 	struct nmreq_option *nr_opt;  /* list of options */
153 	sem_t *sem;	/* for thread synchronization */
154 	struct nmport_d *nmport;      /* nmport descriptor from libnetmap */
155 };
156 
157 static struct TestContext ctx_;
158 
159 typedef int (*testfunc_t)(struct TestContext *ctx);
160 
161 static void
162 nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
163 {
164 	memset(hdr, 0, sizeof(*hdr));
165 	hdr->nr_version = NETMAP_API;
166 	strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name) - 1);
167 }
168 
169 /* Single NETMAP_REQ_PORT_INFO_GET. */
170 static int
171 port_info_get(struct TestContext *ctx)
172 {
173 	struct nmreq_port_info_get req;
174 	struct nmreq_header hdr;
175 	int success;
176 	int ret;
177 
178 	printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ctx->ifname_ext);
179 
180 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
181 	hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
182 	hdr.nr_body    = (uintptr_t)&req;
183 	memset(&req, 0, sizeof(req));
184 	req.nr_mem_id = ctx->nr_mem_id;
185 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
186 	if (ret != 0) {
187 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
188 		return ret;
189 	}
190 	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
191 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
192 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
193 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
194 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
195 	printf("nr_mem_id %u\n", req.nr_mem_id);
196 
197 	success = req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
198 	          req.nr_tx_rings && req.nr_rx_rings && req.nr_tx_rings;
199 	if (!success) {
200 		return -1;
201 	}
202 
203 	/* Write back results to the context structure. */
204 	ctx->nr_tx_slots = req.nr_tx_slots;
205 	ctx->nr_rx_slots = req.nr_rx_slots;
206 	ctx->nr_tx_rings = req.nr_tx_rings;
207 	ctx->nr_rx_rings = req.nr_rx_rings;
208 	ctx->nr_mem_id   = req.nr_mem_id;
209 
210 	return 0;
211 }
212 
213 /* Single NETMAP_REQ_REGISTER, no use. */
214 static int
215 port_register(struct TestContext *ctx)
216 {
217 	struct nmreq_register req;
218 	struct nmreq_header hdr;
219 	int success;
220 	int ret;
221 
222 	printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
223 	       "flags=0x%llx) on '%s'\n",
224 	       ctx->nr_mode, ctx->nr_ringid, (unsigned long long)ctx->nr_flags,
225 	       ctx->ifname_ext);
226 
227 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
228 	hdr.nr_reqtype = NETMAP_REQ_REGISTER;
229 	hdr.nr_body    = (uintptr_t)&req;
230 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
231 	memset(&req, 0, sizeof(req));
232 	req.nr_mem_id     = ctx->nr_mem_id;
233 	req.nr_mode       = ctx->nr_mode;
234 	req.nr_ringid     = ctx->nr_ringid;
235 	req.nr_flags      = ctx->nr_flags;
236 	req.nr_tx_slots   = ctx->nr_tx_slots;
237 	req.nr_rx_slots   = ctx->nr_rx_slots;
238 	req.nr_tx_rings   = ctx->nr_tx_rings;
239 	req.nr_rx_rings   = ctx->nr_rx_rings;
240 	req.nr_extra_bufs = ctx->nr_extra_bufs;
241 	ret               = ioctl(ctx->fd, NIOCCTRL, &hdr);
242 	if (ret != 0) {
243 		perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
244 		return ret;
245 	}
246 	printf("nr_offset 0x%llx\n", (unsigned long long)req.nr_offset);
247 	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
248 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
249 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
250 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
251 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
252 	printf("nr_mem_id %u\n", req.nr_mem_id);
253 	printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
254 
255 	success = req.nr_memsize && (ctx->nr_mode == req.nr_mode) &&
256 	                       (ctx->nr_ringid == req.nr_ringid) &&
257 	                       (ctx->nr_flags == req.nr_flags) &&
258 	                       ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
259 	                        (ctx->nr_tx_slots == req.nr_tx_slots)) &&
260 	                       ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
261 	                        (ctx->nr_rx_slots == req.nr_rx_slots)) &&
262 	                       ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
263 	                        (ctx->nr_tx_rings == req.nr_tx_rings)) &&
264 	                       ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
265 	                        (ctx->nr_rx_rings == req.nr_rx_rings)) &&
266 	                       ((!ctx->nr_mem_id && req.nr_mem_id) ||
267 	                        (ctx->nr_mem_id == req.nr_mem_id)) &&
268 	                       (ctx->nr_extra_bufs == req.nr_extra_bufs);
269 	if (!success) {
270 		return -1;
271 	}
272 
273 	/* Write back results to the context structure.*/
274 	ctx->nr_tx_slots   = req.nr_tx_slots;
275 	ctx->nr_rx_slots   = req.nr_rx_slots;
276 	ctx->nr_tx_rings   = req.nr_tx_rings;
277 	ctx->nr_rx_rings   = req.nr_rx_rings;
278 	ctx->nr_mem_id     = req.nr_mem_id;
279 	ctx->nr_extra_bufs = req.nr_extra_bufs;
280 
281 	return 0;
282 }
283 
284 static int
285 niocregif(struct TestContext *ctx, int netmap_api)
286 {
287 	struct nmreq req;
288 	int success;
289 	int ret;
290 
291 	printf("Testing legacy NIOCREGIF on '%s'\n", ctx->ifname_ext);
292 
293 	memset(&req, 0, sizeof(req));
294 	memcpy(req.nr_name, ctx->ifname_ext, sizeof(req.nr_name));
295 	req.nr_name[sizeof(req.nr_name) - 1] = '\0';
296 	req.nr_version = netmap_api;
297 	req.nr_ringid     = ctx->nr_ringid;
298 	req.nr_flags      = ctx->nr_mode | ctx->nr_flags;
299 	req.nr_tx_slots   = ctx->nr_tx_slots;
300 	req.nr_rx_slots   = ctx->nr_rx_slots;
301 	req.nr_tx_rings   = ctx->nr_tx_rings;
302 	req.nr_rx_rings   = ctx->nr_rx_rings;
303 	req.nr_arg2     = ctx->nr_mem_id;
304 	req.nr_arg3 = ctx->nr_extra_bufs;
305 
306 	ret = ioctl(ctx->fd, NIOCREGIF, &req);
307 	if (ret != 0) {
308 		perror("ioctl(/dev/netmap, NIOCREGIF)");
309 		return ret;
310 	}
311 
312 	printf("nr_offset 0x%x\n", req.nr_offset);
313 	printf("nr_memsize  %u\n", req.nr_memsize);
314 	printf("nr_tx_slots %u\n", req.nr_tx_slots);
315 	printf("nr_rx_slots %u\n", req.nr_rx_slots);
316 	printf("nr_tx_rings %u\n", req.nr_tx_rings);
317 	printf("nr_rx_rings %u\n", req.nr_rx_rings);
318 	printf("nr_version  %d\n", req.nr_version);
319 	printf("nr_ringid   %x\n", req.nr_ringid);
320 	printf("nr_flags    %x\n", req.nr_flags);
321 	printf("nr_arg2     %u\n", req.nr_arg2);
322 	printf("nr_arg3     %u\n", req.nr_arg3);
323 
324 	success = req.nr_memsize &&
325 	       (ctx->nr_ringid == req.nr_ringid) &&
326 	       ((ctx->nr_mode | ctx->nr_flags) == req.nr_flags) &&
327 	       ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
328 		(ctx->nr_tx_slots == req.nr_tx_slots)) &&
329 	       ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
330 		(ctx->nr_rx_slots == req.nr_rx_slots)) &&
331 	       ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
332 		(ctx->nr_tx_rings == req.nr_tx_rings)) &&
333 	       ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
334 		(ctx->nr_rx_rings == req.nr_rx_rings)) &&
335 	       ((!ctx->nr_mem_id && req.nr_arg2) ||
336 		(ctx->nr_mem_id == req.nr_arg2)) &&
337 	       (ctx->nr_extra_bufs == req.nr_arg3);
338 	if (!success) {
339 		return -1;
340 	}
341 
342 	/* Write back results to the context structure.*/
343 	ctx->nr_tx_slots   = req.nr_tx_slots;
344 	ctx->nr_rx_slots   = req.nr_rx_slots;
345 	ctx->nr_tx_rings   = req.nr_tx_rings;
346 	ctx->nr_rx_rings   = req.nr_rx_rings;
347 	ctx->nr_mem_id     = req.nr_arg2;
348 	ctx->nr_extra_bufs = req.nr_arg3;
349 
350 	return ret;
351 }
352 
353 /* The 11 ABI is the one right before the introduction of the new NIOCCTRL
354  * ABI. The 11 ABI is useful to perform tests with legacy applications
355  * (which use the 11 ABI) and new kernel (which uses 12, or higher). */
356 #define NETMAP_API_NIOCREGIF	11
357 
358 static int
359 legacy_regif_default(struct TestContext *ctx)
360 {
361 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
362 }
363 
364 static int
365 legacy_regif_all_nic(struct TestContext *ctx)
366 {
367 	ctx->nr_mode = NR_REG_ALL_NIC;
368 	return niocregif(ctx, NETMAP_API);
369 }
370 
371 static int
372 legacy_regif_12(struct TestContext *ctx)
373 {
374 	ctx->nr_mode = NR_REG_ALL_NIC;
375 	return niocregif(ctx, NETMAP_API_NIOCREGIF+1);
376 }
377 
378 static int
379 legacy_regif_sw(struct TestContext *ctx)
380 {
381 	ctx->nr_mode = NR_REG_SW;
382 	return niocregif(ctx,  NETMAP_API_NIOCREGIF);
383 }
384 
385 static int
386 legacy_regif_future(struct TestContext *ctx)
387 {
388 	ctx->nr_mode = NR_REG_NIC_SW;
389 	/* Test forward compatibility for the legacy ABI. This means
390 	 * using an older kernel (with ABI 12 or higher) and a newer
391 	 * application (with ABI greater than NETMAP_API). */
392 	return niocregif(ctx, NETMAP_API+2);
393 }
394 
395 static int
396 legacy_regif_extra_bufs(struct TestContext *ctx)
397 {
398 	ctx->nr_mode = NR_REG_ALL_NIC;
399 	ctx->nr_extra_bufs = 20;	/* arbitrary number of extra bufs */
400 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
401 }
402 
403 static int
404 legacy_regif_extra_bufs_pipe(struct TestContext *ctx)
405 {
406 	strncat(ctx->ifname_ext, "{pipeexbuf", sizeof(ctx->ifname_ext));
407 	ctx->nr_mode = NR_REG_ALL_NIC;
408 	ctx->nr_extra_bufs = 58;	/* arbitrary number of extra bufs */
409 
410 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
411 }
412 
413 static int
414 legacy_regif_extra_bufs_pipe_vale(struct TestContext *ctx)
415 {
416 	strncpy(ctx->ifname_ext, "valeX1:Y4", sizeof(ctx->ifname_ext));
417 	return legacy_regif_extra_bufs_pipe(ctx);
418 }
419 
420 /* Only valid after a successful port_register(). */
421 static int
422 num_registered_rings(struct TestContext *ctx)
423 {
424 	if (ctx->nr_flags & NR_TX_RINGS_ONLY) {
425 		return ctx->nr_tx_rings;
426 	}
427 	if (ctx->nr_flags & NR_RX_RINGS_ONLY) {
428 		return ctx->nr_rx_rings;
429 	}
430 
431 	return ctx->nr_tx_rings + ctx->nr_rx_rings;
432 }
433 
434 static int
435 port_register_hwall_host(struct TestContext *ctx)
436 {
437 	ctx->nr_mode = NR_REG_NIC_SW;
438 	return port_register(ctx);
439 }
440 
441 static int
442 port_register_host(struct TestContext *ctx)
443 {
444 	ctx->nr_mode = NR_REG_SW;
445 	return port_register(ctx);
446 }
447 
448 static int
449 port_register_hwall(struct TestContext *ctx)
450 {
451 	ctx->nr_mode = NR_REG_ALL_NIC;
452 	return port_register(ctx);
453 }
454 
455 static int
456 port_register_single_ring_couple(struct TestContext *ctx)
457 {
458 	ctx->nr_mode   = NR_REG_ONE_NIC;
459 	ctx->nr_ringid = 0;
460 	return port_register(ctx);
461 }
462 
463 static int
464 port_register_hwall_tx(struct TestContext *ctx)
465 {
466 	ctx->nr_mode = NR_REG_ALL_NIC;
467 	ctx->nr_flags |= NR_TX_RINGS_ONLY;
468 	return port_register(ctx);
469 }
470 
471 static int
472 port_register_hwall_rx(struct TestContext *ctx)
473 {
474 	ctx->nr_mode = NR_REG_ALL_NIC;
475 	ctx->nr_flags |= NR_RX_RINGS_ONLY;
476 	return port_register(ctx);
477 }
478 
479 /* NETMAP_REQ_VALE_ATTACH */
480 static int
481 vale_attach(struct TestContext *ctx)
482 {
483 	struct nmreq_vale_attach req;
484 	struct nmreq_header hdr;
485 	char vpname[sizeof(ctx->bdgname) + 1 + sizeof(ctx->ifname_ext)];
486 	int ret;
487 
488 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
489 
490 	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
491 	nmreq_hdr_init(&hdr, vpname);
492 	hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
493 	hdr.nr_body    = (uintptr_t)&req;
494 	memset(&req, 0, sizeof(req));
495 	req.reg.nr_mem_id = ctx->nr_mem_id;
496 	if (ctx->nr_mode == 0) {
497 		ctx->nr_mode = NR_REG_ALL_NIC; /* default */
498 	}
499 	req.reg.nr_mode = ctx->nr_mode;
500 	ret             = ioctl(ctx->fd, NIOCCTRL, &hdr);
501 	if (ret != 0) {
502 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
503 		return ret;
504 	}
505 	printf("nr_mem_id %u\n", req.reg.nr_mem_id);
506 
507 	return ((!ctx->nr_mem_id && req.reg.nr_mem_id > 1) ||
508 	        (ctx->nr_mem_id == req.reg.nr_mem_id)) &&
509 	                       (ctx->nr_flags == req.reg.nr_flags)
510 	               ? 0
511 	               : -1;
512 }
513 
514 /* NETMAP_REQ_VALE_DETACH */
515 static int
516 vale_detach(struct TestContext *ctx)
517 {
518 	struct nmreq_header hdr;
519 	struct nmreq_vale_detach req;
520 	char vpname[256];
521 	int ret;
522 
523 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
524 
525 	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
526 	nmreq_hdr_init(&hdr, vpname);
527 	hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
528 	hdr.nr_body    = (uintptr_t)&req;
529 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
530 	if (ret != 0) {
531 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
532 		return ret;
533 	}
534 
535 	return 0;
536 }
537 
538 /* First NETMAP_REQ_VALE_ATTACH, then NETMAP_REQ_VALE_DETACH. */
539 static int
540 vale_attach_detach(struct TestContext *ctx)
541 {
542 	int ret;
543 
544 	if ((ret = vale_attach(ctx)) != 0) {
545 		return ret;
546 	}
547 
548 	return vale_detach(ctx);
549 }
550 
551 static int
552 vale_attach_detach_host_rings(struct TestContext *ctx)
553 {
554 	ctx->nr_mode = NR_REG_NIC_SW;
555 	return vale_attach_detach(ctx);
556 }
557 
558 /* First NETMAP_REQ_PORT_HDR_SET and the NETMAP_REQ_PORT_HDR_GET
559  * to check that we get the same value. */
560 static int
561 port_hdr_set_and_get(struct TestContext *ctx)
562 {
563 	struct nmreq_port_hdr req;
564 	struct nmreq_header hdr;
565 	int ret;
566 
567 	printf("Testing NETMAP_REQ_PORT_HDR_SET on '%s'\n", ctx->ifname_ext);
568 
569 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
570 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
571 	hdr.nr_body    = (uintptr_t)&req;
572 	memset(&req, 0, sizeof(req));
573 	req.nr_hdr_len = ctx->nr_hdr_len;
574 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
575 	if (ret != 0) {
576 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
577 		return ret;
578 	}
579 
580 	if (req.nr_hdr_len != ctx->nr_hdr_len) {
581 		return -1;
582 	}
583 
584 	printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname_ext);
585 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
586 	req.nr_hdr_len = 0;
587 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
588 	if (ret != 0) {
589 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
590 		return ret;
591 	}
592 	printf("nr_hdr_len %u\n", req.nr_hdr_len);
593 
594 	return (req.nr_hdr_len == ctx->nr_hdr_len) ? 0 : -1;
595 }
596 
597 /*
598  * Possible lengths for the VirtIO network header, as specified by
599  * the standard:
600  *    http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html
601  */
602 #define VIRTIO_NET_HDR_LEN				10
603 #define VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS	12
604 
605 static int
606 vale_ephemeral_port_hdr_manipulation(struct TestContext *ctx)
607 {
608 	int ret;
609 
610 	strncpy(ctx->ifname_ext, "vale:eph0", sizeof(ctx->ifname_ext));
611 	ctx->nr_mode = NR_REG_ALL_NIC;
612 	if ((ret = port_register(ctx))) {
613 		return ret;
614 	}
615 	/* Try to set and get all the acceptable values. */
616 	ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS;
617 	if ((ret = port_hdr_set_and_get(ctx))) {
618 		return ret;
619 	}
620 	ctx->nr_hdr_len = 0;
621 	if ((ret = port_hdr_set_and_get(ctx))) {
622 		return ret;
623 	}
624 	ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN;
625 	if ((ret = port_hdr_set_and_get(ctx))) {
626 		return ret;
627 	}
628 	return 0;
629 }
630 
631 static int
632 vale_persistent_port(struct TestContext *ctx)
633 {
634 	struct nmreq_vale_newif req;
635 	struct nmreq_header hdr;
636 	int result;
637 	int ret;
638 
639 	strncpy(ctx->ifname_ext, "per4", sizeof(ctx->ifname_ext));
640 
641 	printf("Testing NETMAP_REQ_VALE_NEWIF on '%s'\n", ctx->ifname_ext);
642 
643 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
644 	hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
645 	hdr.nr_body    = (uintptr_t)&req;
646 	memset(&req, 0, sizeof(req));
647 	req.nr_mem_id   = ctx->nr_mem_id;
648 	req.nr_tx_slots = ctx->nr_tx_slots;
649 	req.nr_rx_slots = ctx->nr_rx_slots;
650 	req.nr_tx_rings = ctx->nr_tx_rings;
651 	req.nr_rx_rings = ctx->nr_rx_rings;
652 	ret             = ioctl(ctx->fd, NIOCCTRL, &hdr);
653 	if (ret != 0) {
654 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
655 		return ret;
656 	}
657 
658 	/* Attach the persistent VALE port to a switch and then detach. */
659 	result = vale_attach_detach(ctx);
660 
661 	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname_ext);
662 	hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
663 	hdr.nr_body    = (uintptr_t)NULL;
664 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
665 	if (ret != 0) {
666 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
667 		if (result == 0) {
668 			result = ret;
669 		}
670 	}
671 
672 	return result;
673 }
674 
675 /* Single NETMAP_REQ_POOLS_INFO_GET. */
676 static int
677 pools_info_get(struct TestContext *ctx)
678 {
679 	struct nmreq_pools_info req;
680 	struct nmreq_header hdr;
681 	int ret;
682 
683 	printf("Testing NETMAP_REQ_POOLS_INFO_GET on '%s'\n", ctx->ifname_ext);
684 
685 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
686 	hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
687 	hdr.nr_body    = (uintptr_t)&req;
688 	memset(&req, 0, sizeof(req));
689 	req.nr_mem_id = ctx->nr_mem_id;
690 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
691 	if (ret != 0) {
692 		perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
693 		return ret;
694 	}
695 	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
696 	printf("nr_mem_id %u\n", req.nr_mem_id);
697 	printf("nr_if_pool_offset 0x%llx\n",
698 		(unsigned long long)req.nr_if_pool_offset);
699 	printf("nr_if_pool_objtotal %u\n", req.nr_if_pool_objtotal);
700 	printf("nr_if_pool_objsize %u\n", req.nr_if_pool_objsize);
701 	printf("nr_ring_pool_offset 0x%llx\n",
702 		(unsigned long long)req.nr_if_pool_offset);
703 	printf("nr_ring_pool_objtotal %u\n", req.nr_ring_pool_objtotal);
704 	printf("nr_ring_pool_objsize %u\n", req.nr_ring_pool_objsize);
705 	printf("nr_buf_pool_offset 0x%llx\n",
706 		(unsigned long long)req.nr_buf_pool_offset);
707 	printf("nr_buf_pool_objtotal %u\n", req.nr_buf_pool_objtotal);
708 	printf("nr_buf_pool_objsize %u\n", req.nr_buf_pool_objsize);
709 
710 	return req.nr_memsize && req.nr_if_pool_objtotal &&
711 	                       req.nr_if_pool_objsize &&
712 	                       req.nr_ring_pool_objtotal &&
713 	                       req.nr_ring_pool_objsize &&
714 	                       req.nr_buf_pool_objtotal &&
715 	                       req.nr_buf_pool_objsize
716 	               ? 0
717 	               : -1;
718 }
719 
720 static int
721 pools_info_get_and_register(struct TestContext *ctx)
722 {
723 	int ret;
724 
725 	/* Check that we can get pools info before we register
726 	 * a netmap interface. */
727 	ret = pools_info_get(ctx);
728 	if (ret != 0) {
729 		return ret;
730 	}
731 
732 	ctx->nr_mode = NR_REG_ONE_NIC;
733 	ret          = port_register(ctx);
734 	if (ret != 0) {
735 		return ret;
736 	}
737 	ctx->nr_mem_id = 1;
738 
739 	/* Check that we can get pools info also after we register. */
740 	return pools_info_get(ctx);
741 }
742 
743 static int
744 pools_info_get_empty_ifname(struct TestContext *ctx)
745 {
746 	strncpy(ctx->ifname_ext, "", sizeof(ctx->ifname_ext));
747 	return pools_info_get(ctx) != 0 ? 0 : -1;
748 }
749 
750 static int
751 pipe_master(struct TestContext *ctx)
752 {
753 	strncat(ctx->ifname_ext, "{pipeid1", sizeof(ctx->ifname_ext));
754 	ctx->nr_mode = NR_REG_NIC_SW;
755 
756 	if (port_register(ctx) == 0) {
757 		printf("pipes should not accept NR_REG_NIC_SW\n");
758 		return -1;
759 	}
760 	ctx->nr_mode = NR_REG_ALL_NIC;
761 
762 	return port_register(ctx);
763 }
764 
765 static int
766 pipe_slave(struct TestContext *ctx)
767 {
768 	strncat(ctx->ifname_ext, "}pipeid2", sizeof(ctx->ifname_ext));
769 	ctx->nr_mode = NR_REG_ALL_NIC;
770 
771 	return port_register(ctx);
772 }
773 
774 /* Test PORT_INFO_GET and POOLS_INFO_GET on a pipe. This is useful to test the
775  * registration request used internall by netmap. */
776 static int
777 pipe_port_info_get(struct TestContext *ctx)
778 {
779 	strncat(ctx->ifname_ext, "}pipeid3", sizeof(ctx->ifname_ext));
780 
781 	return port_info_get(ctx);
782 }
783 
784 static int
785 pipe_pools_info_get(struct TestContext *ctx)
786 {
787 	strncat(ctx->ifname_ext, "{xid", sizeof(ctx->ifname_ext));
788 
789 	return pools_info_get(ctx);
790 }
791 
792 /* NETMAP_REQ_VALE_POLLING_ENABLE */
793 static int
794 vale_polling_enable(struct TestContext *ctx)
795 {
796 	struct nmreq_vale_polling req;
797 	struct nmreq_header hdr;
798 	char vpname[256];
799 	int ret;
800 
801 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
802 	printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", vpname);
803 
804 	nmreq_hdr_init(&hdr, vpname);
805 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
806 	hdr.nr_body    = (uintptr_t)&req;
807 	memset(&req, 0, sizeof(req));
808 	req.nr_mode             = ctx->nr_mode;
809 	req.nr_first_cpu_id     = ctx->nr_first_cpu_id;
810 	req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
811 	ret                     = ioctl(ctx->fd, NIOCCTRL, &hdr);
812 	if (ret != 0) {
813 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
814 		return ret;
815 	}
816 
817 	return (req.nr_mode == ctx->nr_mode &&
818 	        req.nr_first_cpu_id == ctx->nr_first_cpu_id &&
819 	        req.nr_num_polling_cpus == ctx->nr_num_polling_cpus)
820 	               ? 0
821 	               : -1;
822 }
823 
824 /* NETMAP_REQ_VALE_POLLING_DISABLE */
825 static int
826 vale_polling_disable(struct TestContext *ctx)
827 {
828 	struct nmreq_vale_polling req;
829 	struct nmreq_header hdr;
830 	char vpname[256];
831 	int ret;
832 
833 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
834 	printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", vpname);
835 
836 	nmreq_hdr_init(&hdr, vpname);
837 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
838 	hdr.nr_body    = (uintptr_t)&req;
839 	memset(&req, 0, sizeof(req));
840 	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
841 	if (ret != 0) {
842 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
843 		return ret;
844 	}
845 
846 	return 0;
847 }
848 
849 static int
850 vale_polling_enable_disable(struct TestContext *ctx)
851 {
852 	int ret = 0;
853 
854 	if ((ret = vale_attach(ctx)) != 0) {
855 		return ret;
856 	}
857 
858 	ctx->nr_mode             = NETMAP_POLLING_MODE_SINGLE_CPU;
859 	ctx->nr_num_polling_cpus = 1;
860 	ctx->nr_first_cpu_id     = 0;
861 	if ((ret = vale_polling_enable(ctx))) {
862 		vale_detach(ctx);
863 #ifdef __FreeBSD__
864 		/* NETMAP_REQ_VALE_POLLING_DISABLE is disabled on FreeBSD,
865 		 * because it is currently broken. We are happy to see that
866 		 * it fails. */
867 		return 0;
868 #else
869 		return ret;
870 #endif
871 	}
872 
873 	if ((ret = vale_polling_disable(ctx))) {
874 		vale_detach(ctx);
875 		return ret;
876 	}
877 
878 	return vale_detach(ctx);
879 }
880 
881 static void
882 push_option(struct nmreq_option *opt, struct TestContext *ctx)
883 {
884 	opt->nro_next = (uintptr_t)ctx->nr_opt;
885 	ctx->nr_opt   = opt;
886 }
887 
888 static void
889 clear_options(struct TestContext *ctx)
890 {
891 	ctx->nr_opt = NULL;
892 }
893 
894 static int
895 checkoption(struct nmreq_option *opt, struct nmreq_option *exp)
896 {
897 	if (opt->nro_next != exp->nro_next) {
898 		printf("nro_next %p expected %p\n",
899 		       (void *)(uintptr_t)opt->nro_next,
900 		       (void *)(uintptr_t)exp->nro_next);
901 		return -1;
902 	}
903 	if (opt->nro_reqtype != exp->nro_reqtype) {
904 		printf("nro_reqtype %u expected %u\n", opt->nro_reqtype,
905 		       exp->nro_reqtype);
906 		return -1;
907 	}
908 	if (opt->nro_status != exp->nro_status) {
909 		printf("nro_status %u expected %u\n", opt->nro_status,
910 		       exp->nro_status);
911 		return -1;
912 	}
913 	return 0;
914 }
915 
916 static int
917 unsupported_option(struct TestContext *ctx)
918 {
919 	struct nmreq_option opt, save;
920 
921 	printf("Testing unsupported option on %s\n", ctx->ifname_ext);
922 
923 	memset(&opt, 0, sizeof(opt));
924 	opt.nro_reqtype = 1234;
925 	push_option(&opt, ctx);
926 	save = opt;
927 
928 	if (port_register_hwall(ctx) >= 0)
929 		return -1;
930 
931 	clear_options(ctx);
932 	save.nro_status = EOPNOTSUPP;
933 	return checkoption(&opt, &save);
934 }
935 
936 static int
937 infinite_options(struct TestContext *ctx)
938 {
939 	struct nmreq_option opt;
940 
941 	printf("Testing infinite list of options on %s\n", ctx->ifname_ext);
942 
943 	opt.nro_reqtype = 1234;
944 	push_option(&opt, ctx);
945 	opt.nro_next = (uintptr_t)&opt;
946 	if (port_register_hwall(ctx) >= 0)
947 		return -1;
948 	clear_options(ctx);
949 	return (errno == EMSGSIZE ? 0 : -1);
950 }
951 
952 #ifdef CONFIG_NETMAP_EXTMEM
953 int
954 change_param(const char *pname, unsigned long newv, unsigned long *poldv)
955 {
956 #ifdef __linux__
957 	char param[256] = "/sys/module/netmap/parameters/";
958 	unsigned long oldv;
959 	FILE *f;
960 
961 	strncat(param, pname, sizeof(param) - 1);
962 
963 	f = fopen(param, "r+");
964 	if (f == NULL) {
965 		perror(param);
966 		return -1;
967 	}
968 	if (fscanf(f, "%ld", &oldv) != 1) {
969 		perror(param);
970 		fclose(f);
971 		return -1;
972 	}
973 	if (poldv)
974 		*poldv = oldv;
975 	rewind(f);
976 	if (fprintf(f, "%ld\n", newv) < 0) {
977 		perror(param);
978 		fclose(f);
979 		return -1;
980 	}
981 	fclose(f);
982 	printf("change_param: %s: %ld -> %ld\n", pname, oldv, newv);
983 #endif /* __linux__ */
984 	return 0;
985 }
986 
987 static int
988 push_extmem_option(struct TestContext *ctx, const struct nmreq_pools_info *pi,
989 		struct nmreq_opt_extmem *e)
990 {
991 	void *addr;
992 
993 	addr = mmap(NULL, pi->nr_memsize, PROT_READ | PROT_WRITE,
994 	            MAP_ANONYMOUS | MAP_SHARED, -1, 0);
995 	if (addr == MAP_FAILED) {
996 		perror("mmap");
997 		return -1;
998 	}
999 
1000 	memset(e, 0, sizeof(*e));
1001 	e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
1002 	e->nro_info = *pi;
1003 	e->nro_usrptr          = (uintptr_t)addr;
1004 
1005 	push_option(&e->nro_opt, ctx);
1006 
1007 	return 0;
1008 }
1009 
1010 static int
1011 pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
1012 {
1013 	struct nmreq_opt_extmem *e;
1014 	int ret;
1015 
1016 	e           = (struct nmreq_opt_extmem *)(uintptr_t)ctx->nr_opt;
1017 	ctx->nr_opt = (struct nmreq_option *)(uintptr_t)ctx->nr_opt->nro_next;
1018 
1019 	if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
1020 		return ret;
1021 	}
1022 
1023 	if (e->nro_usrptr != exp->nro_usrptr) {
1024 		printf("usrptr %" PRIu64 " expected %" PRIu64 "\n",
1025 		       e->nro_usrptr, exp->nro_usrptr);
1026 		return -1;
1027 	}
1028 	if (e->nro_info.nr_memsize != exp->nro_info.nr_memsize) {
1029 		printf("memsize %" PRIu64 " expected %" PRIu64 "\n",
1030 		       e->nro_info.nr_memsize, exp->nro_info.nr_memsize);
1031 		return -1;
1032 	}
1033 
1034 	if ((ret = munmap((void *)(uintptr_t)e->nro_usrptr,
1035 	                  e->nro_info.nr_memsize)))
1036 		return ret;
1037 
1038 	return 0;
1039 }
1040 
1041 static int
1042 _extmem_option(struct TestContext *ctx,
1043 		const struct nmreq_pools_info *pi)
1044 {
1045 	struct nmreq_opt_extmem e, save;
1046 	int ret;
1047 
1048 	if ((ret = push_extmem_option(ctx, pi, &e)) < 0)
1049 		return ret;
1050 
1051 	save = e;
1052 
1053 	strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
1054 	ctx->nr_tx_slots = 16;
1055 	ctx->nr_rx_slots = 16;
1056 
1057 	if ((ret = port_register_hwall(ctx)))
1058 		return ret;
1059 
1060 	ret = pop_extmem_option(ctx, &save);
1061 
1062 	return ret;
1063 }
1064 
1065 static size_t
1066 pools_info_min_memsize(const struct nmreq_pools_info *pi)
1067 {
1068 	size_t tot = 0;
1069 
1070 	tot += pi->nr_if_pool_objtotal * pi->nr_if_pool_objsize;
1071 	tot += pi->nr_ring_pool_objtotal * pi->nr_ring_pool_objsize;
1072 	tot += pi->nr_buf_pool_objtotal * pi->nr_buf_pool_objsize;
1073 
1074 	return tot;
1075 }
1076 
1077 /*
1078  * Fill the specification of a netmap memory allocator to be
1079  * used with the 'struct nmreq_opt_extmem' option. Arbitrary
1080  * values are used for the parameters, but with enough netmap
1081  * rings, netmap ifs, and buffers to support a VALE port.
1082  */
1083 static void
1084 pools_info_fill(struct nmreq_pools_info *pi)
1085 {
1086 	pi->nr_if_pool_objtotal = 2;
1087 	pi->nr_if_pool_objsize = 1024;
1088 	pi->nr_ring_pool_objtotal = 64;
1089 	pi->nr_ring_pool_objsize = 512;
1090 	pi->nr_buf_pool_objtotal = 4096;
1091 	pi->nr_buf_pool_objsize = 2048;
1092 	pi->nr_memsize = pools_info_min_memsize(pi);
1093 }
1094 
1095 static int
1096 extmem_option(struct TestContext *ctx)
1097 {
1098 	struct nmreq_pools_info	pools_info;
1099 
1100 	pools_info_fill(&pools_info);
1101 
1102 	printf("Testing extmem option on vale0:0\n");
1103 	return _extmem_option(ctx, &pools_info);
1104 }
1105 
1106 static int
1107 bad_extmem_option(struct TestContext *ctx)
1108 {
1109 	struct nmreq_pools_info	pools_info;
1110 
1111 	printf("Testing bad extmem option on vale0:0\n");
1112 
1113 	pools_info_fill(&pools_info);
1114 	/* Request a large ring size, to make sure that the kernel
1115 	 * rejects our request. */
1116 	pools_info.nr_ring_pool_objsize = (1 << 16);
1117 
1118 	return _extmem_option(ctx, &pools_info) < 0 ? 0 : -1;
1119 }
1120 
1121 static int
1122 duplicate_extmem_options(struct TestContext *ctx)
1123 {
1124 	struct nmreq_opt_extmem e1, save1, e2, save2;
1125 	struct nmreq_pools_info	pools_info;
1126 	int ret;
1127 
1128 	printf("Testing duplicate extmem option on vale0:0\n");
1129 
1130 	pools_info_fill(&pools_info);
1131 
1132 	if ((ret = push_extmem_option(ctx, &pools_info, &e1)) < 0)
1133 		return ret;
1134 
1135 	if ((ret = push_extmem_option(ctx, &pools_info, &e2)) < 0) {
1136 		clear_options(ctx);
1137 		return ret;
1138 	}
1139 
1140 	save1 = e1;
1141 	save2 = e2;
1142 
1143 	ret = port_register_hwall(ctx);
1144 	if (ret >= 0) {
1145 		printf("duplicate option not detected\n");
1146 		return -1;
1147 	}
1148 
1149 	save2.nro_opt.nro_status = EINVAL;
1150 	if ((ret = pop_extmem_option(ctx, &save2)))
1151 		return ret;
1152 
1153 	save1.nro_opt.nro_status = EINVAL;
1154 	if ((ret = pop_extmem_option(ctx, &save1)))
1155 		return ret;
1156 
1157 	return 0;
1158 }
1159 #endif /* CONFIG_NETMAP_EXTMEM */
1160 
1161 static int
1162 push_csb_option(struct TestContext *ctx, struct nmreq_opt_csb *opt)
1163 {
1164 	size_t csb_size;
1165 	int num_entries;
1166 	int ret;
1167 
1168 	ctx->nr_flags |= NR_EXCLUSIVE;
1169 
1170 	/* Get port info in order to use num_registered_rings(). */
1171 	ret = port_info_get(ctx);
1172 	if (ret != 0) {
1173 		return ret;
1174 	}
1175 	num_entries = num_registered_rings(ctx);
1176 
1177 	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
1178 	           num_entries;
1179 	assert(csb_size > 0);
1180 	if (ctx->csb) {
1181 		free(ctx->csb);
1182 	}
1183 	ret = posix_memalign(&ctx->csb, sizeof(struct nm_csb_atok), csb_size);
1184 	if (ret != 0) {
1185 		printf("Failed to allocate CSB memory\n");
1186 		exit(EXIT_FAILURE);
1187 	}
1188 
1189 	memset(opt, 0, sizeof(*opt));
1190 	opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
1191 	opt->csb_atok            = (uintptr_t)ctx->csb;
1192 	opt->csb_ktoa            = (uintptr_t)(((uint8_t *)ctx->csb) +
1193                                     sizeof(struct nm_csb_atok) * num_entries);
1194 
1195 	printf("Pushing option NETMAP_REQ_OPT_CSB\n");
1196 	push_option(&opt->nro_opt, ctx);
1197 
1198 	return 0;
1199 }
1200 
1201 static int
1202 csb_mode(struct TestContext *ctx)
1203 {
1204 	struct nmreq_opt_csb opt;
1205 	int ret;
1206 
1207 	ret = push_csb_option(ctx, &opt);
1208 	if (ret != 0) {
1209 		return ret;
1210 	}
1211 
1212 	ret = port_register_hwall(ctx);
1213 	clear_options(ctx);
1214 
1215 	return ret;
1216 }
1217 
1218 static int
1219 csb_mode_invalid_memory(struct TestContext *ctx)
1220 {
1221 	struct nmreq_opt_csb opt;
1222 	int ret;
1223 
1224 	memset(&opt, 0, sizeof(opt));
1225 	opt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
1226 	opt.csb_atok            = (uintptr_t)0x10;
1227 	opt.csb_ktoa            = (uintptr_t)0x800;
1228 	push_option(&opt.nro_opt, ctx);
1229 
1230 	ctx->nr_flags = NR_EXCLUSIVE;
1231 	ret           = port_register_hwall(ctx);
1232 	clear_options(ctx);
1233 
1234 	return (ret < 0) ? 0 : -1;
1235 }
1236 
1237 static int
1238 sync_kloop_stop(struct TestContext *ctx)
1239 {
1240 	struct nmreq_header hdr;
1241 	int ret;
1242 
1243 	printf("Testing NETMAP_REQ_SYNC_KLOOP_STOP on '%s'\n", ctx->ifname_ext);
1244 
1245 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
1246 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
1247 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
1248 	if (ret != 0) {
1249 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
1250 	}
1251 
1252 	return ret;
1253 }
1254 
1255 static void *
1256 sync_kloop_worker(void *opaque)
1257 {
1258 	struct TestContext *ctx = opaque;
1259 	struct nmreq_sync_kloop_start req;
1260 	struct nmreq_header hdr;
1261 	int ret;
1262 
1263 	printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname_ext);
1264 
1265 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
1266 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
1267 	hdr.nr_body    = (uintptr_t)&req;
1268 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
1269 	memset(&req, 0, sizeof(req));
1270 	req.sleep_us = 500;
1271 	ret          = ioctl(ctx->fd, NIOCCTRL, &hdr);
1272 	if (ret != 0) {
1273 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
1274 	}
1275 
1276 	if (ctx->sem) {
1277 		sem_post(ctx->sem);
1278 	}
1279 
1280 	pthread_exit(ret ? (void *)THRET_FAILURE : (void *)THRET_SUCCESS);
1281 }
1282 
1283 static int
1284 sync_kloop_start_stop(struct TestContext *ctx)
1285 {
1286 	pthread_t th;
1287 	void *thret = THRET_FAILURE;
1288 	int ret;
1289 
1290 	ret = pthread_create(&th, NULL, sync_kloop_worker, ctx);
1291 	if (ret != 0) {
1292 		printf("pthread_create(kloop): %s\n", strerror(ret));
1293 		return -1;
1294 	}
1295 
1296 	ret = sync_kloop_stop(ctx);
1297 	if (ret != 0) {
1298 		return ret;
1299 	}
1300 
1301 	ret = pthread_join(th, &thret);
1302 	if (ret != 0) {
1303 		printf("pthread_join(kloop): %s\n", strerror(ret));
1304 	}
1305 
1306 	return thret == THRET_SUCCESS ? 0 : -1;
1307 }
1308 
1309 static int
1310 sync_kloop(struct TestContext *ctx)
1311 {
1312 	int ret;
1313 
1314 	ret = csb_mode(ctx);
1315 	if (ret != 0) {
1316 		return ret;
1317 	}
1318 
1319 	return sync_kloop_start_stop(ctx);
1320 }
1321 
1322 static int
1323 sync_kloop_eventfds(struct TestContext *ctx)
1324 {
1325 	struct nmreq_opt_sync_kloop_eventfds *opt = NULL;
1326 	struct nmreq_option save;
1327 	int num_entries;
1328 	size_t opt_size;
1329 	int ret, i;
1330 
1331 	num_entries = num_registered_rings(ctx);
1332 	opt_size    = sizeof(*opt) + num_entries * sizeof(opt->eventfds[0]);
1333 	opt = calloc(1, opt_size);
1334 	opt->nro_opt.nro_next    = 0;
1335 	opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
1336 	opt->nro_opt.nro_status  = 0;
1337 	opt->nro_opt.nro_size    = opt_size;
1338 	for (i = 0; i < num_entries; i++) {
1339 		int efd = eventfd(0, 0);
1340 
1341 		opt->eventfds[i].ioeventfd = efd;
1342 		efd                        = eventfd(0, 0);
1343 		opt->eventfds[i].irqfd = efd;
1344 	}
1345 
1346 	push_option(&opt->nro_opt, ctx);
1347 	save = opt->nro_opt;
1348 
1349 	ret = sync_kloop_start_stop(ctx);
1350 	if (ret != 0) {
1351 		free(opt);
1352 		clear_options(ctx);
1353 		return ret;
1354 	}
1355 #ifdef __linux__
1356 	save.nro_status = 0;
1357 #else  /* !__linux__ */
1358 	save.nro_status = EOPNOTSUPP;
1359 #endif /* !__linux__ */
1360 
1361 	ret = checkoption(&opt->nro_opt, &save);
1362 	free(opt);
1363 	clear_options(ctx);
1364 
1365 	return ret;
1366 }
1367 
1368 static int
1369 sync_kloop_eventfds_all(struct TestContext *ctx)
1370 {
1371 	int ret;
1372 
1373 	ret = csb_mode(ctx);
1374 	if (ret != 0) {
1375 		return ret;
1376 	}
1377 
1378 	return sync_kloop_eventfds(ctx);
1379 }
1380 
1381 static int
1382 sync_kloop_eventfds_all_tx(struct TestContext *ctx)
1383 {
1384 	struct nmreq_opt_csb opt;
1385 	int ret;
1386 
1387 	ret = push_csb_option(ctx, &opt);
1388 	if (ret != 0) {
1389 		return ret;
1390 	}
1391 
1392 	ret = port_register_hwall_tx(ctx);
1393 	if (ret != 0) {
1394 		return ret;
1395 	}
1396 	clear_options(ctx);
1397 
1398 	return sync_kloop_eventfds(ctx);
1399 }
1400 
1401 static int
1402 sync_kloop_nocsb(struct TestContext *ctx)
1403 {
1404 	int ret;
1405 
1406 	ret = port_register_hwall(ctx);
1407 	if (ret != 0) {
1408 		return ret;
1409 	}
1410 
1411 	/* Sync kloop must fail because we did not use
1412 	 * NETMAP_REQ_CSB_ENABLE. */
1413 	return sync_kloop_start_stop(ctx) != 0 ? 0 : -1;
1414 }
1415 
1416 static int
1417 csb_enable(struct TestContext *ctx)
1418 {
1419 	struct nmreq_option saveopt;
1420 	struct nmreq_opt_csb opt;
1421 	struct nmreq_header hdr;
1422 	int ret;
1423 
1424 	ret = push_csb_option(ctx, &opt);
1425 	if (ret != 0) {
1426 		return ret;
1427 	}
1428 	saveopt = opt.nro_opt;
1429 	saveopt.nro_status = 0;
1430 
1431 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
1432 	hdr.nr_reqtype = NETMAP_REQ_CSB_ENABLE;
1433 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
1434 	hdr.nr_body = (uintptr_t)NULL;
1435 
1436 	printf("Testing NETMAP_REQ_CSB_ENABLE on '%s'\n", ctx->ifname_ext);
1437 
1438 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
1439 	if (ret != 0) {
1440 		perror("ioctl(/dev/netmap, NIOCCTRL, CSB_ENABLE)");
1441 		return ret;
1442 	}
1443 
1444 	ret = checkoption(&opt.nro_opt, &saveopt);
1445 	clear_options(ctx);
1446 
1447 	return ret;
1448 }
1449 
1450 static int
1451 sync_kloop_csb_enable(struct TestContext *ctx)
1452 {
1453 	int ret;
1454 
1455 	ctx->nr_flags |= NR_EXCLUSIVE;
1456 	ret = port_register_hwall(ctx);
1457 	if (ret != 0) {
1458 		return ret;
1459 	}
1460 
1461 	ret = csb_enable(ctx);
1462 	if (ret != 0) {
1463 		return ret;
1464 	}
1465 
1466 	return sync_kloop_start_stop(ctx);
1467 }
1468 
1469 static int
1470 sync_kloop_conflict(struct TestContext *ctx)
1471 {
1472 	struct nmreq_opt_csb opt;
1473 	pthread_t th1, th2;
1474 	void *thret1 = THRET_FAILURE, *thret2 = THRET_FAILURE;
1475 	struct timespec to;
1476 	sem_t sem;
1477 	int err = 0;
1478 	int ret;
1479 
1480 	ret = push_csb_option(ctx, &opt);
1481 	if (ret != 0) {
1482 		return ret;
1483 	}
1484 
1485 	ret = port_register_hwall(ctx);
1486 	if (ret != 0) {
1487 		return ret;
1488 	}
1489 	clear_options(ctx);
1490 
1491 	ret = sem_init(&sem, 0, 0);
1492 	if (ret != 0) {
1493 		printf("sem_init() failed: %s\n", strerror(ret));
1494 		return ret;
1495 	}
1496 	ctx->sem = &sem;
1497 
1498 	ret = pthread_create(&th1, NULL, sync_kloop_worker, ctx);
1499 	err |= ret;
1500 	if (ret != 0) {
1501 		printf("pthread_create(kloop1): %s\n", strerror(ret));
1502 	}
1503 
1504 	ret = pthread_create(&th2, NULL, sync_kloop_worker, ctx);
1505 	err |= ret;
1506 	if (ret != 0) {
1507 		printf("pthread_create(kloop2): %s\n", strerror(ret));
1508 	}
1509 
1510 	/* Wait for one of the two threads to fail to start the kloop, to
1511 	 * avoid a race condition where th1 starts the loop and stops,
1512 	 * and after that th2 starts the loop successfully. */
1513 	clock_gettime(CLOCK_REALTIME, &to);
1514 	to.tv_sec += 2;
1515 	ret = sem_timedwait(&sem, &to);
1516 	err |= ret;
1517 	if (ret != 0) {
1518 		printf("sem_timedwait() failed: %s\n", strerror(errno));
1519 	}
1520 
1521 	err |= sync_kloop_stop(ctx);
1522 
1523 	ret = pthread_join(th1, &thret1);
1524 	err |= ret;
1525 	if (ret != 0) {
1526 		printf("pthread_join(kloop1): %s\n", strerror(ret));
1527 	}
1528 
1529 	ret = pthread_join(th2, &thret2);
1530 	err |= ret;
1531 	if (ret != 0) {
1532 		printf("pthread_join(kloop2): %s %d\n", strerror(ret), ret);
1533 	}
1534 
1535 	sem_destroy(&sem);
1536 	ctx->sem = NULL;
1537 	if (err) {
1538 		return err;
1539 	}
1540 
1541 	/* Check that one of the two failed, while the other one succeeded. */
1542 	return ((thret1 == THRET_SUCCESS && thret2 == THRET_FAILURE) ||
1543 			(thret1 == THRET_FAILURE && thret2 == THRET_SUCCESS))
1544 	               ? 0
1545 	               : -1;
1546 }
1547 
1548 static int
1549 sync_kloop_eventfds_mismatch(struct TestContext *ctx)
1550 {
1551 	struct nmreq_opt_csb opt;
1552 	int ret;
1553 
1554 	ret = push_csb_option(ctx, &opt);
1555 	if (ret != 0) {
1556 		return ret;
1557 	}
1558 
1559 	ret = port_register_hwall_rx(ctx);
1560 	if (ret != 0) {
1561 		return ret;
1562 	}
1563 	clear_options(ctx);
1564 
1565 	/* Deceive num_registered_rings() to trigger a failure of
1566 	 * sync_kloop_eventfds(). The latter will think that all the
1567 	 * rings were registered, and allocate the wrong number of
1568 	 * eventfds. */
1569 	ctx->nr_flags &= ~NR_RX_RINGS_ONLY;
1570 
1571 	return (sync_kloop_eventfds(ctx) != 0) ? 0 : -1;
1572 }
1573 
1574 static int
1575 null_port(struct TestContext *ctx)
1576 {
1577 	int ret;
1578 
1579 	ctx->nr_mem_id = 1;
1580 	ctx->nr_mode = NR_REG_NULL;
1581 	ctx->nr_tx_rings = 10;
1582 	ctx->nr_rx_rings = 5;
1583 	ctx->nr_tx_slots = 256;
1584 	ctx->nr_rx_slots = 100;
1585 	ret = port_register(ctx);
1586 	if (ret != 0) {
1587 		return ret;
1588 	}
1589 	return 0;
1590 }
1591 
1592 static int
1593 null_port_all_zero(struct TestContext *ctx)
1594 {
1595 	int ret;
1596 
1597 	ctx->nr_mem_id = 1;
1598 	ctx->nr_mode = NR_REG_NULL;
1599 	ctx->nr_tx_rings = 0;
1600 	ctx->nr_rx_rings = 0;
1601 	ctx->nr_tx_slots = 0;
1602 	ctx->nr_rx_slots = 0;
1603 	ret = port_register(ctx);
1604 	if (ret != 0) {
1605 		return ret;
1606 	}
1607 	return 0;
1608 }
1609 
1610 static int
1611 null_port_sync(struct TestContext *ctx)
1612 {
1613 	int ret;
1614 
1615 	ctx->nr_mem_id = 1;
1616 	ctx->nr_mode = NR_REG_NULL;
1617 	ctx->nr_tx_rings = 10;
1618 	ctx->nr_rx_rings = 5;
1619 	ctx->nr_tx_slots = 256;
1620 	ctx->nr_rx_slots = 100;
1621 	ret = port_register(ctx);
1622 	if (ret != 0) {
1623 		return ret;
1624 	}
1625 	ret = ioctl(ctx->fd, NIOCTXSYNC, 0);
1626 	if (ret != 0) {
1627 		return ret;
1628 	}
1629 	return 0;
1630 }
1631 
1632 static void
1633 usage(const char *prog)
1634 {
1635 	printf("%s -i IFNAME\n"
1636 	       "[-j TEST_NUM1[-[TEST_NUM2]] | -[TEST_NUM_2]]\n"
1637 	       "[-l (list test cases)]\n",
1638 	       prog);
1639 }
1640 
1641 struct mytest {
1642 	testfunc_t test;
1643 	const char *name;
1644 };
1645 
1646 #define decltest(f)                                                            \
1647 	{                                                                      \
1648 		.test = f, .name = #f                                          \
1649 	}
1650 
1651 static struct mytest tests[] = {
1652 	decltest(port_info_get),
1653 	decltest(port_register_hwall_host),
1654 	decltest(port_register_hwall),
1655 	decltest(port_register_host),
1656 	decltest(port_register_single_ring_couple),
1657 	decltest(vale_attach_detach),
1658 	decltest(vale_attach_detach_host_rings),
1659 	decltest(vale_ephemeral_port_hdr_manipulation),
1660 	decltest(vale_persistent_port),
1661 	decltest(pools_info_get_and_register),
1662 	decltest(pools_info_get_empty_ifname),
1663 	decltest(pipe_master),
1664 	decltest(pipe_slave),
1665 	decltest(pipe_port_info_get),
1666 	decltest(pipe_pools_info_get),
1667 	decltest(vale_polling_enable_disable),
1668 	decltest(unsupported_option),
1669 	decltest(infinite_options),
1670 #ifdef CONFIG_NETMAP_EXTMEM
1671 	decltest(extmem_option),
1672 	decltest(bad_extmem_option),
1673 	decltest(duplicate_extmem_options),
1674 #endif /* CONFIG_NETMAP_EXTMEM */
1675 	decltest(csb_mode),
1676 	decltest(csb_mode_invalid_memory),
1677 	decltest(sync_kloop),
1678 	decltest(sync_kloop_eventfds_all),
1679 	decltest(sync_kloop_eventfds_all_tx),
1680 	decltest(sync_kloop_nocsb),
1681 	decltest(sync_kloop_csb_enable),
1682 	decltest(sync_kloop_conflict),
1683 	decltest(sync_kloop_eventfds_mismatch),
1684 	decltest(null_port),
1685 	decltest(null_port_all_zero),
1686 	decltest(null_port_sync),
1687 	decltest(legacy_regif_default),
1688 	decltest(legacy_regif_all_nic),
1689 	decltest(legacy_regif_12),
1690 	decltest(legacy_regif_sw),
1691 	decltest(legacy_regif_future),
1692 	decltest(legacy_regif_extra_bufs),
1693 	decltest(legacy_regif_extra_bufs_pipe),
1694 	decltest(legacy_regif_extra_bufs_pipe_vale),
1695 };
1696 
1697 static void
1698 context_cleanup(struct TestContext *ctx)
1699 {
1700 	if (ctx->csb) {
1701 		free(ctx->csb);
1702 		ctx->csb = NULL;
1703 	}
1704 
1705 	close(ctx->fd);
1706 	ctx->fd = -1;
1707 }
1708 
1709 static int
1710 parse_interval(const char *arg, int *j, int *k)
1711 {
1712 	const char *scan = arg;
1713 	char *rest;
1714 
1715 	*j = 0;
1716 	*k = -1;
1717 	if (*scan == '-') {
1718 		scan++;
1719 		goto get_k;
1720 	}
1721 	if (!isdigit(*scan))
1722 		goto err;
1723 	*k = strtol(scan, &rest, 10);
1724 	*j = *k - 1;
1725 	scan = rest;
1726 	if (*scan == '-') {
1727 		*k = -1;
1728 		scan++;
1729 	}
1730 get_k:
1731 	if (*scan == '\0')
1732 		return 0;
1733 	if (!isdigit(*scan))
1734 		goto err;
1735 	*k = strtol(scan, &rest, 10);
1736 	scan = rest;
1737 	if (!(*scan == '\0'))
1738 		goto err;
1739 
1740 	return 0;
1741 
1742 err:
1743 	fprintf(stderr, "syntax error in '%s', must be num[-[num]] or -[num]\n", arg);
1744 	return -1;
1745 }
1746 
1747 #define ARGV_APPEND(_av, _ac, _x)\
1748 	do {\
1749 		assert((int)(_ac) < (int)(sizeof(_av)/sizeof((_av)[0])));\
1750 		(_av)[(_ac)++] = _x;\
1751 	} while (0)
1752 
1753 static void
1754 tap_cleanup(int signo)
1755 {
1756 	const char *av[8];
1757 	int ac = 0;
1758 
1759 	(void)signo;
1760 #ifdef __FreeBSD__
1761 	ARGV_APPEND(av, ac, "ifconfig");
1762 	ARGV_APPEND(av, ac, ctx_.ifname);
1763 	ARGV_APPEND(av, ac, "destroy");
1764 #else
1765 	ARGV_APPEND(av, ac, "ip");
1766 	ARGV_APPEND(av, ac, "link");
1767 	ARGV_APPEND(av, ac, "del");
1768 	ARGV_APPEND(av, ac, ctx_.ifname);
1769 #endif
1770 	ARGV_APPEND(av, ac, NULL);
1771 	if (exec_command(ac, av)) {
1772 		printf("Failed to destroy tap interface\n");
1773 	}
1774 }
1775 
1776 int
1777 main(int argc, char **argv)
1778 {
1779 	int create_tap = 1;
1780 	int num_tests;
1781 	int ret  = 0;
1782 	int j    = 0;
1783 	int k    = -1;
1784 	int list = 0;
1785 	int opt;
1786 	int i;
1787 
1788 	memset(&ctx_, 0, sizeof(ctx_));
1789 
1790 	{
1791 		struct timespec t;
1792 		int idx;
1793 
1794 		clock_gettime(CLOCK_REALTIME, &t);
1795 		srand((unsigned int)t.tv_nsec);
1796 		idx = rand() % 8000 + 100;
1797 		snprintf(ctx_.ifname, sizeof(ctx_.ifname), "tap%d", idx);
1798 		idx = rand() % 800 + 100;
1799 		snprintf(ctx_.bdgname, sizeof(ctx_.bdgname), "vale%d", idx);
1800 	}
1801 
1802 	while ((opt = getopt(argc, argv, "hi:j:l")) != -1) {
1803 		switch (opt) {
1804 		case 'h':
1805 			usage(argv[0]);
1806 			return 0;
1807 
1808 		case 'i':
1809 			strncpy(ctx_.ifname, optarg, sizeof(ctx_.ifname) - 1);
1810 			create_tap = 0;
1811 			break;
1812 
1813 		case 'j':
1814 			if (parse_interval(optarg, &j, &k) < 0) {
1815 				usage(argv[0]);
1816 				return -1;
1817 			}
1818 			break;
1819 
1820 		case 'l':
1821 			list = 1;
1822 			create_tap = 0;
1823 			break;
1824 
1825 		default:
1826 			printf("    Unrecognized option %c\n", opt);
1827 			usage(argv[0]);
1828 			return -1;
1829 		}
1830 	}
1831 
1832 	num_tests = sizeof(tests) / sizeof(tests[0]);
1833 
1834 	if (j < 0 || j >= num_tests || k > num_tests) {
1835 		fprintf(stderr, "Test interval %d-%d out of range (%d-%d)\n",
1836 				j + 1, k, 1, num_tests + 1);
1837 		return -1;
1838 	}
1839 
1840 	if (k < 0)
1841 		k = num_tests;
1842 
1843 	if (list) {
1844 		printf("Available tests:\n");
1845 		for (i = 0; i < num_tests; i++) {
1846 			printf("#%03d: %s\n", i + 1, tests[i].name);
1847 		}
1848 		return 0;
1849 	}
1850 
1851 	if (create_tap) {
1852 		struct sigaction sa;
1853 		const char *av[8];
1854 		int ac = 0;
1855 #ifdef __FreeBSD__
1856 		ARGV_APPEND(av, ac, "ifconfig");
1857 		ARGV_APPEND(av, ac, ctx_.ifname);
1858 		ARGV_APPEND(av, ac, "create");
1859 		ARGV_APPEND(av, ac, "up");
1860 #else
1861 		ARGV_APPEND(av, ac, "ip");
1862 		ARGV_APPEND(av, ac, "tuntap");
1863 		ARGV_APPEND(av, ac, "add");
1864 		ARGV_APPEND(av, ac, "mode");
1865 		ARGV_APPEND(av, ac, "tap");
1866 		ARGV_APPEND(av, ac, "name");
1867 		ARGV_APPEND(av, ac, ctx_.ifname);
1868 #endif
1869 		ARGV_APPEND(av, ac, NULL);
1870 		if (exec_command(ac, av)) {
1871 			printf("Failed to create tap interface\n");
1872 			return -1;
1873 		}
1874 
1875 		sa.sa_handler = tap_cleanup;
1876 		sigemptyset(&sa.sa_mask);
1877 		sa.sa_flags = SA_RESTART;
1878 		ret         = sigaction(SIGINT, &sa, NULL);
1879 		if (ret) {
1880 			perror("sigaction(SIGINT)");
1881 			goto out;
1882 		}
1883 		ret = sigaction(SIGTERM, &sa, NULL);
1884 		if (ret) {
1885 			perror("sigaction(SIGTERM)");
1886 			goto out;
1887 		}
1888 	}
1889 
1890 	for (i = j; i < k; i++) {
1891 		struct TestContext ctxcopy;
1892 		int fd;
1893 		printf("==> Start of Test #%d [%s]\n", i + 1, tests[i].name);
1894 		fd = open("/dev/netmap", O_RDWR);
1895 		if (fd < 0) {
1896 			perror("open(/dev/netmap)");
1897 			ret = fd;
1898 			goto out;
1899 		}
1900 		memcpy(&ctxcopy, &ctx_, sizeof(ctxcopy));
1901 		ctxcopy.fd = fd;
1902 		memcpy(ctxcopy.ifname_ext, ctxcopy.ifname,
1903 			sizeof(ctxcopy.ifname));
1904 		ret        = tests[i].test(&ctxcopy);
1905 		if (ret != 0) {
1906 			printf("Test #%d [%s] failed\n", i + 1, tests[i].name);
1907 			goto out;
1908 		}
1909 		printf("==> Test #%d [%s] successful\n", i + 1, tests[i].name);
1910 		context_cleanup(&ctxcopy);
1911 	}
1912 out:
1913 	tap_cleanup(0);
1914 
1915 	return ret;
1916 }
1917