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