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