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