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