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