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