xref: /freebsd/tests/sys/netmap/ctrl-api-test.c (revision 2b833162)
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 (invalid options)\n", ctx->ifname_ext);
1016 
1017 	memset(&opt, 0, sizeof(opt));
1018 	opt.nro_reqtype = NETMAP_REQ_OPT_MAX + 1;
1019 	push_option(&opt, ctx);
1020 	opt.nro_next = (uintptr_t)&opt;
1021 	if (port_register_hwall(ctx) >= 0)
1022 		return -1;
1023 	clear_options(ctx);
1024 	return (errno == EMSGSIZE ? 0 : -1);
1025 }
1026 
1027 static int
1028 infinite_options2(struct TestContext *ctx)
1029 {
1030 	struct nmreq_option opt;
1031 
1032 	printf("Testing infinite list of options on %s (valid options)\n", ctx->ifname_ext);
1033 
1034 	memset(&opt, 0, sizeof(opt));
1035 	opt.nro_reqtype = NETMAP_REQ_OPT_OFFSETS;
1036 	push_option(&opt, ctx);
1037 	opt.nro_next = (uintptr_t)&opt;
1038 	if (port_register_hwall(ctx) >= 0)
1039 		return -1;
1040 	clear_options(ctx);
1041 	return (errno == EINVAL ? 0 : -1);
1042 }
1043 
1044 #ifdef CONFIG_NETMAP_EXTMEM
1045 int
1046 change_param(const char *pname, unsigned long newv, unsigned long *poldv)
1047 {
1048 #ifdef __linux__
1049 	char param[256] = "/sys/module/netmap/parameters/";
1050 	unsigned long oldv;
1051 	FILE *f;
1052 
1053 	strncat(param, pname, sizeof(param) - 1);
1054 
1055 	f = fopen(param, "r+");
1056 	if (f == NULL) {
1057 		perror(param);
1058 		return -1;
1059 	}
1060 	if (fscanf(f, "%ld", &oldv) != 1) {
1061 		perror(param);
1062 		fclose(f);
1063 		return -1;
1064 	}
1065 	if (poldv)
1066 		*poldv = oldv;
1067 	rewind(f);
1068 	if (fprintf(f, "%ld\n", newv) < 0) {
1069 		perror(param);
1070 		fclose(f);
1071 		return -1;
1072 	}
1073 	fclose(f);
1074 	printf("change_param: %s: %ld -> %ld\n", pname, oldv, newv);
1075 #endif /* __linux__ */
1076 	return 0;
1077 }
1078 
1079 static int
1080 push_extmem_option(struct TestContext *ctx, const struct nmreq_pools_info *pi,
1081 		struct nmreq_opt_extmem *e)
1082 {
1083 	void *addr;
1084 
1085 	addr = mmap(NULL, pi->nr_memsize, PROT_READ | PROT_WRITE,
1086 	            MAP_ANONYMOUS | MAP_SHARED, -1, 0);
1087 	if (addr == MAP_FAILED) {
1088 		perror("mmap");
1089 		return -1;
1090 	}
1091 
1092 	memset(e, 0, sizeof(*e));
1093 	e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
1094 	e->nro_info = *pi;
1095 	e->nro_usrptr          = (uintptr_t)addr;
1096 
1097 	push_option(&e->nro_opt, ctx);
1098 
1099 	return 0;
1100 }
1101 
1102 static int
1103 pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
1104 {
1105 	struct nmreq_opt_extmem *e;
1106 	int ret;
1107 
1108 	e           = (struct nmreq_opt_extmem *)(uintptr_t)ctx->nr_opt;
1109 	ctx->nr_opt = (struct nmreq_option *)(uintptr_t)ctx->nr_opt->nro_next;
1110 
1111 	if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
1112 		return ret;
1113 	}
1114 
1115 	if (e->nro_usrptr != exp->nro_usrptr) {
1116 		printf("usrptr %" PRIu64 " expected %" PRIu64 "\n",
1117 		       e->nro_usrptr, exp->nro_usrptr);
1118 		return -1;
1119 	}
1120 	if (e->nro_info.nr_memsize != exp->nro_info.nr_memsize) {
1121 		printf("memsize %" PRIu64 " expected %" PRIu64 "\n",
1122 		       e->nro_info.nr_memsize, exp->nro_info.nr_memsize);
1123 		return -1;
1124 	}
1125 
1126 	if ((ret = munmap((void *)(uintptr_t)e->nro_usrptr,
1127 	                  e->nro_info.nr_memsize)))
1128 		return ret;
1129 
1130 	return 0;
1131 }
1132 
1133 static int
1134 _extmem_option(struct TestContext *ctx,
1135 		const struct nmreq_pools_info *pi)
1136 {
1137 	struct nmreq_opt_extmem e, save;
1138 	int ret;
1139 
1140 	if ((ret = push_extmem_option(ctx, pi, &e)) < 0)
1141 		return ret;
1142 
1143 	save = e;
1144 
1145 	strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
1146 	ctx->nr_tx_slots = 16;
1147 	ctx->nr_rx_slots = 16;
1148 
1149 	if ((ret = port_register_hwall(ctx)))
1150 		return ret;
1151 
1152 	ret = pop_extmem_option(ctx, &save);
1153 
1154 	return ret;
1155 }
1156 
1157 static size_t
1158 pools_info_min_memsize(const struct nmreq_pools_info *pi)
1159 {
1160 	size_t tot = 0;
1161 
1162 	tot += pi->nr_if_pool_objtotal * pi->nr_if_pool_objsize;
1163 	tot += pi->nr_ring_pool_objtotal * pi->nr_ring_pool_objsize;
1164 	tot += pi->nr_buf_pool_objtotal * pi->nr_buf_pool_objsize;
1165 
1166 	return tot;
1167 }
1168 
1169 /*
1170  * Fill the specification of a netmap memory allocator to be
1171  * used with the 'struct nmreq_opt_extmem' option. Arbitrary
1172  * values are used for the parameters, but with enough netmap
1173  * rings, netmap ifs, and buffers to support a VALE port.
1174  */
1175 static void
1176 pools_info_fill(struct nmreq_pools_info *pi)
1177 {
1178 	pi->nr_if_pool_objtotal = 2;
1179 	pi->nr_if_pool_objsize = 1024;
1180 	pi->nr_ring_pool_objtotal = 64;
1181 	pi->nr_ring_pool_objsize = 512;
1182 	pi->nr_buf_pool_objtotal = 4096;
1183 	pi->nr_buf_pool_objsize = 2048;
1184 	pi->nr_memsize = pools_info_min_memsize(pi);
1185 }
1186 
1187 static int
1188 extmem_option(struct TestContext *ctx)
1189 {
1190 	struct nmreq_pools_info	pools_info;
1191 
1192 	pools_info_fill(&pools_info);
1193 
1194 	printf("Testing extmem option on vale0:0\n");
1195 	return _extmem_option(ctx, &pools_info);
1196 }
1197 
1198 static int
1199 bad_extmem_option(struct TestContext *ctx)
1200 {
1201 	struct nmreq_pools_info	pools_info;
1202 
1203 	printf("Testing bad extmem option on vale0:0\n");
1204 
1205 	pools_info_fill(&pools_info);
1206 	/* Request a large ring size, to make sure that the kernel
1207 	 * rejects our request. */
1208 	pools_info.nr_ring_pool_objsize = (1 << 20);
1209 
1210 	return _extmem_option(ctx, &pools_info) < 0 ? 0 : -1;
1211 }
1212 
1213 static int
1214 duplicate_extmem_options(struct TestContext *ctx)
1215 {
1216 	struct nmreq_opt_extmem e1, save1, e2, save2;
1217 	struct nmreq_pools_info	pools_info;
1218 	int ret;
1219 
1220 	printf("Testing duplicate extmem option on vale0:0\n");
1221 
1222 	pools_info_fill(&pools_info);
1223 
1224 	if ((ret = push_extmem_option(ctx, &pools_info, &e1)) < 0)
1225 		return ret;
1226 
1227 	if ((ret = push_extmem_option(ctx, &pools_info, &e2)) < 0) {
1228 		clear_options(ctx);
1229 		return ret;
1230 	}
1231 
1232 	save1 = e1;
1233 	save2 = e2;
1234 
1235 	strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
1236 	ctx->nr_tx_slots = 16;
1237 	ctx->nr_rx_slots = 16;
1238 
1239 	ret = port_register_hwall(ctx);
1240 	if (ret >= 0) {
1241 		printf("duplicate option not detected\n");
1242 		return -1;
1243 	}
1244 
1245 	save2.nro_opt.nro_status = EINVAL;
1246 	if ((ret = pop_extmem_option(ctx, &save2)))
1247 		return ret;
1248 
1249 	save1.nro_opt.nro_status = EINVAL;
1250 	if ((ret = pop_extmem_option(ctx, &save1)))
1251 		return ret;
1252 
1253 	return 0;
1254 }
1255 #endif /* CONFIG_NETMAP_EXTMEM */
1256 
1257 static int
1258 push_csb_option(struct TestContext *ctx, struct nmreq_opt_csb *opt)
1259 {
1260 	size_t csb_size;
1261 	int num_entries;
1262 	int ret;
1263 
1264 	ctx->nr_flags |= NR_EXCLUSIVE;
1265 
1266 	/* Get port info in order to use num_registered_rings(). */
1267 	ret = port_info_get(ctx);
1268 	if (ret != 0) {
1269 		return ret;
1270 	}
1271 	num_entries = num_registered_rings(ctx);
1272 
1273 	csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
1274 	           num_entries;
1275 	assert(csb_size > 0);
1276 	if (ctx->csb) {
1277 		free(ctx->csb);
1278 	}
1279 	ret = posix_memalign(&ctx->csb, sizeof(struct nm_csb_atok), csb_size);
1280 	if (ret != 0) {
1281 		printf("Failed to allocate CSB memory\n");
1282 		exit(EXIT_FAILURE);
1283 	}
1284 
1285 	memset(opt, 0, sizeof(*opt));
1286 	opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
1287 	opt->csb_atok            = (uintptr_t)ctx->csb;
1288 	opt->csb_ktoa            = (uintptr_t)(((uint8_t *)ctx->csb) +
1289                                     sizeof(struct nm_csb_atok) * num_entries);
1290 
1291 	printf("Pushing option NETMAP_REQ_OPT_CSB\n");
1292 	push_option(&opt->nro_opt, ctx);
1293 
1294 	return 0;
1295 }
1296 
1297 static int
1298 csb_mode(struct TestContext *ctx)
1299 {
1300 	struct nmreq_opt_csb opt;
1301 	int ret;
1302 
1303 	ret = push_csb_option(ctx, &opt);
1304 	if (ret != 0) {
1305 		return ret;
1306 	}
1307 
1308 	ret = port_register_hwall(ctx);
1309 	clear_options(ctx);
1310 
1311 	return ret;
1312 }
1313 
1314 static int
1315 csb_mode_invalid_memory(struct TestContext *ctx)
1316 {
1317 	struct nmreq_opt_csb opt;
1318 	int ret;
1319 
1320 	memset(&opt, 0, sizeof(opt));
1321 	opt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
1322 	opt.csb_atok            = (uintptr_t)0x10;
1323 	opt.csb_ktoa            = (uintptr_t)0x800;
1324 	push_option(&opt.nro_opt, ctx);
1325 
1326 	ctx->nr_flags = NR_EXCLUSIVE;
1327 	ret           = port_register_hwall(ctx);
1328 	clear_options(ctx);
1329 
1330 	return (ret < 0) ? 0 : -1;
1331 }
1332 
1333 static int
1334 sync_kloop_stop(struct TestContext *ctx)
1335 {
1336 	struct nmreq_header hdr;
1337 	int ret;
1338 
1339 	printf("Testing NETMAP_REQ_SYNC_KLOOP_STOP on '%s'\n", ctx->ifname_ext);
1340 
1341 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
1342 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
1343 	ret            = ioctl(ctx->fd, NIOCCTRL, &hdr);
1344 	if (ret != 0) {
1345 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
1346 	}
1347 
1348 	return ret;
1349 }
1350 
1351 static void *
1352 sync_kloop_worker(void *opaque)
1353 {
1354 	struct TestContext *ctx = opaque;
1355 	struct nmreq_sync_kloop_start req;
1356 	struct nmreq_header hdr;
1357 	int ret;
1358 
1359 	printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname_ext);
1360 
1361 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
1362 	hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
1363 	hdr.nr_body    = (uintptr_t)&req;
1364 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
1365 	memset(&req, 0, sizeof(req));
1366 	req.sleep_us = 500;
1367 	ret          = ioctl(ctx->fd, NIOCCTRL, &hdr);
1368 	if (ret != 0) {
1369 		perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
1370 	}
1371 
1372 	if (ctx->sem) {
1373 		sem_post(ctx->sem);
1374 	}
1375 
1376 	pthread_exit(ret ? (void *)THRET_FAILURE : (void *)THRET_SUCCESS);
1377 }
1378 
1379 static int
1380 sync_kloop_start_stop(struct TestContext *ctx)
1381 {
1382 	pthread_t th;
1383 	void *thret = THRET_FAILURE;
1384 	int ret;
1385 
1386 	ret = pthread_create(&th, NULL, sync_kloop_worker, ctx);
1387 	if (ret != 0) {
1388 		printf("pthread_create(kloop): %s\n", strerror(ret));
1389 		return -1;
1390 	}
1391 
1392 	ret = sync_kloop_stop(ctx);
1393 	if (ret != 0) {
1394 		return ret;
1395 	}
1396 
1397 	ret = pthread_join(th, &thret);
1398 	if (ret != 0) {
1399 		printf("pthread_join(kloop): %s\n", strerror(ret));
1400 	}
1401 
1402 	return thret == THRET_SUCCESS ? 0 : -1;
1403 }
1404 
1405 static int
1406 sync_kloop(struct TestContext *ctx)
1407 {
1408 	int ret;
1409 
1410 	ret = csb_mode(ctx);
1411 	if (ret != 0) {
1412 		return ret;
1413 	}
1414 
1415 	return sync_kloop_start_stop(ctx);
1416 }
1417 
1418 static int
1419 sync_kloop_eventfds(struct TestContext *ctx)
1420 {
1421 	struct nmreq_opt_sync_kloop_eventfds *evopt = NULL;
1422 	struct nmreq_opt_sync_kloop_mode modeopt;
1423 	struct nmreq_option evsave;
1424 	int num_entries;
1425 	size_t opt_size;
1426 	int ret, i;
1427 
1428 	memset(&modeopt, 0, sizeof(modeopt));
1429 	modeopt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_MODE;
1430 	modeopt.mode = ctx->sync_kloop_mode;
1431 	push_option(&modeopt.nro_opt, ctx);
1432 
1433 	num_entries = num_registered_rings(ctx);
1434 	opt_size    = sizeof(*evopt) + num_entries * sizeof(evopt->eventfds[0]);
1435 	evopt = calloc(1, opt_size);
1436 	evopt->nro_opt.nro_next    = 0;
1437 	evopt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
1438 	evopt->nro_opt.nro_status  = 0;
1439 	evopt->nro_opt.nro_size    = opt_size;
1440 	for (i = 0; i < num_entries; i++) {
1441 		int efd = eventfd(0, 0);
1442 
1443 		evopt->eventfds[i].ioeventfd = efd;
1444 		efd                        = eventfd(0, 0);
1445 		evopt->eventfds[i].irqfd = efd;
1446 	}
1447 
1448 	push_option(&evopt->nro_opt, ctx);
1449 	evsave = evopt->nro_opt;
1450 
1451 	ret = sync_kloop_start_stop(ctx);
1452 	if (ret != 0) {
1453 		free(evopt);
1454 		clear_options(ctx);
1455 		return ret;
1456 	}
1457 #ifdef __linux__
1458 	evsave.nro_status = 0;
1459 #else  /* !__linux__ */
1460 	evsave.nro_status = EOPNOTSUPP;
1461 #endif /* !__linux__ */
1462 
1463 	ret = checkoption(&evopt->nro_opt, &evsave);
1464 	free(evopt);
1465 	clear_options(ctx);
1466 
1467 	return ret;
1468 }
1469 
1470 static int
1471 sync_kloop_eventfds_all_mode(struct TestContext *ctx,
1472 			     uint32_t sync_kloop_mode)
1473 {
1474 	int ret;
1475 
1476 	ret = csb_mode(ctx);
1477 	if (ret != 0) {
1478 		return ret;
1479 	}
1480 
1481 	ctx->sync_kloop_mode = sync_kloop_mode;
1482 
1483 	return sync_kloop_eventfds(ctx);
1484 }
1485 
1486 static int
1487 sync_kloop_eventfds_all(struct TestContext *ctx)
1488 {
1489 	return sync_kloop_eventfds_all_mode(ctx, 0);
1490 }
1491 
1492 static int
1493 sync_kloop_eventfds_all_tx(struct TestContext *ctx)
1494 {
1495 	struct nmreq_opt_csb opt;
1496 	int ret;
1497 
1498 	ret = push_csb_option(ctx, &opt);
1499 	if (ret != 0) {
1500 		return ret;
1501 	}
1502 
1503 	ret = port_register_hwall_tx(ctx);
1504 	if (ret != 0) {
1505 		return ret;
1506 	}
1507 	clear_options(ctx);
1508 
1509 	return sync_kloop_eventfds(ctx);
1510 }
1511 
1512 static int
1513 sync_kloop_eventfds_all_direct(struct TestContext *ctx)
1514 {
1515 	return sync_kloop_eventfds_all_mode(ctx,
1516 	    NM_OPT_SYNC_KLOOP_DIRECT_TX | NM_OPT_SYNC_KLOOP_DIRECT_RX);
1517 }
1518 
1519 static int
1520 sync_kloop_eventfds_all_direct_tx(struct TestContext *ctx)
1521 {
1522 	return sync_kloop_eventfds_all_mode(ctx,
1523 	    NM_OPT_SYNC_KLOOP_DIRECT_TX);
1524 }
1525 
1526 static int
1527 sync_kloop_eventfds_all_direct_rx(struct TestContext *ctx)
1528 {
1529 	return sync_kloop_eventfds_all_mode(ctx,
1530 	    NM_OPT_SYNC_KLOOP_DIRECT_RX);
1531 }
1532 
1533 static int
1534 sync_kloop_nocsb(struct TestContext *ctx)
1535 {
1536 	int ret;
1537 
1538 	ret = port_register_hwall(ctx);
1539 	if (ret != 0) {
1540 		return ret;
1541 	}
1542 
1543 	/* Sync kloop must fail because we did not use
1544 	 * NETMAP_REQ_CSB_ENABLE. */
1545 	return sync_kloop_start_stop(ctx) != 0 ? 0 : -1;
1546 }
1547 
1548 static int
1549 csb_enable(struct TestContext *ctx)
1550 {
1551 	struct nmreq_option saveopt;
1552 	struct nmreq_opt_csb opt;
1553 	struct nmreq_header hdr;
1554 	int ret;
1555 
1556 	ret = push_csb_option(ctx, &opt);
1557 	if (ret != 0) {
1558 		return ret;
1559 	}
1560 	saveopt = opt.nro_opt;
1561 	saveopt.nro_status = 0;
1562 
1563 	nmreq_hdr_init(&hdr, ctx->ifname_ext);
1564 	hdr.nr_reqtype = NETMAP_REQ_CSB_ENABLE;
1565 	hdr.nr_options = (uintptr_t)ctx->nr_opt;
1566 	hdr.nr_body = (uintptr_t)NULL;
1567 
1568 	printf("Testing NETMAP_REQ_CSB_ENABLE on '%s'\n", ctx->ifname_ext);
1569 
1570 	ret           = ioctl(ctx->fd, NIOCCTRL, &hdr);
1571 	if (ret != 0) {
1572 		perror("ioctl(/dev/netmap, NIOCCTRL, CSB_ENABLE)");
1573 		return ret;
1574 	}
1575 
1576 	ret = checkoption(&opt.nro_opt, &saveopt);
1577 	clear_options(ctx);
1578 
1579 	return ret;
1580 }
1581 
1582 static int
1583 sync_kloop_csb_enable(struct TestContext *ctx)
1584 {
1585 	int ret;
1586 
1587 	ctx->nr_flags |= NR_EXCLUSIVE;
1588 	ret = port_register_hwall(ctx);
1589 	if (ret != 0) {
1590 		return ret;
1591 	}
1592 
1593 	ret = csb_enable(ctx);
1594 	if (ret != 0) {
1595 		return ret;
1596 	}
1597 
1598 	return sync_kloop_start_stop(ctx);
1599 }
1600 
1601 static int
1602 sync_kloop_conflict(struct TestContext *ctx)
1603 {
1604 	struct nmreq_opt_csb opt;
1605 	pthread_t th1, th2;
1606 	void *thret1 = THRET_FAILURE, *thret2 = THRET_FAILURE;
1607 	struct timespec to;
1608 	sem_t sem;
1609 	int err = 0;
1610 	int ret;
1611 
1612 	ret = push_csb_option(ctx, &opt);
1613 	if (ret != 0) {
1614 		return ret;
1615 	}
1616 
1617 	ret = port_register_hwall(ctx);
1618 	if (ret != 0) {
1619 		return ret;
1620 	}
1621 	clear_options(ctx);
1622 
1623 	ret = sem_init(&sem, 0, 0);
1624 	if (ret != 0) {
1625 		printf("sem_init() failed: %s\n", strerror(ret));
1626 		return ret;
1627 	}
1628 	ctx->sem = &sem;
1629 
1630 	ret = pthread_create(&th1, NULL, sync_kloop_worker, ctx);
1631 	err |= ret;
1632 	if (ret != 0) {
1633 		printf("pthread_create(kloop1): %s\n", strerror(ret));
1634 	}
1635 
1636 	ret = pthread_create(&th2, NULL, sync_kloop_worker, ctx);
1637 	err |= ret;
1638 	if (ret != 0) {
1639 		printf("pthread_create(kloop2): %s\n", strerror(ret));
1640 	}
1641 
1642 	/* Wait for one of the two threads to fail to start the kloop, to
1643 	 * avoid a race condition where th1 starts the loop and stops,
1644 	 * and after that th2 starts the loop successfully. */
1645 	clock_gettime(CLOCK_REALTIME, &to);
1646 	to.tv_sec += 2;
1647 	ret = sem_timedwait(&sem, &to);
1648 	err |= ret;
1649 	if (ret != 0) {
1650 		printf("sem_timedwait() failed: %s\n", strerror(errno));
1651 	}
1652 
1653 	err |= sync_kloop_stop(ctx);
1654 
1655 	ret = pthread_join(th1, &thret1);
1656 	err |= ret;
1657 	if (ret != 0) {
1658 		printf("pthread_join(kloop1): %s\n", strerror(ret));
1659 	}
1660 
1661 	ret = pthread_join(th2, &thret2);
1662 	err |= ret;
1663 	if (ret != 0) {
1664 		printf("pthread_join(kloop2): %s %d\n", strerror(ret), ret);
1665 	}
1666 
1667 	sem_destroy(&sem);
1668 	ctx->sem = NULL;
1669 	if (err) {
1670 		return err;
1671 	}
1672 
1673 	/* Check that one of the two failed, while the other one succeeded. */
1674 	return ((thret1 == THRET_SUCCESS && thret2 == THRET_FAILURE) ||
1675 			(thret1 == THRET_FAILURE && thret2 == THRET_SUCCESS))
1676 	               ? 0
1677 	               : -1;
1678 }
1679 
1680 static int
1681 sync_kloop_eventfds_mismatch(struct TestContext *ctx)
1682 {
1683 	struct nmreq_opt_csb opt;
1684 	int ret;
1685 
1686 	ret = push_csb_option(ctx, &opt);
1687 	if (ret != 0) {
1688 		return ret;
1689 	}
1690 
1691 	ret = port_register_hwall_rx(ctx);
1692 	if (ret != 0) {
1693 		return ret;
1694 	}
1695 	clear_options(ctx);
1696 
1697 	/* Deceive num_registered_rings() to trigger a failure of
1698 	 * sync_kloop_eventfds(). The latter will think that all the
1699 	 * rings were registered, and allocate the wrong number of
1700 	 * eventfds. */
1701 	ctx->nr_flags &= ~NR_RX_RINGS_ONLY;
1702 
1703 	return (sync_kloop_eventfds(ctx) != 0) ? 0 : -1;
1704 }
1705 
1706 static int
1707 null_port(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 = 10;
1714 	ctx->nr_rx_rings = 5;
1715 	ctx->nr_tx_slots = 256;
1716 	ctx->nr_rx_slots = 100;
1717 	ret = port_register(ctx);
1718 	if (ret != 0) {
1719 		return ret;
1720 	}
1721 	return 0;
1722 }
1723 
1724 static int
1725 null_port_all_zero(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 = 0;
1732 	ctx->nr_rx_rings = 0;
1733 	ctx->nr_tx_slots = 0;
1734 	ctx->nr_rx_slots = 0;
1735 	ret = port_register(ctx);
1736 	if (ret != 0) {
1737 		return ret;
1738 	}
1739 	return 0;
1740 }
1741 
1742 static int
1743 null_port_sync(struct TestContext *ctx)
1744 {
1745 	int ret;
1746 
1747 	ctx->nr_mem_id = 1;
1748 	ctx->nr_mode = NR_REG_NULL;
1749 	ctx->nr_tx_rings = 10;
1750 	ctx->nr_rx_rings = 5;
1751 	ctx->nr_tx_slots = 256;
1752 	ctx->nr_rx_slots = 100;
1753 	ret = port_register(ctx);
1754 	if (ret != 0) {
1755 		return ret;
1756 	}
1757 	ret = ioctl(ctx->fd, NIOCTXSYNC, 0);
1758 	if (ret != 0) {
1759 		return ret;
1760 	}
1761 	return 0;
1762 }
1763 
1764 struct nmreq_parse_test {
1765 	const char *ifname;
1766 	const char *exp_port;
1767 	const char *exp_suff;
1768 	int exp_error;
1769 	uint32_t exp_mode;
1770 	uint16_t exp_ringid;
1771 	uint64_t exp_flags;
1772 };
1773 
1774 static struct nmreq_parse_test nmreq_parse_tests[] = {
1775 	/* port spec is the input. The expected results are as follows:
1776 	 * - port: what should go into hdr.nr_name
1777 	 * - suff: the trailing part of the input after parsing (NULL means equal to port spec)
1778 	 * - err: the expected return value, interpreted as follows
1779 	 *       err > 0 => nmreq_header_parse should fail with the given error
1780 	 *       err < 0 => nrmeq_header_parse should succeed, but nmreq_register_decode should
1781 	 *       		   fail with error |err|
1782 	 *       err = 0 => should succeed
1783 	 * - mode, ringid flags: what should go into the corresponding nr_* fields in the
1784 	 *   	nmreq_register struct in case of success
1785 	 */
1786 
1787 	/*port spec*/			/*port*/	/*suff*/    /*err*/	/*mode*/    /*ringid*/ /*flags*/
1788 	{ "netmap:eth0",		"eth0",		"",		0, 	NR_REG_ALL_NIC,	0,	0 },
1789 	{ "netmap:eth0-1",		"eth0",		"",		0, 	NR_REG_ONE_NIC, 1,	0 },
1790 	{ "netmap:eth0-",		"eth0",		"-",		-EINVAL,0,		0,	0 },
1791 	{ "netmap:eth0/x",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_EXCLUSIVE },
1792 	{ "netmap:eth0/z",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_ZCOPY_MON },
1793 	{ "netmap:eth0/r",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_MONITOR_RX },
1794 	{ "netmap:eth0/t",		"eth0",		"",		0, 	NR_REG_ALL_NIC, 0,	NR_MONITOR_TX },
1795 	{ "netmap:eth0-2/Tx",		"eth0",		"",		0, 	NR_REG_ONE_NIC, 2,	NR_TX_RINGS_ONLY|NR_EXCLUSIVE },
1796 	{ "netmap:eth0*",		"eth0",		"",		0, 	NR_REG_NIC_SW,  0,	0 },
1797 	{ "netmap:eth0^",		"eth0",		"",		0, 	NR_REG_SW,	0,	0 },
1798 	{ "netmap:eth0@2",		"eth0",	        "",		0,	NR_REG_ALL_NIC, 0,	0 },
1799 	{ "netmap:eth0@2/R",		"eth0",	        "",		0,	NR_REG_ALL_NIC, 0,	NR_RX_RINGS_ONLY },
1800 	{ "netmap:eth0@netmap:lo/R",	"eth0",	        "@netmap:lo/R",	0,	NR_REG_ALL_NIC,	0,	0 },
1801 	{ "netmap:eth0/R@xxx",		"eth0",	        "@xxx",		0,	NR_REG_ALL_NIC,	0,	NR_RX_RINGS_ONLY },
1802 	{ "netmap:eth0@2/R@2",		"eth0",	        "",		0,	NR_REG_ALL_NIC, 0,	NR_RX_RINGS_ONLY },
1803 	{ "netmap:eth0@2/R@3",		"eth0",	        "@2/R@3",	-EINVAL,0,		0,	0 },
1804 	{ "netmap:eth0@",		"eth0",	        "@",		-EINVAL,0,		0,	0 },
1805 	{ "netmap:",			"",		NULL,		EINVAL, 0,		0,	0 },
1806 	{ "netmap:^",			"",		NULL,		EINVAL,	0,		0,	0 },
1807 	{ "netmap:{",			"",		NULL,		EINVAL,	0,		0,	0 },
1808 	{ "netmap:vale0:0",		NULL,		NULL,		EINVAL,	0,		0,	0 },
1809 	{ "eth0",			NULL,		NULL,		EINVAL, 0,		0,	0 },
1810 	{ "vale0:0",			"vale0:0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
1811 	{ "vale:0",			"vale:0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
1812 	{ "valeXXX:YYY",		"valeXXX:YYY",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
1813 	{ "valeXXX:YYY-4",		"valeXXX:YYY",	"",		0,	NR_REG_ONE_NIC, 4,	0 },
1814 	{ "netmapXXX:eth0",		NULL,		NULL,		EINVAL,	0,		0,	0 },
1815 	{ "netmap:14",			"14",		"",		0, 	NR_REG_ALL_NIC,	0,	0 },
1816 	{ "netmap:eth0&",		NULL,		NULL,		EINVAL, 0,		0,	0 },
1817 	{ "netmap:pipe{0",		"pipe{0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
1818 	{ "netmap:pipe{in",		"pipe{in",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
1819 	{ "netmap:pipe{in-7",		"pipe{in",	"",		0,	NR_REG_ONE_NIC, 7,	0 },
1820 	{ "vale0:0{0",			"vale0:0{0",	"",		0,	NR_REG_ALL_NIC, 0,	0 },
1821 	{ "netmap:pipe{1}2",		NULL,		NULL,		EINVAL, 0,		0,	0 },
1822 	{ "vale0:0@opt", 		"vale0:0",	"@opt",		0,	NR_REG_ALL_NIC, 0,	0 },
1823 	{ "vale0:0/Tx@opt", 		"vale0:0",	"@opt",		0,	NR_REG_ALL_NIC, 0,	NR_TX_RINGS_ONLY|NR_EXCLUSIVE },
1824 	{ "vale0:0-3@opt", 		"vale0:0",	"@opt",		0,	NR_REG_ONE_NIC, 3,	0 },
1825 	{ "vale0:0@", 			"vale0:0",	"@",		-EINVAL,0,	        0,	0 },
1826 	{ "",				NULL,		NULL,		EINVAL, 0,		0,	0 },
1827 	{ NULL,				NULL,		NULL,		0, 	0,		0,	0 },
1828 };
1829 
1830 static void
1831 randomize(void *dst, size_t n)
1832 {
1833 	size_t i;
1834 	char *dst_ = dst;
1835 
1836 	for (i = 0; i < n; i++)
1837 		dst_[i] = (char)random();
1838 }
1839 
1840 static int
1841 nmreq_hdr_parsing(struct TestContext *ctx,
1842 		struct nmreq_parse_test *t,
1843 		struct nmreq_header *hdr)
1844 {
1845 	const char *save;
1846 	struct nmreq_header orig_hdr;
1847 
1848 	save = ctx->ifparse = t->ifname;
1849 	orig_hdr = *hdr;
1850 
1851 	printf("nmreq_header: \"%s\"\n", ctx->ifparse);
1852 	if (nmreq_header_decode(&ctx->ifparse, hdr, ctx->nmctx) < 0) {
1853 		if (t->exp_error > 0) {
1854 			if (errno != t->exp_error) {
1855 				printf("!!! got errno=%d, want %d\n",
1856 						errno, t->exp_error);
1857 				return -1;
1858 			}
1859 			if (ctx->ifparse != save) {
1860 				printf("!!! parse error, but first arg changed\n");
1861 				return -1;
1862 			}
1863 			if (memcmp(&orig_hdr, hdr, sizeof(*hdr))) {
1864 				printf("!!! parse error, but header changed\n");
1865 				return -1;
1866 			}
1867 			return 0;
1868 		}
1869 		printf ("!!! nmreq_header_decode was expected to succeed, but it failed with error %d\n", errno);
1870 		return -1;
1871 	}
1872 	if (t->exp_error > 0) {
1873 		printf("!!! nmreq_header_decode returns 0, but error %d was expected\n", t->exp_error);
1874 		return -1;
1875 	}
1876 	if (strcmp(t->exp_port, hdr->nr_name) != 0) {
1877 		printf("!!! got '%s', want '%s'\n", hdr->nr_name, t->exp_port);
1878 		return -1;
1879 	}
1880 	if (hdr->nr_reqtype != orig_hdr.nr_reqtype ||
1881 	    hdr->nr_options != orig_hdr.nr_options ||
1882 	    hdr->nr_body    != orig_hdr.nr_body) {
1883 		printf("!!! some fields of the nmreq_header where changed unexpectedly\n");
1884 		return -1;
1885 	}
1886 	return 0;
1887 }
1888 
1889 static int
1890 nmreq_reg_parsing(struct TestContext *ctx,
1891 		struct nmreq_parse_test *t,
1892 		struct nmreq_register *reg)
1893 {
1894 	const char *save;
1895 	struct nmreq_register orig_reg;
1896 
1897 
1898 	save = ctx->ifparse;
1899 	orig_reg = *reg;
1900 
1901 	printf("nmreq_register: \"%s\"\n", ctx->ifparse);
1902 	if (nmreq_register_decode(&ctx->ifparse, reg, ctx->nmctx) < 0) {
1903 		if (t->exp_error < 0) {
1904 			if (errno != -t->exp_error) {
1905 				printf("!!! got errno=%d, want %d\n",
1906 						errno, -t->exp_error);
1907 				return -1;
1908 			}
1909 			if (ctx->ifparse != save) {
1910 				printf("!!! parse error, but first arg changed\n");
1911 				return -1;
1912 			}
1913 			if (memcmp(&orig_reg, reg, sizeof(*reg))) {
1914 				printf("!!! parse error, but nmreq_register changed\n");
1915 				return -1;
1916 			}
1917 			return 0;
1918 		}
1919 		printf ("!!! parse failed but it should have succeeded\n");
1920 		return -1;
1921 	}
1922 	if (t->exp_error < 0) {
1923 		printf("!!! nmreq_register_decode returns 0, but error %d was expected\n", -t->exp_error);
1924 		return -1;
1925 	}
1926 	if (reg->nr_mode != t->exp_mode) {
1927 		printf("!!! got nr_mode '%d', want '%d'\n", reg->nr_mode, t->exp_mode);
1928 		return -1;
1929 	}
1930 	if (reg->nr_ringid != t->exp_ringid) {
1931 		printf("!!! got nr_ringid '%d', want '%d'\n", reg->nr_ringid, t->exp_ringid);
1932 		return -1;
1933 	}
1934 	if (reg->nr_flags != t->exp_flags) {
1935 		printf("!!! got nm_flags '%llx', want '%llx\n", (unsigned long long)reg->nr_flags,
1936 				(unsigned long long)t->exp_flags);
1937 		return -1;
1938 	}
1939 	if (reg->nr_offset     != orig_reg.nr_offset     ||
1940 	    reg->nr_memsize    != orig_reg.nr_memsize    ||
1941 	    reg->nr_tx_slots   != orig_reg.nr_tx_slots   ||
1942 	    reg->nr_rx_slots   != orig_reg.nr_rx_slots   ||
1943 	    reg->nr_tx_rings   != orig_reg.nr_tx_rings   ||
1944 	    reg->nr_rx_rings   != orig_reg.nr_rx_rings   ||
1945 	    reg->nr_extra_bufs != orig_reg.nr_extra_bufs)
1946 	{
1947 		printf("!!! some fields of the nmreq_register where changed unexpectedly\n");
1948 		return -1;
1949 	}
1950 	return 0;
1951 }
1952 
1953 static void
1954 nmctx_parsing_error(struct nmctx *ctx, const char *msg)
1955 {
1956 	(void)ctx;
1957 	printf("    got message: %s\n", msg);
1958 }
1959 
1960 static int
1961 nmreq_parsing(struct TestContext *ctx)
1962 {
1963 	struct nmreq_parse_test *t;
1964 	struct nmreq_header hdr;
1965 	struct nmreq_register reg;
1966 	struct nmctx test_nmctx, *nmctx;
1967 	int ret = 0;
1968 
1969 	nmctx = nmctx_get();
1970 	if (nmctx == NULL) {
1971 		printf("Failed to acquire nmctx: %s", strerror(errno));
1972 		return -1;
1973 	}
1974 	test_nmctx = *nmctx;
1975 	test_nmctx.error = nmctx_parsing_error;
1976 	ctx->nmctx = &test_nmctx;
1977 	for (t = nmreq_parse_tests; t->ifname != NULL; t++) {
1978 		const char *exp_suff = t->exp_suff != NULL ?
1979 			t->exp_suff : t->ifname;
1980 
1981 		randomize(&hdr, sizeof(hdr));
1982 		randomize(&reg, sizeof(reg));
1983 		reg.nr_mem_id = 0;
1984 		if (nmreq_hdr_parsing(ctx, t, &hdr) < 0) {
1985 			ret = -1;
1986 		} else if (t->exp_error <= 0 && nmreq_reg_parsing(ctx, t, &reg) < 0) {
1987 			ret = -1;
1988 		}
1989 		if (strcmp(ctx->ifparse, exp_suff) != 0) {
1990 			printf("!!! string suffix after parse is '%s', but it should be '%s'\n",
1991 					ctx->ifparse, exp_suff);
1992 			ret = -1;
1993 		}
1994 	}
1995 	ctx->nmctx = NULL;
1996 	return ret;
1997 }
1998 
1999 static int
2000 binarycomp(struct TestContext *ctx)
2001 {
2002 #define ckroff(f, o) do {\
2003 	if (offsetof(struct netmap_ring, f) != (o)) {\
2004 		printf("offset of netmap_ring.%s is %zd, but it should be %d",\
2005 				#f, offsetof(struct netmap_ring, f), (o));\
2006 		return -1;\
2007 	}\
2008 } while (0)
2009 
2010 	(void)ctx;
2011 
2012 	ckroff(buf_ofs, 0);
2013 	ckroff(num_slots, 8);
2014 	ckroff(nr_buf_size, 12);
2015 	ckroff(ringid, 16);
2016 	ckroff(dir, 18);
2017 	ckroff(head, 20);
2018 	ckroff(cur, 24);
2019 	ckroff(tail, 28);
2020 	ckroff(flags, 32);
2021 	ckroff(ts, 40);
2022 	ckroff(offset_mask, 56);
2023 	ckroff(buf_align, 64);
2024 	ckroff(sem, 128);
2025 	ckroff(slot, 256);
2026 
2027 	return 0;
2028 }
2029 
2030 static void
2031 usage(const char *prog)
2032 {
2033 	printf("%s -i IFNAME\n"
2034 	       "[-j TEST_NUM1[-[TEST_NUM2]] | -[TEST_NUM_2]]\n"
2035 	       "[-l (list test cases)]\n",
2036 	       prog);
2037 }
2038 
2039 struct mytest {
2040 	testfunc_t test;
2041 	const char *name;
2042 };
2043 
2044 #define decltest(f)                                                            \
2045 	{                                                                      \
2046 		.test = f, .name = #f                                          \
2047 	}
2048 
2049 static struct mytest tests[] = {
2050 	decltest(port_info_get),
2051 	decltest(port_register_hwall_host),
2052 	decltest(port_register_hwall),
2053 	decltest(port_register_hostall),
2054 	decltest(port_register_single_hw_pair),
2055 	decltest(port_register_single_host_pair),
2056 	decltest(port_register_hostall_many),
2057 	decltest(vale_attach_detach),
2058 	decltest(vale_attach_detach_host_rings),
2059 	decltest(vale_ephemeral_port_hdr_manipulation),
2060 	decltest(vale_persistent_port),
2061 	decltest(pools_info_get_and_register),
2062 	decltest(pools_info_get_empty_ifname),
2063 	decltest(pipe_master),
2064 	decltest(pipe_slave),
2065 	decltest(pipe_port_info_get),
2066 	decltest(pipe_pools_info_get),
2067 	decltest(vale_polling_enable_disable),
2068 	decltest(unsupported_option),
2069 	decltest(infinite_options),
2070 	decltest(infinite_options2),
2071 #ifdef CONFIG_NETMAP_EXTMEM
2072 	decltest(extmem_option),
2073 	decltest(bad_extmem_option),
2074 	decltest(duplicate_extmem_options),
2075 #endif /* CONFIG_NETMAP_EXTMEM */
2076 	decltest(csb_mode),
2077 	decltest(csb_mode_invalid_memory),
2078 	decltest(sync_kloop),
2079 	decltest(sync_kloop_eventfds_all),
2080 	decltest(sync_kloop_eventfds_all_tx),
2081 	decltest(sync_kloop_eventfds_all_direct),
2082 	decltest(sync_kloop_eventfds_all_direct_tx),
2083 	decltest(sync_kloop_eventfds_all_direct_rx),
2084 	decltest(sync_kloop_nocsb),
2085 	decltest(sync_kloop_csb_enable),
2086 	decltest(sync_kloop_conflict),
2087 	decltest(sync_kloop_eventfds_mismatch),
2088 	decltest(null_port),
2089 	decltest(null_port_all_zero),
2090 	decltest(null_port_sync),
2091 	decltest(legacy_regif_default),
2092 	decltest(legacy_regif_all_nic),
2093 	decltest(legacy_regif_12),
2094 	decltest(legacy_regif_sw),
2095 	decltest(legacy_regif_future),
2096 	decltest(legacy_regif_extra_bufs),
2097 	decltest(legacy_regif_extra_bufs_pipe),
2098 	decltest(legacy_regif_extra_bufs_pipe_vale),
2099 	decltest(nmreq_parsing),
2100 	decltest(binarycomp),
2101 };
2102 
2103 static void
2104 context_cleanup(struct TestContext *ctx)
2105 {
2106 	if (ctx->csb) {
2107 		free(ctx->csb);
2108 		ctx->csb = NULL;
2109 	}
2110 
2111 	close(ctx->fd);
2112 	ctx->fd = -1;
2113 }
2114 
2115 static int
2116 parse_interval(const char *arg, int *j, int *k)
2117 {
2118 	const char *scan = arg;
2119 	char *rest;
2120 
2121 	*j = 0;
2122 	*k = -1;
2123 	if (*scan == '-') {
2124 		scan++;
2125 		goto get_k;
2126 	}
2127 	if (!isdigit(*scan))
2128 		goto err;
2129 	*k = strtol(scan, &rest, 10);
2130 	*j = *k - 1;
2131 	scan = rest;
2132 	if (*scan == '-') {
2133 		*k = -1;
2134 		scan++;
2135 	}
2136 get_k:
2137 	if (*scan == '\0')
2138 		return 0;
2139 	if (!isdigit(*scan))
2140 		goto err;
2141 	*k = strtol(scan, &rest, 10);
2142 	scan = rest;
2143 	if (!(*scan == '\0'))
2144 		goto err;
2145 
2146 	return 0;
2147 
2148 err:
2149 	fprintf(stderr, "syntax error in '%s', must be num[-[num]] or -[num]\n", arg);
2150 	return -1;
2151 }
2152 
2153 #define ARGV_APPEND(_av, _ac, _x)\
2154 	do {\
2155 		assert((int)(_ac) < (int)(sizeof(_av)/sizeof((_av)[0])));\
2156 		(_av)[(_ac)++] = _x;\
2157 	} while (0)
2158 
2159 static void
2160 tap_cleanup(int signo)
2161 {
2162 	const char *av[8];
2163 	int ac = 0;
2164 
2165 	(void)signo;
2166 #ifdef __FreeBSD__
2167 	ARGV_APPEND(av, ac, "ifconfig");
2168 	ARGV_APPEND(av, ac, ctx_.ifname);
2169 	ARGV_APPEND(av, ac, "destroy");
2170 #else
2171 	ARGV_APPEND(av, ac, "ip");
2172 	ARGV_APPEND(av, ac, "link");
2173 	ARGV_APPEND(av, ac, "del");
2174 	ARGV_APPEND(av, ac, ctx_.ifname);
2175 #endif
2176 	ARGV_APPEND(av, ac, NULL);
2177 	if (exec_command(ac, av)) {
2178 		printf("Failed to destroy tap interface\n");
2179 	}
2180 }
2181 
2182 int
2183 main(int argc, char **argv)
2184 {
2185 	int create_tap = 1;
2186 	int num_tests;
2187 	int ret  = 0;
2188 	int j    = 0;
2189 	int k    = -1;
2190 	int list = 0;
2191 	int opt;
2192 	int i;
2193 
2194 #ifdef __FreeBSD__
2195 	PLAIN_REQUIRE_KERNEL_MODULE("if_tap", 0);
2196 	PLAIN_REQUIRE_KERNEL_MODULE("netmap", 0);
2197 #endif
2198 
2199 	memset(&ctx_, 0, sizeof(ctx_));
2200 
2201 	{
2202 		struct timespec t;
2203 		int idx;
2204 
2205 		clock_gettime(CLOCK_REALTIME, &t);
2206 		srand((unsigned int)t.tv_nsec);
2207 		idx = rand() % 8000 + 100;
2208 		snprintf(ctx_.ifname, sizeof(ctx_.ifname), "tap%d", idx);
2209 		idx = rand() % 800 + 100;
2210 		snprintf(ctx_.bdgname, sizeof(ctx_.bdgname), "vale%d", idx);
2211 	}
2212 
2213 	while ((opt = getopt(argc, argv, "hi:j:l")) != -1) {
2214 		switch (opt) {
2215 		case 'h':
2216 			usage(argv[0]);
2217 			return 0;
2218 
2219 		case 'i':
2220 			strncpy(ctx_.ifname, optarg, sizeof(ctx_.ifname) - 1);
2221 			create_tap = 0;
2222 			break;
2223 
2224 		case 'j':
2225 			if (parse_interval(optarg, &j, &k) < 0) {
2226 				usage(argv[0]);
2227 				return -1;
2228 			}
2229 			break;
2230 
2231 		case 'l':
2232 			list = 1;
2233 			create_tap = 0;
2234 			break;
2235 
2236 		default:
2237 			printf("    Unrecognized option %c\n", opt);
2238 			usage(argv[0]);
2239 			return -1;
2240 		}
2241 	}
2242 
2243 	num_tests = sizeof(tests) / sizeof(tests[0]);
2244 
2245 	if (j < 0 || j >= num_tests || k > num_tests) {
2246 		fprintf(stderr, "Test interval %d-%d out of range (%d-%d)\n",
2247 				j + 1, k, 1, num_tests + 1);
2248 		return -1;
2249 	}
2250 
2251 	if (k < 0)
2252 		k = num_tests;
2253 
2254 	if (list) {
2255 		printf("Available tests:\n");
2256 		for (i = 0; i < num_tests; i++) {
2257 			printf("#%03d: %s\n", i + 1, tests[i].name);
2258 		}
2259 		return 0;
2260 	}
2261 
2262 	if (create_tap) {
2263 		struct sigaction sa;
2264 		const char *av[8];
2265 		int ac = 0;
2266 #ifdef __FreeBSD__
2267 		ARGV_APPEND(av, ac, "ifconfig");
2268 		ARGV_APPEND(av, ac, ctx_.ifname);
2269 		ARGV_APPEND(av, ac, "create");
2270 		ARGV_APPEND(av, ac, "up");
2271 #else
2272 		ARGV_APPEND(av, ac, "ip");
2273 		ARGV_APPEND(av, ac, "tuntap");
2274 		ARGV_APPEND(av, ac, "add");
2275 		ARGV_APPEND(av, ac, "mode");
2276 		ARGV_APPEND(av, ac, "tap");
2277 		ARGV_APPEND(av, ac, "name");
2278 		ARGV_APPEND(av, ac, ctx_.ifname);
2279 #endif
2280 		ARGV_APPEND(av, ac, NULL);
2281 		if (exec_command(ac, av)) {
2282 			printf("Failed to create tap interface\n");
2283 			return -1;
2284 		}
2285 
2286 		sa.sa_handler = tap_cleanup;
2287 		sigemptyset(&sa.sa_mask);
2288 		sa.sa_flags = SA_RESTART;
2289 		ret         = sigaction(SIGINT, &sa, NULL);
2290 		if (ret) {
2291 			perror("sigaction(SIGINT)");
2292 			goto out;
2293 		}
2294 		ret = sigaction(SIGTERM, &sa, NULL);
2295 		if (ret) {
2296 			perror("sigaction(SIGTERM)");
2297 			goto out;
2298 		}
2299 	}
2300 
2301 	for (i = j; i < k; i++) {
2302 		struct TestContext ctxcopy;
2303 		int fd;
2304 		printf("==> Start of Test #%d [%s]\n", i + 1, tests[i].name);
2305 		fd = open("/dev/netmap", O_RDWR);
2306 		if (fd < 0) {
2307 			perror("open(/dev/netmap)");
2308 			ret = fd;
2309 			goto out;
2310 		}
2311 		memcpy(&ctxcopy, &ctx_, sizeof(ctxcopy));
2312 		ctxcopy.fd = fd;
2313 		memcpy(ctxcopy.ifname_ext, ctxcopy.ifname,
2314 			sizeof(ctxcopy.ifname));
2315 		ret        = tests[i].test(&ctxcopy);
2316 		if (ret != 0) {
2317 			printf("Test #%d [%s] failed\n", i + 1, tests[i].name);
2318 			goto out;
2319 		}
2320 		printf("==> Test #%d [%s] successful\n", i + 1, tests[i].name);
2321 		context_cleanup(&ctxcopy);
2322 	}
2323 out:
2324 	tap_cleanup(0);
2325 
2326 	return ret;
2327 }
2328