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