xref: /freebsd/tests/sys/netmap/ctrl-api-test.c (revision 123af6ec70016f5556da5972d4d63c7d175c06d3)
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 	uint32_t sync_kloop_mode; /* sync-kloop */
150 	int fd; /* netmap file descriptor */
151 
152 	void *csb;                    /* CSB entries (atok and ktoa) */
153 	struct nmreq_option *nr_opt;  /* list of options */
154 	sem_t *sem;	/* for thread synchronization */
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  * However, version 14 introduced a change in the layout of struct netmap_if,
357  * so that binary backward compatibility to 11 is not supported anymore.
358  */
359 #define NETMAP_API_NIOCREGIF	14
360 
361 static int
362 legacy_regif_default(struct TestContext *ctx)
363 {
364 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
365 }
366 
367 static int
368 legacy_regif_all_nic(struct TestContext *ctx)
369 {
370 	ctx->nr_mode = NR_REG_ALL_NIC;
371 	return niocregif(ctx, NETMAP_API);
372 }
373 
374 static int
375 legacy_regif_12(struct TestContext *ctx)
376 {
377 	ctx->nr_mode = NR_REG_ALL_NIC;
378 	return niocregif(ctx, NETMAP_API_NIOCREGIF+1);
379 }
380 
381 static int
382 legacy_regif_sw(struct TestContext *ctx)
383 {
384 	ctx->nr_mode = NR_REG_SW;
385 	return niocregif(ctx,  NETMAP_API_NIOCREGIF);
386 }
387 
388 static int
389 legacy_regif_future(struct TestContext *ctx)
390 {
391 	ctx->nr_mode = NR_REG_NIC_SW;
392 	/* Test forward compatibility for the legacy ABI. This means
393 	 * using an older kernel (with ABI 12 or higher) and a newer
394 	 * application (with ABI greater than NETMAP_API). */
395 	return niocregif(ctx, NETMAP_API+2);
396 }
397 
398 static int
399 legacy_regif_extra_bufs(struct TestContext *ctx)
400 {
401 	ctx->nr_mode = NR_REG_ALL_NIC;
402 	ctx->nr_extra_bufs = 20;	/* arbitrary number of extra bufs */
403 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
404 }
405 
406 static int
407 legacy_regif_extra_bufs_pipe(struct TestContext *ctx)
408 {
409 	strncat(ctx->ifname_ext, "{pipeexbuf", sizeof(ctx->ifname_ext));
410 	ctx->nr_mode = NR_REG_ALL_NIC;
411 	ctx->nr_extra_bufs = 58;	/* arbitrary number of extra bufs */
412 
413 	return niocregif(ctx, NETMAP_API_NIOCREGIF);
414 }
415 
416 static int
417 legacy_regif_extra_bufs_pipe_vale(struct TestContext *ctx)
418 {
419 	strncpy(ctx->ifname_ext, "valeX1:Y4", sizeof(ctx->ifname_ext));
420 	return legacy_regif_extra_bufs_pipe(ctx);
421 }
422 
423 /* Only valid after a successful port_register(). */
424 static int
425 num_registered_rings(struct TestContext *ctx)
426 {
427 	if (ctx->nr_flags & NR_TX_RINGS_ONLY) {
428 		return ctx->nr_tx_rings;
429 	}
430 	if (ctx->nr_flags & NR_RX_RINGS_ONLY) {
431 		return ctx->nr_rx_rings;
432 	}
433 
434 	return ctx->nr_tx_rings + ctx->nr_rx_rings;
435 }
436 
437 static int
438 port_register_hwall_host(struct TestContext *ctx)
439 {
440 	ctx->nr_mode = NR_REG_NIC_SW;
441 	return port_register(ctx);
442 }
443 
444 static int
445 port_register_host(struct TestContext *ctx)
446 {
447 	ctx->nr_mode = NR_REG_SW;
448 	return port_register(ctx);
449 }
450 
451 static int
452 port_register_hwall(struct TestContext *ctx)
453 {
454 	ctx->nr_mode = NR_REG_ALL_NIC;
455 	return port_register(ctx);
456 }
457 
458 static int
459 port_register_single_ring_couple(struct TestContext *ctx)
460 {
461 	ctx->nr_mode   = NR_REG_ONE_NIC;
462 	ctx->nr_ringid = 0;
463 	return port_register(ctx);
464 }
465 
466 static int
467 port_register_hwall_tx(struct TestContext *ctx)
468 {
469 	ctx->nr_mode = NR_REG_ALL_NIC;
470 	ctx->nr_flags |= NR_TX_RINGS_ONLY;
471 	return port_register(ctx);
472 }
473 
474 static int
475 port_register_hwall_rx(struct TestContext *ctx)
476 {
477 	ctx->nr_mode = NR_REG_ALL_NIC;
478 	ctx->nr_flags |= NR_RX_RINGS_ONLY;
479 	return port_register(ctx);
480 }
481 
482 /* NETMAP_REQ_VALE_ATTACH */
483 static int
484 vale_attach(struct TestContext *ctx)
485 {
486 	struct nmreq_vale_attach req;
487 	struct nmreq_header hdr;
488 	char vpname[sizeof(ctx->bdgname) + 1 + sizeof(ctx->ifname_ext)];
489 	int ret;
490 
491 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
492 
493 	printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
494 	nmreq_hdr_init(&hdr, vpname);
495 	hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
496 	hdr.nr_body    = (uintptr_t)&req;
497 	memset(&req, 0, sizeof(req));
498 	req.reg.nr_mem_id = ctx->nr_mem_id;
499 	if (ctx->nr_mode == 0) {
500 		ctx->nr_mode = NR_REG_ALL_NIC; /* default */
501 	}
502 	req.reg.nr_mode = ctx->nr_mode;
503 	ret             = ioctl(ctx->fd, NIOCCTRL, &hdr);
504 	if (ret != 0) {
505 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
506 		return ret;
507 	}
508 	printf("nr_mem_id %u\n", req.reg.nr_mem_id);
509 
510 	return ((!ctx->nr_mem_id && req.reg.nr_mem_id > 1) ||
511 	        (ctx->nr_mem_id == req.reg.nr_mem_id)) &&
512 	                       (ctx->nr_flags == req.reg.nr_flags)
513 	               ? 0
514 	               : -1;
515 }
516 
517 /* NETMAP_REQ_VALE_DETACH */
518 static int
519 vale_detach(struct TestContext *ctx)
520 {
521 	struct nmreq_header hdr;
522 	struct nmreq_vale_detach req;
523 	char vpname[256];
524 	int ret;
525 
526 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
527 
528 	printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
529 	nmreq_hdr_init(&hdr, vpname);
530 	hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
531 	hdr.nr_body    = (uintptr_t)&req;
532 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
533 	if (ret != 0) {
534 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
535 		return ret;
536 	}
537 
538 	return 0;
539 }
540 
541 /* First NETMAP_REQ_VALE_ATTACH, then NETMAP_REQ_VALE_DETACH. */
542 static int
543 vale_attach_detach(struct TestContext *ctx)
544 {
545 	int ret;
546 
547 	if ((ret = vale_attach(ctx)) != 0) {
548 		return ret;
549 	}
550 
551 	return vale_detach(ctx);
552 }
553 
554 static int
555 vale_attach_detach_host_rings(struct TestContext *ctx)
556 {
557 	ctx->nr_mode = NR_REG_NIC_SW;
558 	return vale_attach_detach(ctx);
559 }
560 
561 /* First NETMAP_REQ_PORT_HDR_SET and the NETMAP_REQ_PORT_HDR_GET
562  * to check that we get the same value. */
563 static int
564 port_hdr_set_and_get(struct TestContext *ctx)
565 {
566 	struct nmreq_port_hdr req;
567 	struct nmreq_header hdr;
568 	int ret;
569 
570 	printf("Testing NETMAP_REQ_PORT_HDR_SET on '%s'\n", ctx->ifname_ext);
571 
572 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
573 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
574 	hdr.nr_body    = (uintptr_t)&req;
575 	memset(&req, 0, sizeof(req));
576 	req.nr_hdr_len = ctx->nr_hdr_len;
577 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
578 	if (ret != 0) {
579 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
580 		return ret;
581 	}
582 
583 	if (req.nr_hdr_len != ctx->nr_hdr_len) {
584 		return -1;
585 	}
586 
587 	printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname_ext);
588 	hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
589 	req.nr_hdr_len = 0;
590 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
591 	if (ret != 0) {
592 		perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
593 		return ret;
594 	}
595 	printf("nr_hdr_len %u\n", req.nr_hdr_len);
596 
597 	return (req.nr_hdr_len == ctx->nr_hdr_len) ? 0 : -1;
598 }
599 
600 /*
601  * Possible lengths for the VirtIO network header, as specified by
602  * the standard:
603  *    http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html
604  */
605 #define VIRTIO_NET_HDR_LEN				10
606 #define VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS	12
607 
608 static int
609 vale_ephemeral_port_hdr_manipulation(struct TestContext *ctx)
610 {
611 	int ret;
612 
613 	strncpy(ctx->ifname_ext, "vale:eph0", sizeof(ctx->ifname_ext));
614 	ctx->nr_mode = NR_REG_ALL_NIC;
615 	if ((ret = port_register(ctx))) {
616 		return ret;
617 	}
618 	/* Try to set and get all the acceptable values. */
619 	ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS;
620 	if ((ret = port_hdr_set_and_get(ctx))) {
621 		return ret;
622 	}
623 	ctx->nr_hdr_len = 0;
624 	if ((ret = port_hdr_set_and_get(ctx))) {
625 		return ret;
626 	}
627 	ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN;
628 	if ((ret = port_hdr_set_and_get(ctx))) {
629 		return ret;
630 	}
631 	return 0;
632 }
633 
634 static int
635 vale_persistent_port(struct TestContext *ctx)
636 {
637 	struct nmreq_vale_newif req;
638 	struct nmreq_header hdr;
639 	int result;
640 	int ret;
641 
642 	strncpy(ctx->ifname_ext, "per4", sizeof(ctx->ifname_ext));
643 
644 	printf("Testing NETMAP_REQ_VALE_NEWIF on '%s'\n", ctx->ifname_ext);
645 
646 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
647 	hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
648 	hdr.nr_body    = (uintptr_t)&req;
649 	memset(&req, 0, sizeof(req));
650 	req.nr_mem_id   = ctx->nr_mem_id;
651 	req.nr_tx_slots = ctx->nr_tx_slots;
652 	req.nr_rx_slots = ctx->nr_rx_slots;
653 	req.nr_tx_rings = ctx->nr_tx_rings;
654 	req.nr_rx_rings = ctx->nr_rx_rings;
655 	ret             = ioctl(ctx->fd, NIOCCTRL, &hdr);
656 	if (ret != 0) {
657 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
658 		return ret;
659 	}
660 
661 	/* Attach the persistent VALE port to a switch and then detach. */
662 	result = vale_attach_detach(ctx);
663 
664 	printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname_ext);
665 	hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
666 	hdr.nr_body    = (uintptr_t)NULL;
667 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
668 	if (ret != 0) {
669 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
670 		if (result == 0) {
671 			result = ret;
672 		}
673 	}
674 
675 	return result;
676 }
677 
678 /* Single NETMAP_REQ_POOLS_INFO_GET. */
679 static int
680 pools_info_get(struct TestContext *ctx)
681 {
682 	struct nmreq_pools_info req;
683 	struct nmreq_header hdr;
684 	int ret;
685 
686 	printf("Testing NETMAP_REQ_POOLS_INFO_GET on '%s'\n", ctx->ifname_ext);
687 
688 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
689 	hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
690 	hdr.nr_body    = (uintptr_t)&req;
691 	memset(&req, 0, sizeof(req));
692 	req.nr_mem_id = ctx->nr_mem_id;
693 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
694 	if (ret != 0) {
695 		perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
696 		return ret;
697 	}
698 	printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
699 	printf("nr_mem_id %u\n", req.nr_mem_id);
700 	printf("nr_if_pool_offset 0x%llx\n",
701 		(unsigned long long)req.nr_if_pool_offset);
702 	printf("nr_if_pool_objtotal %u\n", req.nr_if_pool_objtotal);
703 	printf("nr_if_pool_objsize %u\n", req.nr_if_pool_objsize);
704 	printf("nr_ring_pool_offset 0x%llx\n",
705 		(unsigned long long)req.nr_if_pool_offset);
706 	printf("nr_ring_pool_objtotal %u\n", req.nr_ring_pool_objtotal);
707 	printf("nr_ring_pool_objsize %u\n", req.nr_ring_pool_objsize);
708 	printf("nr_buf_pool_offset 0x%llx\n",
709 		(unsigned long long)req.nr_buf_pool_offset);
710 	printf("nr_buf_pool_objtotal %u\n", req.nr_buf_pool_objtotal);
711 	printf("nr_buf_pool_objsize %u\n", req.nr_buf_pool_objsize);
712 
713 	return req.nr_memsize && req.nr_if_pool_objtotal &&
714 	                       req.nr_if_pool_objsize &&
715 	                       req.nr_ring_pool_objtotal &&
716 	                       req.nr_ring_pool_objsize &&
717 	                       req.nr_buf_pool_objtotal &&
718 	                       req.nr_buf_pool_objsize
719 	               ? 0
720 	               : -1;
721 }
722 
723 static int
724 pools_info_get_and_register(struct TestContext *ctx)
725 {
726 	int ret;
727 
728 	/* Check that we can get pools info before we register
729 	 * a netmap interface. */
730 	ret = pools_info_get(ctx);
731 	if (ret != 0) {
732 		return ret;
733 	}
734 
735 	ctx->nr_mode = NR_REG_ONE_NIC;
736 	ret          = port_register(ctx);
737 	if (ret != 0) {
738 		return ret;
739 	}
740 	ctx->nr_mem_id = 1;
741 
742 	/* Check that we can get pools info also after we register. */
743 	return pools_info_get(ctx);
744 }
745 
746 static int
747 pools_info_get_empty_ifname(struct TestContext *ctx)
748 {
749 	strncpy(ctx->ifname_ext, "", sizeof(ctx->ifname_ext));
750 	return pools_info_get(ctx) != 0 ? 0 : -1;
751 }
752 
753 static int
754 pipe_master(struct TestContext *ctx)
755 {
756 	strncat(ctx->ifname_ext, "{pipeid1", sizeof(ctx->ifname_ext));
757 	ctx->nr_mode = NR_REG_NIC_SW;
758 
759 	if (port_register(ctx) == 0) {
760 		printf("pipes should not accept NR_REG_NIC_SW\n");
761 		return -1;
762 	}
763 	ctx->nr_mode = NR_REG_ALL_NIC;
764 
765 	return port_register(ctx);
766 }
767 
768 static int
769 pipe_slave(struct TestContext *ctx)
770 {
771 	strncat(ctx->ifname_ext, "}pipeid2", sizeof(ctx->ifname_ext));
772 	ctx->nr_mode = NR_REG_ALL_NIC;
773 
774 	return port_register(ctx);
775 }
776 
777 /* Test PORT_INFO_GET and POOLS_INFO_GET on a pipe. This is useful to test the
778  * registration request used internall by netmap. */
779 static int
780 pipe_port_info_get(struct TestContext *ctx)
781 {
782 	strncat(ctx->ifname_ext, "}pipeid3", sizeof(ctx->ifname_ext));
783 
784 	return port_info_get(ctx);
785 }
786 
787 static int
788 pipe_pools_info_get(struct TestContext *ctx)
789 {
790 	strncat(ctx->ifname_ext, "{xid", sizeof(ctx->ifname_ext));
791 
792 	return pools_info_get(ctx);
793 }
794 
795 /* NETMAP_REQ_VALE_POLLING_ENABLE */
796 static int
797 vale_polling_enable(struct TestContext *ctx)
798 {
799 	struct nmreq_vale_polling req;
800 	struct nmreq_header hdr;
801 	char vpname[256];
802 	int ret;
803 
804 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
805 	printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", vpname);
806 
807 	nmreq_hdr_init(&hdr, vpname);
808 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
809 	hdr.nr_body    = (uintptr_t)&req;
810 	memset(&req, 0, sizeof(req));
811 	req.nr_mode             = ctx->nr_mode;
812 	req.nr_first_cpu_id     = ctx->nr_first_cpu_id;
813 	req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
814 	ret                     = ioctl(ctx->fd, NIOCCTRL, &hdr);
815 	if (ret != 0) {
816 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
817 		return ret;
818 	}
819 
820 	return (req.nr_mode == ctx->nr_mode &&
821 	        req.nr_first_cpu_id == ctx->nr_first_cpu_id &&
822 	        req.nr_num_polling_cpus == ctx->nr_num_polling_cpus)
823 	               ? 0
824 	               : -1;
825 }
826 
827 /* NETMAP_REQ_VALE_POLLING_DISABLE */
828 static int
829 vale_polling_disable(struct TestContext *ctx)
830 {
831 	struct nmreq_vale_polling req;
832 	struct nmreq_header hdr;
833 	char vpname[256];
834 	int ret;
835 
836 	snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname_ext);
837 	printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", vpname);
838 
839 	nmreq_hdr_init(&hdr, vpname);
840 	hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
841 	hdr.nr_body    = (uintptr_t)&req;
842 	memset(&req, 0, sizeof(req));
843 	ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
844 	if (ret != 0) {
845 		perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
846 		return ret;
847 	}
848 
849 	return 0;
850 }
851 
852 static int
853 vale_polling_enable_disable(struct TestContext *ctx)
854 {
855 	int ret = 0;
856 
857 	if ((ret = vale_attach(ctx)) != 0) {
858 		return ret;
859 	}
860 
861 	ctx->nr_mode             = NETMAP_POLLING_MODE_SINGLE_CPU;
862 	ctx->nr_num_polling_cpus = 1;
863 	ctx->nr_first_cpu_id     = 0;
864 	if ((ret = vale_polling_enable(ctx))) {
865 		vale_detach(ctx);
866 #ifdef __FreeBSD__
867 		/* NETMAP_REQ_VALE_POLLING_DISABLE is disabled on FreeBSD,
868 		 * because it is currently broken. We are happy to see that
869 		 * it fails. */
870 		return 0;
871 #else
872 		return ret;
873 #endif
874 	}
875 
876 	if ((ret = vale_polling_disable(ctx))) {
877 		vale_detach(ctx);
878 		return ret;
879 	}
880 
881 	return vale_detach(ctx);
882 }
883 
884 static void
885 push_option(struct nmreq_option *opt, struct TestContext *ctx)
886 {
887 	opt->nro_next = (uintptr_t)ctx->nr_opt;
888 	ctx->nr_opt   = opt;
889 }
890 
891 static void
892 clear_options(struct TestContext *ctx)
893 {
894 	ctx->nr_opt = NULL;
895 }
896 
897 static int
898 checkoption(struct nmreq_option *opt, struct nmreq_option *exp)
899 {
900 	if (opt->nro_next != exp->nro_next) {
901 		printf("nro_next %p expected %p\n",
902 		       (void *)(uintptr_t)opt->nro_next,
903 		       (void *)(uintptr_t)exp->nro_next);
904 		return -1;
905 	}
906 	if (opt->nro_reqtype != exp->nro_reqtype) {
907 		printf("nro_reqtype %u expected %u\n", opt->nro_reqtype,
908 		       exp->nro_reqtype);
909 		return -1;
910 	}
911 	if (opt->nro_status != exp->nro_status) {
912 		printf("nro_status %u expected %u\n", opt->nro_status,
913 		       exp->nro_status);
914 		return -1;
915 	}
916 	return 0;
917 }
918 
919 static int
920 unsupported_option(struct TestContext *ctx)
921 {
922 	struct nmreq_option opt, save;
923 
924 	printf("Testing unsupported option on %s\n", ctx->ifname_ext);
925 
926 	memset(&opt, 0, sizeof(opt));
927 	opt.nro_reqtype = 1234;
928 	push_option(&opt, ctx);
929 	save = opt;
930 
931 	if (port_register_hwall(ctx) >= 0)
932 		return -1;
933 
934 	clear_options(ctx);
935 	save.nro_status = EOPNOTSUPP;
936 	return checkoption(&opt, &save);
937 }
938 
939 static int
940 infinite_options(struct TestContext *ctx)
941 {
942 	struct nmreq_option opt;
943 
944 	printf("Testing infinite list of options on %s\n", ctx->ifname_ext);
945 
946 	opt.nro_reqtype = 1234;
947 	push_option(&opt, ctx);
948 	opt.nro_next = (uintptr_t)&opt;
949 	if (port_register_hwall(ctx) >= 0)
950 		return -1;
951 	clear_options(ctx);
952 	return (errno == EMSGSIZE ? 0 : -1);
953 }
954 
955 #ifdef CONFIG_NETMAP_EXTMEM
956 int
957 change_param(const char *pname, unsigned long newv, unsigned long *poldv)
958 {
959 #ifdef __linux__
960 	char param[256] = "/sys/module/netmap/parameters/";
961 	unsigned long oldv;
962 	FILE *f;
963 
964 	strncat(param, pname, sizeof(param) - 1);
965 
966 	f = fopen(param, "r+");
967 	if (f == NULL) {
968 		perror(param);
969 		return -1;
970 	}
971 	if (fscanf(f, "%ld", &oldv) != 1) {
972 		perror(param);
973 		fclose(f);
974 		return -1;
975 	}
976 	if (poldv)
977 		*poldv = oldv;
978 	rewind(f);
979 	if (fprintf(f, "%ld\n", newv) < 0) {
980 		perror(param);
981 		fclose(f);
982 		return -1;
983 	}
984 	fclose(f);
985 	printf("change_param: %s: %ld -> %ld\n", pname, oldv, newv);
986 #endif /* __linux__ */
987 	return 0;
988 }
989 
990 static int
991 push_extmem_option(struct TestContext *ctx, const struct nmreq_pools_info *pi,
992 		struct nmreq_opt_extmem *e)
993 {
994 	void *addr;
995 
996 	addr = mmap(NULL, pi->nr_memsize, PROT_READ | PROT_WRITE,
997 	            MAP_ANONYMOUS | MAP_SHARED, -1, 0);
998 	if (addr == MAP_FAILED) {
999 		perror("mmap");
1000 		return -1;
1001 	}
1002 
1003 	memset(e, 0, sizeof(*e));
1004 	e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
1005 	e->nro_info = *pi;
1006 	e->nro_usrptr          = (uintptr_t)addr;
1007 
1008 	push_option(&e->nro_opt, ctx);
1009 
1010 	return 0;
1011 }
1012 
1013 static int
1014 pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
1015 {
1016 	struct nmreq_opt_extmem *e;
1017 	int ret;
1018 
1019 	e           = (struct nmreq_opt_extmem *)(uintptr_t)ctx->nr_opt;
1020 	ctx->nr_opt = (struct nmreq_option *)(uintptr_t)ctx->nr_opt->nro_next;
1021 
1022 	if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
1023 		return ret;
1024 	}
1025 
1026 	if (e->nro_usrptr != exp->nro_usrptr) {
1027 		printf("usrptr %" PRIu64 " expected %" PRIu64 "\n",
1028 		       e->nro_usrptr, exp->nro_usrptr);
1029 		return -1;
1030 	}
1031 	if (e->nro_info.nr_memsize != exp->nro_info.nr_memsize) {
1032 		printf("memsize %" PRIu64 " expected %" PRIu64 "\n",
1033 		       e->nro_info.nr_memsize, exp->nro_info.nr_memsize);
1034 		return -1;
1035 	}
1036 
1037 	if ((ret = munmap((void *)(uintptr_t)e->nro_usrptr,
1038 	                  e->nro_info.nr_memsize)))
1039 		return ret;
1040 
1041 	return 0;
1042 }
1043 
1044 static int
1045 _extmem_option(struct TestContext *ctx,
1046 		const struct nmreq_pools_info *pi)
1047 {
1048 	struct nmreq_opt_extmem e, save;
1049 	int ret;
1050 
1051 	if ((ret = push_extmem_option(ctx, pi, &e)) < 0)
1052 		return ret;
1053 
1054 	save = e;
1055 
1056 	strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
1057 	ctx->nr_tx_slots = 16;
1058 	ctx->nr_rx_slots = 16;
1059 
1060 	if ((ret = port_register_hwall(ctx)))
1061 		return ret;
1062 
1063 	ret = pop_extmem_option(ctx, &save);
1064 
1065 	return ret;
1066 }
1067 
1068 static size_t
1069 pools_info_min_memsize(const struct nmreq_pools_info *pi)
1070 {
1071 	size_t tot = 0;
1072 
1073 	tot += pi->nr_if_pool_objtotal * pi->nr_if_pool_objsize;
1074 	tot += pi->nr_ring_pool_objtotal * pi->nr_ring_pool_objsize;
1075 	tot += pi->nr_buf_pool_objtotal * pi->nr_buf_pool_objsize;
1076 
1077 	return tot;
1078 }
1079 
1080 /*
1081  * Fill the specification of a netmap memory allocator to be
1082  * used with the 'struct nmreq_opt_extmem' option. Arbitrary
1083  * values are used for the parameters, but with enough netmap
1084  * rings, netmap ifs, and buffers to support a VALE port.
1085  */
1086 static void
1087 pools_info_fill(struct nmreq_pools_info *pi)
1088 {
1089 	pi->nr_if_pool_objtotal = 2;
1090 	pi->nr_if_pool_objsize = 1024;
1091 	pi->nr_ring_pool_objtotal = 64;
1092 	pi->nr_ring_pool_objsize = 512;
1093 	pi->nr_buf_pool_objtotal = 4096;
1094 	pi->nr_buf_pool_objsize = 2048;
1095 	pi->nr_memsize = pools_info_min_memsize(pi);
1096 }
1097 
1098 static int
1099 extmem_option(struct TestContext *ctx)
1100 {
1101 	struct nmreq_pools_info	pools_info;
1102 
1103 	pools_info_fill(&pools_info);
1104 
1105 	printf("Testing extmem option on vale0:0\n");
1106 	return _extmem_option(ctx, &pools_info);
1107 }
1108 
1109 static int
1110 bad_extmem_option(struct TestContext *ctx)
1111 {
1112 	struct nmreq_pools_info	pools_info;
1113 
1114 	printf("Testing bad extmem option on vale0:0\n");
1115 
1116 	pools_info_fill(&pools_info);
1117 	/* Request a large ring size, to make sure that the kernel
1118 	 * rejects our request. */
1119 	pools_info.nr_ring_pool_objsize = (1 << 20);
1120 
1121 	return _extmem_option(ctx, &pools_info) < 0 ? 0 : -1;
1122 }
1123 
1124 static int
1125 duplicate_extmem_options(struct TestContext *ctx)
1126 {
1127 	struct nmreq_opt_extmem e1, save1, e2, save2;
1128 	struct nmreq_pools_info	pools_info;
1129 	int ret;
1130 
1131 	printf("Testing duplicate extmem option on vale0:0\n");
1132 
1133 	pools_info_fill(&pools_info);
1134 
1135 	if ((ret = push_extmem_option(ctx, &pools_info, &e1)) < 0)
1136 		return ret;
1137 
1138 	if ((ret = push_extmem_option(ctx, &pools_info, &e2)) < 0) {
1139 		clear_options(ctx);
1140 		return ret;
1141 	}
1142 
1143 	save1 = e1;
1144 	save2 = e2;
1145 
1146 	strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
1147 	ctx->nr_tx_slots = 16;
1148 	ctx->nr_rx_slots = 16;
1149 
1150 	ret = port_register_hwall(ctx);
1151 	if (ret >= 0) {
1152 		printf("duplicate option not detected\n");
1153 		return -1;
1154 	}
1155 
1156 	save2.nro_opt.nro_status = EINVAL;
1157 	if ((ret = pop_extmem_option(ctx, &save2)))
1158 		return ret;
1159 
1160 	save1.nro_opt.nro_status = EINVAL;
1161 	if ((ret = pop_extmem_option(ctx, &save1)))
1162 		return ret;
1163 
1164 	return 0;
1165 }
1166 #endif /* CONFIG_NETMAP_EXTMEM */
1167 
1168 static int
1169 push_csb_option(struct TestContext *ctx, struct nmreq_opt_csb *opt)
1170 {
1171 	size_t csb_size;
1172 	int num_entries;
1173 	int ret;
1174 
1175 	ctx->nr_flags |= NR_EXCLUSIVE;
1176 
1177 	/* Get port info in order to use num_registered_rings(). */
1178 	ret = port_info_get(ctx);
1179 	if (ret != 0) {
1180 		return ret;
1181 	}
1182 	num_entries = num_registered_rings(ctx);
1183 
1184 	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
1185 	           num_entries;
1186 	assert(csb_size > 0);
1187 	if (ctx->csb) {
1188 		free(ctx->csb);
1189 	}
1190 	ret = posix_memalign(&ctx->csb, sizeof(struct nm_csb_atok), csb_size);
1191 	if (ret != 0) {
1192 		printf("Failed to allocate CSB memory\n");
1193 		exit(EXIT_FAILURE);
1194 	}
1195 
1196 	memset(opt, 0, sizeof(*opt));
1197 	opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
1198 	opt->csb_atok            = (uintptr_t)ctx->csb;
1199 	opt->csb_ktoa            = (uintptr_t)(((uint8_t *)ctx->csb) +
1200                                     sizeof(struct nm_csb_atok) * num_entries);
1201 
1202 	printf("Pushing option NETMAP_REQ_OPT_CSB\n");
1203 	push_option(&opt->nro_opt, ctx);
1204 
1205 	return 0;
1206 }
1207 
1208 static int
1209 csb_mode(struct TestContext *ctx)
1210 {
1211 	struct nmreq_opt_csb opt;
1212 	int ret;
1213 
1214 	ret = push_csb_option(ctx, &opt);
1215 	if (ret != 0) {
1216 		return ret;
1217 	}
1218 
1219 	ret = port_register_hwall(ctx);
1220 	clear_options(ctx);
1221 
1222 	return ret;
1223 }
1224 
1225 static int
1226 csb_mode_invalid_memory(struct TestContext *ctx)
1227 {
1228 	struct nmreq_opt_csb opt;
1229 	int ret;
1230 
1231 	memset(&opt, 0, sizeof(opt));
1232 	opt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
1233 	opt.csb_atok            = (uintptr_t)0x10;
1234 	opt.csb_ktoa            = (uintptr_t)0x800;
1235 	push_option(&opt.nro_opt, ctx);
1236 
1237 	ctx->nr_flags = NR_EXCLUSIVE;
1238 	ret           = port_register_hwall(ctx);
1239 	clear_options(ctx);
1240 
1241 	return (ret < 0) ? 0 : -1;
1242 }
1243 
1244 static int
1245 sync_kloop_stop(struct TestContext *ctx)
1246 {
1247 	struct nmreq_header hdr;
1248 	int ret;
1249 
1250 	printf("Testing NETMAP_REQ_SYNC_KLOOP_STOP on '%s'\n", ctx->ifname_ext);
1251 
1252 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
1253 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
1254 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
1255 	if (ret != 0) {
1256 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
1257 	}
1258 
1259 	return ret;
1260 }
1261 
1262 static void *
1263 sync_kloop_worker(void *opaque)
1264 {
1265 	struct TestContext *ctx = opaque;
1266 	struct nmreq_sync_kloop_start req;
1267 	struct nmreq_header hdr;
1268 	int ret;
1269 
1270 	printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname_ext);
1271 
1272 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
1273 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
1274 	hdr.nr_body    = (uintptr_t)&req;
1275 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
1276 	memset(&req, 0, sizeof(req));
1277 	req.sleep_us = 500;
1278 	ret          = ioctl(ctx->fd, NIOCCTRL, &hdr);
1279 	if (ret != 0) {
1280 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
1281 	}
1282 
1283 	if (ctx->sem) {
1284 		sem_post(ctx->sem);
1285 	}
1286 
1287 	pthread_exit(ret ? (void *)THRET_FAILURE : (void *)THRET_SUCCESS);
1288 }
1289 
1290 static int
1291 sync_kloop_start_stop(struct TestContext *ctx)
1292 {
1293 	pthread_t th;
1294 	void *thret = THRET_FAILURE;
1295 	int ret;
1296 
1297 	ret = pthread_create(&th, NULL, sync_kloop_worker, ctx);
1298 	if (ret != 0) {
1299 		printf("pthread_create(kloop): %s\n", strerror(ret));
1300 		return -1;
1301 	}
1302 
1303 	ret = sync_kloop_stop(ctx);
1304 	if (ret != 0) {
1305 		return ret;
1306 	}
1307 
1308 	ret = pthread_join(th, &thret);
1309 	if (ret != 0) {
1310 		printf("pthread_join(kloop): %s\n", strerror(ret));
1311 	}
1312 
1313 	return thret == THRET_SUCCESS ? 0 : -1;
1314 }
1315 
1316 static int
1317 sync_kloop(struct TestContext *ctx)
1318 {
1319 	int ret;
1320 
1321 	ret = csb_mode(ctx);
1322 	if (ret != 0) {
1323 		return ret;
1324 	}
1325 
1326 	return sync_kloop_start_stop(ctx);
1327 }
1328 
1329 static int
1330 sync_kloop_eventfds(struct TestContext *ctx)
1331 {
1332 	struct nmreq_opt_sync_kloop_eventfds *evopt = NULL;
1333 	struct nmreq_opt_sync_kloop_mode modeopt;
1334 	struct nmreq_option evsave;
1335 	int num_entries;
1336 	size_t opt_size;
1337 	int ret, i;
1338 
1339 	memset(&modeopt, 0, sizeof(modeopt));
1340 	modeopt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_MODE;
1341 	modeopt.mode = ctx->sync_kloop_mode;
1342 	push_option(&modeopt.nro_opt, ctx);
1343 
1344 	num_entries = num_registered_rings(ctx);
1345 	opt_size    = sizeof(*evopt) + num_entries * sizeof(evopt->eventfds[0]);
1346 	evopt = calloc(1, opt_size);
1347 	evopt->nro_opt.nro_next    = 0;
1348 	evopt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
1349 	evopt->nro_opt.nro_status  = 0;
1350 	evopt->nro_opt.nro_size    = opt_size;
1351 	for (i = 0; i < num_entries; i++) {
1352 		int efd = eventfd(0, 0);
1353 
1354 		evopt->eventfds[i].ioeventfd = efd;
1355 		efd                        = eventfd(0, 0);
1356 		evopt->eventfds[i].irqfd = efd;
1357 	}
1358 
1359 	push_option(&evopt->nro_opt, ctx);
1360 	evsave = evopt->nro_opt;
1361 
1362 	ret = sync_kloop_start_stop(ctx);
1363 	if (ret != 0) {
1364 		free(evopt);
1365 		clear_options(ctx);
1366 		return ret;
1367 	}
1368 #ifdef __linux__
1369 	evsave.nro_status = 0;
1370 #else  /* !__linux__ */
1371 	evsave.nro_status = EOPNOTSUPP;
1372 #endif /* !__linux__ */
1373 
1374 	ret = checkoption(&evopt->nro_opt, &evsave);
1375 	free(evopt);
1376 	clear_options(ctx);
1377 
1378 	return ret;
1379 }
1380 
1381 static int
1382 sync_kloop_eventfds_all_mode(struct TestContext *ctx,
1383 			     uint32_t sync_kloop_mode)
1384 {
1385 	int ret;
1386 
1387 	ret = csb_mode(ctx);
1388 	if (ret != 0) {
1389 		return ret;
1390 	}
1391 
1392 	ctx->sync_kloop_mode = sync_kloop_mode;
1393 
1394 	return sync_kloop_eventfds(ctx);
1395 }
1396 
1397 static int
1398 sync_kloop_eventfds_all(struct TestContext *ctx)
1399 {
1400 	return sync_kloop_eventfds_all_mode(ctx, 0);
1401 }
1402 
1403 static int
1404 sync_kloop_eventfds_all_tx(struct TestContext *ctx)
1405 {
1406 	struct nmreq_opt_csb opt;
1407 	int ret;
1408 
1409 	ret = push_csb_option(ctx, &opt);
1410 	if (ret != 0) {
1411 		return ret;
1412 	}
1413 
1414 	ret = port_register_hwall_tx(ctx);
1415 	if (ret != 0) {
1416 		return ret;
1417 	}
1418 	clear_options(ctx);
1419 
1420 	return sync_kloop_eventfds(ctx);
1421 }
1422 
1423 static int
1424 sync_kloop_eventfds_all_direct(struct TestContext *ctx)
1425 {
1426 	return sync_kloop_eventfds_all_mode(ctx,
1427 	    NM_OPT_SYNC_KLOOP_DIRECT_TX | NM_OPT_SYNC_KLOOP_DIRECT_RX);
1428 }
1429 
1430 static int
1431 sync_kloop_eventfds_all_direct_tx(struct TestContext *ctx)
1432 {
1433 	return sync_kloop_eventfds_all_mode(ctx,
1434 	    NM_OPT_SYNC_KLOOP_DIRECT_TX);
1435 }
1436 
1437 static int
1438 sync_kloop_eventfds_all_direct_rx(struct TestContext *ctx)
1439 {
1440 	return sync_kloop_eventfds_all_mode(ctx,
1441 	    NM_OPT_SYNC_KLOOP_DIRECT_RX);
1442 }
1443 
1444 static int
1445 sync_kloop_nocsb(struct TestContext *ctx)
1446 {
1447 	int ret;
1448 
1449 	ret = port_register_hwall(ctx);
1450 	if (ret != 0) {
1451 		return ret;
1452 	}
1453 
1454 	/* Sync kloop must fail because we did not use
1455 	 * NETMAP_REQ_CSB_ENABLE. */
1456 	return sync_kloop_start_stop(ctx) != 0 ? 0 : -1;
1457 }
1458 
1459 static int
1460 csb_enable(struct TestContext *ctx)
1461 {
1462 	struct nmreq_option saveopt;
1463 	struct nmreq_opt_csb opt;
1464 	struct nmreq_header hdr;
1465 	int ret;
1466 
1467 	ret = push_csb_option(ctx, &opt);
1468 	if (ret != 0) {
1469 		return ret;
1470 	}
1471 	saveopt = opt.nro_opt;
1472 	saveopt.nro_status = 0;
1473 
1474 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
1475 	hdr.nr_reqtype = NETMAP_REQ_CSB_ENABLE;
1476 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
1477 	hdr.nr_body = (uintptr_t)NULL;
1478 
1479 	printf("Testing NETMAP_REQ_CSB_ENABLE on '%s'\n", ctx->ifname_ext);
1480 
1481 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
1482 	if (ret != 0) {
1483 		perror("ioctl(/dev/netmap, NIOCCTRL, CSB_ENABLE)");
1484 		return ret;
1485 	}
1486 
1487 	ret = checkoption(&opt.nro_opt, &saveopt);
1488 	clear_options(ctx);
1489 
1490 	return ret;
1491 }
1492 
1493 static int
1494 sync_kloop_csb_enable(struct TestContext *ctx)
1495 {
1496 	int ret;
1497 
1498 	ctx->nr_flags |= NR_EXCLUSIVE;
1499 	ret = port_register_hwall(ctx);
1500 	if (ret != 0) {
1501 		return ret;
1502 	}
1503 
1504 	ret = csb_enable(ctx);
1505 	if (ret != 0) {
1506 		return ret;
1507 	}
1508 
1509 	return sync_kloop_start_stop(ctx);
1510 }
1511 
1512 static int
1513 sync_kloop_conflict(struct TestContext *ctx)
1514 {
1515 	struct nmreq_opt_csb opt;
1516 	pthread_t th1, th2;
1517 	void *thret1 = THRET_FAILURE, *thret2 = THRET_FAILURE;
1518 	struct timespec to;
1519 	sem_t sem;
1520 	int err = 0;
1521 	int ret;
1522 
1523 	ret = push_csb_option(ctx, &opt);
1524 	if (ret != 0) {
1525 		return ret;
1526 	}
1527 
1528 	ret = port_register_hwall(ctx);
1529 	if (ret != 0) {
1530 		return ret;
1531 	}
1532 	clear_options(ctx);
1533 
1534 	ret = sem_init(&sem, 0, 0);
1535 	if (ret != 0) {
1536 		printf("sem_init() failed: %s\n", strerror(ret));
1537 		return ret;
1538 	}
1539 	ctx->sem = &sem;
1540 
1541 	ret = pthread_create(&th1, NULL, sync_kloop_worker, ctx);
1542 	err |= ret;
1543 	if (ret != 0) {
1544 		printf("pthread_create(kloop1): %s\n", strerror(ret));
1545 	}
1546 
1547 	ret = pthread_create(&th2, NULL, sync_kloop_worker, ctx);
1548 	err |= ret;
1549 	if (ret != 0) {
1550 		printf("pthread_create(kloop2): %s\n", strerror(ret));
1551 	}
1552 
1553 	/* Wait for one of the two threads to fail to start the kloop, to
1554 	 * avoid a race condition where th1 starts the loop and stops,
1555 	 * and after that th2 starts the loop successfully. */
1556 	clock_gettime(CLOCK_REALTIME, &to);
1557 	to.tv_sec += 2;
1558 	ret = sem_timedwait(&sem, &to);
1559 	err |= ret;
1560 	if (ret != 0) {
1561 		printf("sem_timedwait() failed: %s\n", strerror(errno));
1562 	}
1563 
1564 	err |= sync_kloop_stop(ctx);
1565 
1566 	ret = pthread_join(th1, &thret1);
1567 	err |= ret;
1568 	if (ret != 0) {
1569 		printf("pthread_join(kloop1): %s\n", strerror(ret));
1570 	}
1571 
1572 	ret = pthread_join(th2, &thret2);
1573 	err |= ret;
1574 	if (ret != 0) {
1575 		printf("pthread_join(kloop2): %s %d\n", strerror(ret), ret);
1576 	}
1577 
1578 	sem_destroy(&sem);
1579 	ctx->sem = NULL;
1580 	if (err) {
1581 		return err;
1582 	}
1583 
1584 	/* Check that one of the two failed, while the other one succeeded. */
1585 	return ((thret1 == THRET_SUCCESS && thret2 == THRET_FAILURE) ||
1586 			(thret1 == THRET_FAILURE && thret2 == THRET_SUCCESS))
1587 	               ? 0
1588 	               : -1;
1589 }
1590 
1591 static int
1592 sync_kloop_eventfds_mismatch(struct TestContext *ctx)
1593 {
1594 	struct nmreq_opt_csb opt;
1595 	int ret;
1596 
1597 	ret = push_csb_option(ctx, &opt);
1598 	if (ret != 0) {
1599 		return ret;
1600 	}
1601 
1602 	ret = port_register_hwall_rx(ctx);
1603 	if (ret != 0) {
1604 		return ret;
1605 	}
1606 	clear_options(ctx);
1607 
1608 	/* Deceive num_registered_rings() to trigger a failure of
1609 	 * sync_kloop_eventfds(). The latter will think that all the
1610 	 * rings were registered, and allocate the wrong number of
1611 	 * eventfds. */
1612 	ctx->nr_flags &= ~NR_RX_RINGS_ONLY;
1613 
1614 	return (sync_kloop_eventfds(ctx) != 0) ? 0 : -1;
1615 }
1616 
1617 static int
1618 null_port(struct TestContext *ctx)
1619 {
1620 	int ret;
1621 
1622 	ctx->nr_mem_id = 1;
1623 	ctx->nr_mode = NR_REG_NULL;
1624 	ctx->nr_tx_rings = 10;
1625 	ctx->nr_rx_rings = 5;
1626 	ctx->nr_tx_slots = 256;
1627 	ctx->nr_rx_slots = 100;
1628 	ret = port_register(ctx);
1629 	if (ret != 0) {
1630 		return ret;
1631 	}
1632 	return 0;
1633 }
1634 
1635 static int
1636 null_port_all_zero(struct TestContext *ctx)
1637 {
1638 	int ret;
1639 
1640 	ctx->nr_mem_id = 1;
1641 	ctx->nr_mode = NR_REG_NULL;
1642 	ctx->nr_tx_rings = 0;
1643 	ctx->nr_rx_rings = 0;
1644 	ctx->nr_tx_slots = 0;
1645 	ctx->nr_rx_slots = 0;
1646 	ret = port_register(ctx);
1647 	if (ret != 0) {
1648 		return ret;
1649 	}
1650 	return 0;
1651 }
1652 
1653 static int
1654 null_port_sync(struct TestContext *ctx)
1655 {
1656 	int ret;
1657 
1658 	ctx->nr_mem_id = 1;
1659 	ctx->nr_mode = NR_REG_NULL;
1660 	ctx->nr_tx_rings = 10;
1661 	ctx->nr_rx_rings = 5;
1662 	ctx->nr_tx_slots = 256;
1663 	ctx->nr_rx_slots = 100;
1664 	ret = port_register(ctx);
1665 	if (ret != 0) {
1666 		return ret;
1667 	}
1668 	ret = ioctl(ctx->fd, NIOCTXSYNC, 0);
1669 	if (ret != 0) {
1670 		return ret;
1671 	}
1672 	return 0;
1673 }
1674 
1675 static void
1676 usage(const char *prog)
1677 {
1678 	printf("%s -i IFNAME\n"
1679 	       "[-j TEST_NUM1[-[TEST_NUM2]] | -[TEST_NUM_2]]\n"
1680 	       "[-l (list test cases)]\n",
1681 	       prog);
1682 }
1683 
1684 struct mytest {
1685 	testfunc_t test;
1686 	const char *name;
1687 };
1688 
1689 #define decltest(f)                                                            \
1690 	{                                                                      \
1691 		.test = f, .name = #f                                          \
1692 	}
1693 
1694 static struct mytest tests[] = {
1695 	decltest(port_info_get),
1696 	decltest(port_register_hwall_host),
1697 	decltest(port_register_hwall),
1698 	decltest(port_register_host),
1699 	decltest(port_register_single_ring_couple),
1700 	decltest(vale_attach_detach),
1701 	decltest(vale_attach_detach_host_rings),
1702 	decltest(vale_ephemeral_port_hdr_manipulation),
1703 	decltest(vale_persistent_port),
1704 	decltest(pools_info_get_and_register),
1705 	decltest(pools_info_get_empty_ifname),
1706 	decltest(pipe_master),
1707 	decltest(pipe_slave),
1708 	decltest(pipe_port_info_get),
1709 	decltest(pipe_pools_info_get),
1710 	decltest(vale_polling_enable_disable),
1711 	decltest(unsupported_option),
1712 	decltest(infinite_options),
1713 #ifdef CONFIG_NETMAP_EXTMEM
1714 	decltest(extmem_option),
1715 	decltest(bad_extmem_option),
1716 	decltest(duplicate_extmem_options),
1717 #endif /* CONFIG_NETMAP_EXTMEM */
1718 	decltest(csb_mode),
1719 	decltest(csb_mode_invalid_memory),
1720 	decltest(sync_kloop),
1721 	decltest(sync_kloop_eventfds_all),
1722 	decltest(sync_kloop_eventfds_all_tx),
1723 	decltest(sync_kloop_eventfds_all_direct),
1724 	decltest(sync_kloop_eventfds_all_direct_tx),
1725 	decltest(sync_kloop_eventfds_all_direct_rx),
1726 	decltest(sync_kloop_nocsb),
1727 	decltest(sync_kloop_csb_enable),
1728 	decltest(sync_kloop_conflict),
1729 	decltest(sync_kloop_eventfds_mismatch),
1730 	decltest(null_port),
1731 	decltest(null_port_all_zero),
1732 	decltest(null_port_sync),
1733 	decltest(legacy_regif_default),
1734 	decltest(legacy_regif_all_nic),
1735 	decltest(legacy_regif_12),
1736 	decltest(legacy_regif_sw),
1737 	decltest(legacy_regif_future),
1738 	decltest(legacy_regif_extra_bufs),
1739 	decltest(legacy_regif_extra_bufs_pipe),
1740 	decltest(legacy_regif_extra_bufs_pipe_vale),
1741 };
1742 
1743 static void
1744 context_cleanup(struct TestContext *ctx)
1745 {
1746 	if (ctx->csb) {
1747 		free(ctx->csb);
1748 		ctx->csb = NULL;
1749 	}
1750 
1751 	close(ctx->fd);
1752 	ctx->fd = -1;
1753 }
1754 
1755 static int
1756 parse_interval(const char *arg, int *j, int *k)
1757 {
1758 	const char *scan = arg;
1759 	char *rest;
1760 
1761 	*j = 0;
1762 	*k = -1;
1763 	if (*scan == '-') {
1764 		scan++;
1765 		goto get_k;
1766 	}
1767 	if (!isdigit(*scan))
1768 		goto err;
1769 	*k = strtol(scan, &rest, 10);
1770 	*j = *k - 1;
1771 	scan = rest;
1772 	if (*scan == '-') {
1773 		*k = -1;
1774 		scan++;
1775 	}
1776 get_k:
1777 	if (*scan == '\0')
1778 		return 0;
1779 	if (!isdigit(*scan))
1780 		goto err;
1781 	*k = strtol(scan, &rest, 10);
1782 	scan = rest;
1783 	if (!(*scan == '\0'))
1784 		goto err;
1785 
1786 	return 0;
1787 
1788 err:
1789 	fprintf(stderr, "syntax error in '%s', must be num[-[num]] or -[num]\n", arg);
1790 	return -1;
1791 }
1792 
1793 #define ARGV_APPEND(_av, _ac, _x)\
1794 	do {\
1795 		assert((int)(_ac) < (int)(sizeof(_av)/sizeof((_av)[0])));\
1796 		(_av)[(_ac)++] = _x;\
1797 	} while (0)
1798 
1799 static void
1800 tap_cleanup(int signo)
1801 {
1802 	const char *av[8];
1803 	int ac = 0;
1804 
1805 	(void)signo;
1806 #ifdef __FreeBSD__
1807 	ARGV_APPEND(av, ac, "ifconfig");
1808 	ARGV_APPEND(av, ac, ctx_.ifname);
1809 	ARGV_APPEND(av, ac, "destroy");
1810 #else
1811 	ARGV_APPEND(av, ac, "ip");
1812 	ARGV_APPEND(av, ac, "link");
1813 	ARGV_APPEND(av, ac, "del");
1814 	ARGV_APPEND(av, ac, ctx_.ifname);
1815 #endif
1816 	ARGV_APPEND(av, ac, NULL);
1817 	if (exec_command(ac, av)) {
1818 		printf("Failed to destroy tap interface\n");
1819 	}
1820 }
1821 
1822 int
1823 main(int argc, char **argv)
1824 {
1825 	int create_tap = 1;
1826 	int num_tests;
1827 	int ret  = 0;
1828 	int j    = 0;
1829 	int k    = -1;
1830 	int list = 0;
1831 	int opt;
1832 	int i;
1833 
1834 	memset(&ctx_, 0, sizeof(ctx_));
1835 
1836 	{
1837 		struct timespec t;
1838 		int idx;
1839 
1840 		clock_gettime(CLOCK_REALTIME, &t);
1841 		srand((unsigned int)t.tv_nsec);
1842 		idx = rand() % 8000 + 100;
1843 		snprintf(ctx_.ifname, sizeof(ctx_.ifname), "tap%d", idx);
1844 		idx = rand() % 800 + 100;
1845 		snprintf(ctx_.bdgname, sizeof(ctx_.bdgname), "vale%d", idx);
1846 	}
1847 
1848 	while ((opt = getopt(argc, argv, "hi:j:l")) != -1) {
1849 		switch (opt) {
1850 		case 'h':
1851 			usage(argv[0]);
1852 			return 0;
1853 
1854 		case 'i':
1855 			strncpy(ctx_.ifname, optarg, sizeof(ctx_.ifname) - 1);
1856 			create_tap = 0;
1857 			break;
1858 
1859 		case 'j':
1860 			if (parse_interval(optarg, &j, &k) < 0) {
1861 				usage(argv[0]);
1862 				return -1;
1863 			}
1864 			break;
1865 
1866 		case 'l':
1867 			list = 1;
1868 			create_tap = 0;
1869 			break;
1870 
1871 		default:
1872 			printf("    Unrecognized option %c\n", opt);
1873 			usage(argv[0]);
1874 			return -1;
1875 		}
1876 	}
1877 
1878 	num_tests = sizeof(tests) / sizeof(tests[0]);
1879 
1880 	if (j < 0 || j >= num_tests || k > num_tests) {
1881 		fprintf(stderr, "Test interval %d-%d out of range (%d-%d)\n",
1882 				j + 1, k, 1, num_tests + 1);
1883 		return -1;
1884 	}
1885 
1886 	if (k < 0)
1887 		k = num_tests;
1888 
1889 	if (list) {
1890 		printf("Available tests:\n");
1891 		for (i = 0; i < num_tests; i++) {
1892 			printf("#%03d: %s\n", i + 1, tests[i].name);
1893 		}
1894 		return 0;
1895 	}
1896 
1897 	if (create_tap) {
1898 		struct sigaction sa;
1899 		const char *av[8];
1900 		int ac = 0;
1901 #ifdef __FreeBSD__
1902 		ARGV_APPEND(av, ac, "ifconfig");
1903 		ARGV_APPEND(av, ac, ctx_.ifname);
1904 		ARGV_APPEND(av, ac, "create");
1905 		ARGV_APPEND(av, ac, "up");
1906 #else
1907 		ARGV_APPEND(av, ac, "ip");
1908 		ARGV_APPEND(av, ac, "tuntap");
1909 		ARGV_APPEND(av, ac, "add");
1910 		ARGV_APPEND(av, ac, "mode");
1911 		ARGV_APPEND(av, ac, "tap");
1912 		ARGV_APPEND(av, ac, "name");
1913 		ARGV_APPEND(av, ac, ctx_.ifname);
1914 #endif
1915 		ARGV_APPEND(av, ac, NULL);
1916 		if (exec_command(ac, av)) {
1917 			printf("Failed to create tap interface\n");
1918 			return -1;
1919 		}
1920 
1921 		sa.sa_handler = tap_cleanup;
1922 		sigemptyset(&sa.sa_mask);
1923 		sa.sa_flags = SA_RESTART;
1924 		ret         = sigaction(SIGINT, &sa, NULL);
1925 		if (ret) {
1926 			perror("sigaction(SIGINT)");
1927 			goto out;
1928 		}
1929 		ret = sigaction(SIGTERM, &sa, NULL);
1930 		if (ret) {
1931 			perror("sigaction(SIGTERM)");
1932 			goto out;
1933 		}
1934 	}
1935 
1936 	for (i = j; i < k; i++) {
1937 		struct TestContext ctxcopy;
1938 		int fd;
1939 		printf("==> Start of Test #%d [%s]\n", i + 1, tests[i].name);
1940 		fd = open("/dev/netmap", O_RDWR);
1941 		if (fd < 0) {
1942 			perror("open(/dev/netmap)");
1943 			ret = fd;
1944 			goto out;
1945 		}
1946 		memcpy(&ctxcopy, &ctx_, sizeof(ctxcopy));
1947 		ctxcopy.fd = fd;
1948 		memcpy(ctxcopy.ifname_ext, ctxcopy.ifname,
1949 			sizeof(ctxcopy.ifname));
1950 		ret        = tests[i].test(&ctxcopy);
1951 		if (ret != 0) {
1952 			printf("Test #%d [%s] failed\n", i + 1, tests[i].name);
1953 			goto out;
1954 		}
1955 		printf("==> Test #%d [%s] successful\n", i + 1, tests[i].name);
1956 		context_cleanup(&ctxcopy);
1957 	}
1958 out:
1959 	tap_cleanup(0);
1960 
1961 	return ret;
1962 }
1963