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