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