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