2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (C) 2018 Vincenzo Maffione
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
31 * This program contains a suite of unit tests for the netmap control device.
33 * On FreeBSD, you can run these tests with Kyua once installed in the system:
34 * # kyua test -k /usr/tests/sys/netmap/Kyuafile
36 * On Linux, you can run them directly:
40 #include <sys/ioctl.h>
49 #include <libnetmap.h>
51 #include <net/netmap.h>
53 #include <semaphore.h>
64 #include "freebsd_test_suite/macros.h"
67 eventfd(int x __unused, int y __unused)
73 #include <sys/eventfd.h>
79 exec_command(int argc, const char *const argv[])
86 printf("Executing command: ");
87 for (i = 0; i < argc - 1; i++) {
89 /* Invalid argument. */
95 printf("%s", argv[i]);
100 if (child_pid == 0) {
104 /* Child process. Redirect stdin, stdout
106 for (i = 0; i < 3; i++) {
108 fds[i] = open("/dev/null", O_RDONLY);
110 for (i--; i >= 0; i--) {
117 /* Make a copy of the arguments, passing them to execvp. */
118 av = calloc(argc, sizeof(av[0]));
122 for (i = 0; i < argc - 1; i++) {
123 av[i] = strdup(argv[i]);
133 wret = waitpid(child_pid, &child_status, 0);
135 fprintf(stderr, "waitpid() failed: %s\n", strerror(errno));
138 if (WIFEXITED(child_status)) {
139 return WEXITSTATUS(child_status);
146 #define THRET_SUCCESS ((void *)128)
147 #define THRET_FAILURE ((void *)0)
150 char ifname[NM_IFNAMSZ];
151 char ifname_ext[NM_IFNAMSZ];
152 char bdgname[NM_IFNAMSZ];
153 uint32_t nr_tx_slots; /* slots in tx rings */
154 uint32_t nr_rx_slots; /* slots in rx rings */
155 uint16_t nr_tx_rings; /* number of tx rings */
156 uint16_t nr_rx_rings; /* number of rx rings */
157 uint16_t nr_host_tx_rings; /* number of host tx rings */
158 uint16_t nr_host_rx_rings; /* number of host rx rings */
159 uint16_t nr_mem_id; /* id of the memory allocator */
160 uint16_t nr_ringid; /* ring(s) we care about */
161 uint32_t nr_mode; /* specify NR_REG_* modes */
162 uint32_t nr_extra_bufs; /* number of requested extra buffers */
163 uint64_t nr_flags; /* additional flags (see below) */
164 uint32_t nr_hdr_len; /* for PORT_HDR_SET and PORT_HDR_GET */
165 uint32_t nr_first_cpu_id; /* vale polling */
166 uint32_t nr_num_polling_cpus; /* vale polling */
167 uint32_t sync_kloop_mode; /* sync-kloop */
168 int fd; /* netmap file descriptor */
170 void *csb; /* CSB entries (atok and ktoa) */
171 struct nmreq_option *nr_opt; /* list of options */
172 sem_t *sem; /* for thread synchronization */
176 struct nmport_d *nmport; /* nmport descriptor from libnetmap */
179 static struct TestContext ctx_;
181 typedef int (*testfunc_t)(struct TestContext *ctx);
184 nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
186 memset(hdr, 0, sizeof(*hdr));
187 hdr->nr_version = NETMAP_API;
188 assert(strlen(ifname) < NM_IFNAMSZ);
189 strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name));
192 /* Single NETMAP_REQ_PORT_INFO_GET. */
194 port_info_get(struct TestContext *ctx)
196 struct nmreq_port_info_get req;
197 struct nmreq_header hdr;
201 printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ctx->ifname_ext);
203 nmreq_hdr_init(&hdr, ctx->ifname_ext);
204 hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
205 hdr.nr_body = (uintptr_t)&req;
206 memset(&req, 0, sizeof(req));
207 req.nr_mem_id = ctx->nr_mem_id;
208 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
210 perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
213 printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
214 printf("nr_tx_slots %u\n", req.nr_tx_slots);
215 printf("nr_rx_slots %u\n", req.nr_rx_slots);
216 printf("nr_tx_rings %u\n", req.nr_tx_rings);
217 printf("nr_rx_rings %u\n", req.nr_rx_rings);
218 printf("nr_mem_id %u\n", req.nr_mem_id);
220 success = req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
221 req.nr_tx_rings && req.nr_rx_rings && req.nr_tx_rings;
226 /* Write back results to the context structure. */
227 ctx->nr_tx_slots = req.nr_tx_slots;
228 ctx->nr_rx_slots = req.nr_rx_slots;
229 ctx->nr_tx_rings = req.nr_tx_rings;
230 ctx->nr_rx_rings = req.nr_rx_rings;
231 ctx->nr_mem_id = req.nr_mem_id;
236 /* Single NETMAP_REQ_REGISTER, no use. */
238 port_register(struct TestContext *ctx)
240 struct nmreq_register req;
241 struct nmreq_header hdr;
245 printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
246 "flags=0x%llx) on '%s'\n",
247 ctx->nr_mode, ctx->nr_ringid, (unsigned long long)ctx->nr_flags,
250 nmreq_hdr_init(&hdr, ctx->ifname_ext);
251 hdr.nr_reqtype = NETMAP_REQ_REGISTER;
252 hdr.nr_body = (uintptr_t)&req;
253 hdr.nr_options = (uintptr_t)ctx->nr_opt;
254 memset(&req, 0, sizeof(req));
255 req.nr_mem_id = ctx->nr_mem_id;
256 req.nr_mode = ctx->nr_mode;
257 req.nr_ringid = ctx->nr_ringid;
258 req.nr_flags = ctx->nr_flags;
259 req.nr_tx_slots = ctx->nr_tx_slots;
260 req.nr_rx_slots = ctx->nr_rx_slots;
261 req.nr_tx_rings = ctx->nr_tx_rings;
262 req.nr_host_tx_rings = ctx->nr_host_tx_rings;
263 req.nr_host_rx_rings = ctx->nr_host_rx_rings;
264 req.nr_rx_rings = ctx->nr_rx_rings;
265 req.nr_extra_bufs = ctx->nr_extra_bufs;
266 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
268 perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
271 printf("nr_offset 0x%llx\n", (unsigned long long)req.nr_offset);
272 printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
273 printf("nr_tx_slots %u\n", req.nr_tx_slots);
274 printf("nr_rx_slots %u\n", req.nr_rx_slots);
275 printf("nr_tx_rings %u\n", req.nr_tx_rings);
276 printf("nr_rx_rings %u\n", req.nr_rx_rings);
277 printf("nr_host_tx_rings %u\n", req.nr_host_tx_rings);
278 printf("nr_host_rx_rings %u\n", req.nr_host_rx_rings);
279 printf("nr_mem_id %u\n", req.nr_mem_id);
280 printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
282 success = req.nr_memsize && (ctx->nr_mode == req.nr_mode) &&
283 (ctx->nr_ringid == req.nr_ringid) &&
284 (ctx->nr_flags == req.nr_flags) &&
285 ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
286 (ctx->nr_tx_slots == req.nr_tx_slots)) &&
287 ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
288 (ctx->nr_rx_slots == req.nr_rx_slots)) &&
289 ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
290 (ctx->nr_tx_rings == req.nr_tx_rings)) &&
291 ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
292 (ctx->nr_rx_rings == req.nr_rx_rings)) &&
293 ((!ctx->nr_host_tx_rings && req.nr_host_tx_rings) ||
294 (ctx->nr_host_tx_rings == req.nr_host_tx_rings)) &&
295 ((!ctx->nr_host_rx_rings && req.nr_host_rx_rings) ||
296 (ctx->nr_host_rx_rings == req.nr_host_rx_rings)) &&
297 ((!ctx->nr_mem_id && req.nr_mem_id) ||
298 (ctx->nr_mem_id == req.nr_mem_id)) &&
299 (ctx->nr_extra_bufs == req.nr_extra_bufs);
304 /* Write back results to the context structure.*/
305 ctx->nr_tx_slots = req.nr_tx_slots;
306 ctx->nr_rx_slots = req.nr_rx_slots;
307 ctx->nr_tx_rings = req.nr_tx_rings;
308 ctx->nr_rx_rings = req.nr_rx_rings;
309 ctx->nr_host_tx_rings = req.nr_host_tx_rings;
310 ctx->nr_host_rx_rings = req.nr_host_rx_rings;
311 ctx->nr_mem_id = req.nr_mem_id;
312 ctx->nr_extra_bufs = req.nr_extra_bufs;
318 niocregif(struct TestContext *ctx, int netmap_api)
324 printf("Testing legacy NIOCREGIF on '%s'\n", ctx->ifname_ext);
326 memset(&req, 0, sizeof(req));
327 memcpy(req.nr_name, ctx->ifname_ext, sizeof(req.nr_name));
328 req.nr_name[sizeof(req.nr_name) - 1] = '\0';
329 req.nr_version = netmap_api;
330 req.nr_ringid = ctx->nr_ringid;
331 req.nr_flags = ctx->nr_mode | ctx->nr_flags;
332 req.nr_tx_slots = ctx->nr_tx_slots;
333 req.nr_rx_slots = ctx->nr_rx_slots;
334 req.nr_tx_rings = ctx->nr_tx_rings;
335 req.nr_rx_rings = ctx->nr_rx_rings;
336 req.nr_arg2 = ctx->nr_mem_id;
337 req.nr_arg3 = ctx->nr_extra_bufs;
339 ret = ioctl(ctx->fd, NIOCREGIF, &req);
341 perror("ioctl(/dev/netmap, NIOCREGIF)");
345 printf("nr_offset 0x%x\n", req.nr_offset);
346 printf("nr_memsize %u\n", req.nr_memsize);
347 printf("nr_tx_slots %u\n", req.nr_tx_slots);
348 printf("nr_rx_slots %u\n", req.nr_rx_slots);
349 printf("nr_tx_rings %u\n", req.nr_tx_rings);
350 printf("nr_rx_rings %u\n", req.nr_rx_rings);
351 printf("nr_version %d\n", req.nr_version);
352 printf("nr_ringid %x\n", req.nr_ringid);
353 printf("nr_flags %x\n", req.nr_flags);
354 printf("nr_arg2 %u\n", req.nr_arg2);
355 printf("nr_arg3 %u\n", req.nr_arg3);
357 success = req.nr_memsize &&
358 (ctx->nr_ringid == req.nr_ringid) &&
359 ((ctx->nr_mode | ctx->nr_flags) == req.nr_flags) &&
360 ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
361 (ctx->nr_tx_slots == req.nr_tx_slots)) &&
362 ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
363 (ctx->nr_rx_slots == req.nr_rx_slots)) &&
364 ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
365 (ctx->nr_tx_rings == req.nr_tx_rings)) &&
366 ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
367 (ctx->nr_rx_rings == req.nr_rx_rings)) &&
368 ((!ctx->nr_mem_id && req.nr_arg2) ||
369 (ctx->nr_mem_id == req.nr_arg2)) &&
370 (ctx->nr_extra_bufs == req.nr_arg3);
375 /* Write back results to the context structure.*/
376 ctx->nr_tx_slots = req.nr_tx_slots;
377 ctx->nr_rx_slots = req.nr_rx_slots;
378 ctx->nr_tx_rings = req.nr_tx_rings;
379 ctx->nr_rx_rings = req.nr_rx_rings;
380 ctx->nr_mem_id = req.nr_arg2;
381 ctx->nr_extra_bufs = req.nr_arg3;
386 /* The 11 ABI is the one right before the introduction of the new NIOCCTRL
387 * ABI. The 11 ABI is useful to perform tests with legacy applications
388 * (which use the 11 ABI) and new kernel (which uses 12, or higher).
389 * However, version 14 introduced a change in the layout of struct netmap_if,
390 * so that binary backward compatibility to 11 is not supported anymore.
392 #define NETMAP_API_NIOCREGIF 14
395 legacy_regif_default(struct TestContext *ctx)
397 return niocregif(ctx, NETMAP_API_NIOCREGIF);
401 legacy_regif_all_nic(struct TestContext *ctx)
403 ctx->nr_mode = NR_REG_ALL_NIC;
404 return niocregif(ctx, NETMAP_API);
408 legacy_regif_12(struct TestContext *ctx)
410 ctx->nr_mode = NR_REG_ALL_NIC;
411 return niocregif(ctx, NETMAP_API_NIOCREGIF+1);
415 legacy_regif_sw(struct TestContext *ctx)
417 ctx->nr_mode = NR_REG_SW;
418 return niocregif(ctx, NETMAP_API_NIOCREGIF);
422 legacy_regif_future(struct TestContext *ctx)
424 ctx->nr_mode = NR_REG_NIC_SW;
425 /* Test forward compatibility for the legacy ABI. This means
426 * using an older kernel (with ABI 12 or higher) and a newer
427 * application (with ABI greater than NETMAP_API). */
428 return niocregif(ctx, NETMAP_API+2);
432 legacy_regif_extra_bufs(struct TestContext *ctx)
434 ctx->nr_mode = NR_REG_ALL_NIC;
435 ctx->nr_extra_bufs = 20; /* arbitrary number of extra bufs */
436 return niocregif(ctx, NETMAP_API_NIOCREGIF);
440 legacy_regif_extra_bufs_pipe(struct TestContext *ctx)
442 strncat(ctx->ifname_ext, "{pipeexbuf", sizeof(ctx->ifname_ext));
443 ctx->nr_mode = NR_REG_ALL_NIC;
444 ctx->nr_extra_bufs = 58; /* arbitrary number of extra bufs */
446 return niocregif(ctx, NETMAP_API_NIOCREGIF);
450 legacy_regif_extra_bufs_pipe_vale(struct TestContext *ctx)
452 strncpy(ctx->ifname_ext, "valeX1:Y4", sizeof(ctx->ifname_ext));
453 return legacy_regif_extra_bufs_pipe(ctx);
456 /* Only valid after a successful port_register(). */
458 num_registered_rings(struct TestContext *ctx)
460 if (ctx->nr_flags & NR_TX_RINGS_ONLY) {
461 return ctx->nr_tx_rings;
463 if (ctx->nr_flags & NR_RX_RINGS_ONLY) {
464 return ctx->nr_rx_rings;
467 return ctx->nr_tx_rings + ctx->nr_rx_rings;
471 port_register_hwall_host(struct TestContext *ctx)
473 ctx->nr_mode = NR_REG_NIC_SW;
474 return port_register(ctx);
478 port_register_hostall(struct TestContext *ctx)
480 ctx->nr_mode = NR_REG_SW;
481 return port_register(ctx);
485 port_register_hwall(struct TestContext *ctx)
487 ctx->nr_mode = NR_REG_ALL_NIC;
488 return port_register(ctx);
492 port_register_single_hw_pair(struct TestContext *ctx)
494 ctx->nr_mode = NR_REG_ONE_NIC;
496 return port_register(ctx);
500 port_register_single_host_pair(struct TestContext *ctx)
502 ctx->nr_mode = NR_REG_ONE_SW;
503 ctx->nr_host_tx_rings = 2;
504 ctx->nr_host_rx_rings = 2;
506 return port_register(ctx);
510 port_register_hostall_many(struct TestContext *ctx)
512 ctx->nr_mode = NR_REG_SW;
513 ctx->nr_host_tx_rings = 5;
514 ctx->nr_host_rx_rings = 4;
515 return port_register(ctx);
519 port_register_hwall_tx(struct TestContext *ctx)
521 ctx->nr_mode = NR_REG_ALL_NIC;
522 ctx->nr_flags |= NR_TX_RINGS_ONLY;
523 return port_register(ctx);
527 port_register_hwall_rx(struct TestContext *ctx)
529 ctx->nr_mode = NR_REG_ALL_NIC;
530 ctx->nr_flags |= NR_RX_RINGS_ONLY;
531 return port_register(ctx);
536 vale_mkname(char *vpname, struct TestContext *ctx)
538 if (snprintf(vpname, NM_IFNAMSZ, "%s:%s", ctx->bdgname, ctx->ifname_ext) >= NM_IFNAMSZ) {
539 fprintf(stderr, "%s:%s too long (max %d chars)\n", ctx->bdgname, ctx->ifname_ext,
547 /* NETMAP_REQ_VALE_ATTACH */
549 vale_attach(struct TestContext *ctx)
551 struct nmreq_vale_attach req;
552 struct nmreq_header hdr;
553 char vpname[NM_IFNAMSZ];
556 if (vale_mkname(vpname, ctx) < 0)
559 printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
560 nmreq_hdr_init(&hdr, vpname);
561 hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
562 hdr.nr_body = (uintptr_t)&req;
563 memset(&req, 0, sizeof(req));
564 req.reg.nr_mem_id = ctx->nr_mem_id;
565 if (ctx->nr_mode == 0) {
566 ctx->nr_mode = NR_REG_ALL_NIC; /* default */
568 req.reg.nr_mode = ctx->nr_mode;
569 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
571 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
574 printf("nr_mem_id %u\n", req.reg.nr_mem_id);
576 return ((!ctx->nr_mem_id && req.reg.nr_mem_id > 1) ||
577 (ctx->nr_mem_id == req.reg.nr_mem_id)) &&
578 (ctx->nr_flags == req.reg.nr_flags)
583 /* NETMAP_REQ_VALE_DETACH */
585 vale_detach(struct TestContext *ctx)
587 struct nmreq_header hdr;
588 struct nmreq_vale_detach req;
589 char vpname[NM_IFNAMSZ];
592 if (vale_mkname(vpname, ctx) < 0)
595 printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
596 nmreq_hdr_init(&hdr, vpname);
597 hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
598 hdr.nr_body = (uintptr_t)&req;
599 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
601 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
608 /* First NETMAP_REQ_VALE_ATTACH, then NETMAP_REQ_VALE_DETACH. */
610 vale_attach_detach(struct TestContext *ctx)
614 if ((ret = vale_attach(ctx)) != 0) {
618 return vale_detach(ctx);
622 vale_attach_detach_host_rings(struct TestContext *ctx)
624 ctx->nr_mode = NR_REG_NIC_SW;
625 return vale_attach_detach(ctx);
628 /* First NETMAP_REQ_PORT_HDR_SET and the NETMAP_REQ_PORT_HDR_GET
629 * to check that we get the same value. */
631 port_hdr_set_and_get(struct TestContext *ctx)
633 struct nmreq_port_hdr req;
634 struct nmreq_header hdr;
637 printf("Testing NETMAP_REQ_PORT_HDR_SET on '%s'\n", ctx->ifname_ext);
639 nmreq_hdr_init(&hdr, ctx->ifname_ext);
640 hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
641 hdr.nr_body = (uintptr_t)&req;
642 memset(&req, 0, sizeof(req));
643 req.nr_hdr_len = ctx->nr_hdr_len;
644 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
646 perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
650 if (req.nr_hdr_len != ctx->nr_hdr_len) {
654 printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname_ext);
655 hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
657 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
659 perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
662 printf("nr_hdr_len %u\n", req.nr_hdr_len);
664 return (req.nr_hdr_len == ctx->nr_hdr_len) ? 0 : -1;
668 * Possible lengths for the VirtIO network header, as specified by
670 * http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html
672 #define VIRTIO_NET_HDR_LEN 10
673 #define VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS 12
676 vale_ephemeral_port_hdr_manipulation(struct TestContext *ctx)
680 strncpy(ctx->ifname_ext, "vale:eph0", sizeof(ctx->ifname_ext));
681 ctx->nr_mode = NR_REG_ALL_NIC;
682 if ((ret = port_register(ctx))) {
685 /* Try to set and get all the acceptable values. */
686 ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS;
687 if ((ret = port_hdr_set_and_get(ctx))) {
691 if ((ret = port_hdr_set_and_get(ctx))) {
694 ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN;
695 if ((ret = port_hdr_set_and_get(ctx))) {
702 vale_persistent_port(struct TestContext *ctx)
704 struct nmreq_vale_newif req;
705 struct nmreq_header hdr;
709 strncpy(ctx->ifname_ext, "per4", sizeof(ctx->ifname_ext));
711 printf("Testing NETMAP_REQ_VALE_NEWIF on '%s'\n", ctx->ifname_ext);
713 nmreq_hdr_init(&hdr, ctx->ifname_ext);
714 hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
715 hdr.nr_body = (uintptr_t)&req;
716 memset(&req, 0, sizeof(req));
717 req.nr_mem_id = ctx->nr_mem_id;
718 req.nr_tx_slots = ctx->nr_tx_slots;
719 req.nr_rx_slots = ctx->nr_rx_slots;
720 req.nr_tx_rings = ctx->nr_tx_rings;
721 req.nr_rx_rings = ctx->nr_rx_rings;
722 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
724 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
728 /* Attach the persistent VALE port to a switch and then detach. */
729 result = vale_attach_detach(ctx);
731 printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname_ext);
732 hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
733 hdr.nr_body = (uintptr_t)NULL;
734 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
736 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
745 /* Single NETMAP_REQ_POOLS_INFO_GET. */
747 pools_info_get(struct TestContext *ctx)
749 struct nmreq_pools_info req;
750 struct nmreq_header hdr;
753 printf("Testing NETMAP_REQ_POOLS_INFO_GET on '%s'\n", ctx->ifname_ext);
755 nmreq_hdr_init(&hdr, ctx->ifname_ext);
756 hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
757 hdr.nr_body = (uintptr_t)&req;
758 memset(&req, 0, sizeof(req));
759 req.nr_mem_id = ctx->nr_mem_id;
760 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
762 perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
765 printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
766 printf("nr_mem_id %u\n", req.nr_mem_id);
767 printf("nr_if_pool_offset 0x%llx\n",
768 (unsigned long long)req.nr_if_pool_offset);
769 printf("nr_if_pool_objtotal %u\n", req.nr_if_pool_objtotal);
770 printf("nr_if_pool_objsize %u\n", req.nr_if_pool_objsize);
771 printf("nr_ring_pool_offset 0x%llx\n",
772 (unsigned long long)req.nr_if_pool_offset);
773 printf("nr_ring_pool_objtotal %u\n", req.nr_ring_pool_objtotal);
774 printf("nr_ring_pool_objsize %u\n", req.nr_ring_pool_objsize);
775 printf("nr_buf_pool_offset 0x%llx\n",
776 (unsigned long long)req.nr_buf_pool_offset);
777 printf("nr_buf_pool_objtotal %u\n", req.nr_buf_pool_objtotal);
778 printf("nr_buf_pool_objsize %u\n", req.nr_buf_pool_objsize);
780 return req.nr_memsize && req.nr_if_pool_objtotal &&
781 req.nr_if_pool_objsize &&
782 req.nr_ring_pool_objtotal &&
783 req.nr_ring_pool_objsize &&
784 req.nr_buf_pool_objtotal &&
785 req.nr_buf_pool_objsize
791 pools_info_get_and_register(struct TestContext *ctx)
795 /* Check that we can get pools info before we register
796 * a netmap interface. */
797 ret = pools_info_get(ctx);
802 ctx->nr_mode = NR_REG_ONE_NIC;
803 ret = port_register(ctx);
809 /* Check that we can get pools info also after we register. */
810 return pools_info_get(ctx);
814 pools_info_get_empty_ifname(struct TestContext *ctx)
816 strncpy(ctx->ifname_ext, "", sizeof(ctx->ifname_ext));
817 return pools_info_get(ctx) != 0 ? 0 : -1;
821 pipe_master(struct TestContext *ctx)
823 strncat(ctx->ifname_ext, "{pipeid1", sizeof(ctx->ifname_ext));
824 ctx->nr_mode = NR_REG_NIC_SW;
826 if (port_register(ctx) == 0) {
827 printf("pipes should not accept NR_REG_NIC_SW\n");
830 ctx->nr_mode = NR_REG_ALL_NIC;
832 return port_register(ctx);
836 pipe_slave(struct TestContext *ctx)
838 strncat(ctx->ifname_ext, "}pipeid2", sizeof(ctx->ifname_ext));
839 ctx->nr_mode = NR_REG_ALL_NIC;
841 return port_register(ctx);
844 /* Test PORT_INFO_GET and POOLS_INFO_GET on a pipe. This is useful to test the
845 * registration request used internally by netmap. */
847 pipe_port_info_get(struct TestContext *ctx)
849 strncat(ctx->ifname_ext, "}pipeid3", sizeof(ctx->ifname_ext));
851 return port_info_get(ctx);
855 pipe_pools_info_get(struct TestContext *ctx)
857 strncat(ctx->ifname_ext, "{xid", sizeof(ctx->ifname_ext));
859 return pools_info_get(ctx);
862 /* NETMAP_REQ_VALE_POLLING_ENABLE */
864 vale_polling_enable(struct TestContext *ctx)
866 struct nmreq_vale_polling req;
867 struct nmreq_header hdr;
868 char vpname[NM_IFNAMSZ];
871 if (vale_mkname(vpname, ctx) < 0)
874 printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", vpname);
876 nmreq_hdr_init(&hdr, vpname);
877 hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
878 hdr.nr_body = (uintptr_t)&req;
879 memset(&req, 0, sizeof(req));
880 req.nr_mode = ctx->nr_mode;
881 req.nr_first_cpu_id = ctx->nr_first_cpu_id;
882 req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
883 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
885 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
889 return (req.nr_mode == ctx->nr_mode &&
890 req.nr_first_cpu_id == ctx->nr_first_cpu_id &&
891 req.nr_num_polling_cpus == ctx->nr_num_polling_cpus)
896 /* NETMAP_REQ_VALE_POLLING_DISABLE */
898 vale_polling_disable(struct TestContext *ctx)
900 struct nmreq_vale_polling req;
901 struct nmreq_header hdr;
902 char vpname[NM_IFNAMSZ];
905 if (vale_mkname(vpname, ctx) < 0)
908 printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", vpname);
910 nmreq_hdr_init(&hdr, vpname);
911 hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
912 hdr.nr_body = (uintptr_t)&req;
913 memset(&req, 0, sizeof(req));
914 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
916 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
924 vale_polling_enable_disable(struct TestContext *ctx)
928 if ((ret = vale_attach(ctx)) != 0) {
932 ctx->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
933 ctx->nr_num_polling_cpus = 1;
934 ctx->nr_first_cpu_id = 0;
935 if ((ret = vale_polling_enable(ctx))) {
938 /* NETMAP_REQ_VALE_POLLING_DISABLE is disabled on FreeBSD,
939 * because it is currently broken. We are happy to see that
947 if ((ret = vale_polling_disable(ctx))) {
952 return vale_detach(ctx);
956 push_option(struct nmreq_option *opt, struct TestContext *ctx)
958 opt->nro_next = (uintptr_t)ctx->nr_opt;
963 clear_options(struct TestContext *ctx)
969 checkoption(struct nmreq_option *opt, struct nmreq_option *exp)
971 if (opt->nro_next != exp->nro_next) {
972 printf("nro_next %p expected %p\n",
973 (void *)(uintptr_t)opt->nro_next,
974 (void *)(uintptr_t)exp->nro_next);
977 if (opt->nro_reqtype != exp->nro_reqtype) {
978 printf("nro_reqtype %u expected %u\n", opt->nro_reqtype,
982 if (opt->nro_status != exp->nro_status) {
983 printf("nro_status %u expected %u\n", opt->nro_status,
991 unsupported_option(struct TestContext *ctx)
993 struct nmreq_option opt, save;
995 printf("Testing unsupported option on %s\n", ctx->ifname_ext);
997 memset(&opt, 0, sizeof(opt));
998 opt.nro_reqtype = 1234;
999 push_option(&opt, ctx);
1002 if (port_register_hwall(ctx) >= 0)
1006 save.nro_status = EOPNOTSUPP;
1007 return checkoption(&opt, &save);
1011 infinite_options(struct TestContext *ctx)
1013 struct nmreq_option opt;
1015 printf("Testing infinite list of options on %s (invalid options)\n", ctx->ifname_ext);
1017 memset(&opt, 0, sizeof(opt));
1018 opt.nro_reqtype = NETMAP_REQ_OPT_MAX + 1;
1019 push_option(&opt, ctx);
1020 opt.nro_next = (uintptr_t)&opt;
1021 if (port_register_hwall(ctx) >= 0)
1024 return (errno == EMSGSIZE ? 0 : -1);
1028 infinite_options2(struct TestContext *ctx)
1030 struct nmreq_option opt;
1032 printf("Testing infinite list of options on %s (valid options)\n", ctx->ifname_ext);
1034 memset(&opt, 0, sizeof(opt));
1035 opt.nro_reqtype = NETMAP_REQ_OPT_OFFSETS;
1036 push_option(&opt, ctx);
1037 opt.nro_next = (uintptr_t)&opt;
1038 if (port_register_hwall(ctx) >= 0)
1041 return (errno == EINVAL ? 0 : -1);
1044 #ifdef CONFIG_NETMAP_EXTMEM
1046 change_param(const char *pname, unsigned long newv, unsigned long *poldv)
1049 char param[256] = "/sys/module/netmap/parameters/";
1053 strncat(param, pname, sizeof(param) - 1);
1055 f = fopen(param, "r+");
1060 if (fscanf(f, "%ld", &oldv) != 1) {
1068 if (fprintf(f, "%ld\n", newv) < 0) {
1074 printf("change_param: %s: %ld -> %ld\n", pname, oldv, newv);
1075 #endif /* __linux__ */
1080 push_extmem_option(struct TestContext *ctx, const struct nmreq_pools_info *pi,
1081 struct nmreq_opt_extmem *e)
1085 addr = mmap(NULL, pi->nr_memsize, PROT_READ | PROT_WRITE,
1086 MAP_ANONYMOUS | MAP_SHARED, -1, 0);
1087 if (addr == MAP_FAILED) {
1092 memset(e, 0, sizeof(*e));
1093 e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
1095 e->nro_usrptr = (uintptr_t)addr;
1097 push_option(&e->nro_opt, ctx);
1103 pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
1105 struct nmreq_opt_extmem *e;
1108 e = (struct nmreq_opt_extmem *)(uintptr_t)ctx->nr_opt;
1109 ctx->nr_opt = (struct nmreq_option *)(uintptr_t)ctx->nr_opt->nro_next;
1111 if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
1115 if (e->nro_usrptr != exp->nro_usrptr) {
1116 printf("usrptr %" PRIu64 " expected %" PRIu64 "\n",
1117 e->nro_usrptr, exp->nro_usrptr);
1120 if (e->nro_info.nr_memsize != exp->nro_info.nr_memsize) {
1121 printf("memsize %" PRIu64 " expected %" PRIu64 "\n",
1122 e->nro_info.nr_memsize, exp->nro_info.nr_memsize);
1126 if ((ret = munmap((void *)(uintptr_t)e->nro_usrptr,
1127 e->nro_info.nr_memsize)))
1134 _extmem_option(struct TestContext *ctx,
1135 const struct nmreq_pools_info *pi)
1137 struct nmreq_opt_extmem e, save;
1140 if ((ret = push_extmem_option(ctx, pi, &e)) < 0)
1145 strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
1146 ctx->nr_tx_slots = 16;
1147 ctx->nr_rx_slots = 16;
1149 if ((ret = port_register_hwall(ctx)))
1152 ret = pop_extmem_option(ctx, &save);
1158 pools_info_min_memsize(const struct nmreq_pools_info *pi)
1162 tot += pi->nr_if_pool_objtotal * pi->nr_if_pool_objsize;
1163 tot += pi->nr_ring_pool_objtotal * pi->nr_ring_pool_objsize;
1164 tot += pi->nr_buf_pool_objtotal * pi->nr_buf_pool_objsize;
1170 * Fill the specification of a netmap memory allocator to be
1171 * used with the 'struct nmreq_opt_extmem' option. Arbitrary
1172 * values are used for the parameters, but with enough netmap
1173 * rings, netmap ifs, and buffers to support a VALE port.
1176 pools_info_fill(struct nmreq_pools_info *pi)
1178 pi->nr_if_pool_objtotal = 2;
1179 pi->nr_if_pool_objsize = 1024;
1180 pi->nr_ring_pool_objtotal = 64;
1181 pi->nr_ring_pool_objsize = 512;
1182 pi->nr_buf_pool_objtotal = 4096;
1183 pi->nr_buf_pool_objsize = 2048;
1184 pi->nr_memsize = pools_info_min_memsize(pi);
1188 extmem_option(struct TestContext *ctx)
1190 struct nmreq_pools_info pools_info;
1192 pools_info_fill(&pools_info);
1194 printf("Testing extmem option on vale0:0\n");
1195 return _extmem_option(ctx, &pools_info);
1199 bad_extmem_option(struct TestContext *ctx)
1201 struct nmreq_pools_info pools_info;
1203 printf("Testing bad extmem option on vale0:0\n");
1205 pools_info_fill(&pools_info);
1206 /* Request a large ring size, to make sure that the kernel
1207 * rejects our request. */
1208 pools_info.nr_ring_pool_objsize = (1 << 20);
1210 return _extmem_option(ctx, &pools_info) < 0 ? 0 : -1;
1214 duplicate_extmem_options(struct TestContext *ctx)
1216 struct nmreq_opt_extmem e1, save1, e2, save2;
1217 struct nmreq_pools_info pools_info;
1220 printf("Testing duplicate extmem option on vale0:0\n");
1222 pools_info_fill(&pools_info);
1224 if ((ret = push_extmem_option(ctx, &pools_info, &e1)) < 0)
1227 if ((ret = push_extmem_option(ctx, &pools_info, &e2)) < 0) {
1235 strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
1236 ctx->nr_tx_slots = 16;
1237 ctx->nr_rx_slots = 16;
1239 ret = port_register_hwall(ctx);
1241 printf("duplicate option not detected\n");
1245 save2.nro_opt.nro_status = EINVAL;
1246 if ((ret = pop_extmem_option(ctx, &save2)))
1249 save1.nro_opt.nro_status = EINVAL;
1250 if ((ret = pop_extmem_option(ctx, &save1)))
1255 #endif /* CONFIG_NETMAP_EXTMEM */
1258 push_csb_option(struct TestContext *ctx, struct nmreq_opt_csb *opt)
1264 ctx->nr_flags |= NR_EXCLUSIVE;
1266 /* Get port info in order to use num_registered_rings(). */
1267 ret = port_info_get(ctx);
1271 num_entries = num_registered_rings(ctx);
1273 csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
1275 assert(csb_size > 0);
1279 ret = posix_memalign(&ctx->csb, sizeof(struct nm_csb_atok), csb_size);
1281 printf("Failed to allocate CSB memory\n");
1285 memset(opt, 0, sizeof(*opt));
1286 opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
1287 opt->csb_atok = (uintptr_t)ctx->csb;
1288 opt->csb_ktoa = (uintptr_t)(((uint8_t *)ctx->csb) +
1289 sizeof(struct nm_csb_atok) * num_entries);
1291 printf("Pushing option NETMAP_REQ_OPT_CSB\n");
1292 push_option(&opt->nro_opt, ctx);
1298 csb_mode(struct TestContext *ctx)
1300 struct nmreq_opt_csb opt;
1303 ret = push_csb_option(ctx, &opt);
1308 ret = port_register_hwall(ctx);
1315 csb_mode_invalid_memory(struct TestContext *ctx)
1317 struct nmreq_opt_csb opt;
1320 memset(&opt, 0, sizeof(opt));
1321 opt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
1322 opt.csb_atok = (uintptr_t)0x10;
1323 opt.csb_ktoa = (uintptr_t)0x800;
1324 push_option(&opt.nro_opt, ctx);
1326 ctx->nr_flags = NR_EXCLUSIVE;
1327 ret = port_register_hwall(ctx);
1330 return (ret < 0) ? 0 : -1;
1334 sync_kloop_stop(struct TestContext *ctx)
1336 struct nmreq_header hdr;
1339 printf("Testing NETMAP_REQ_SYNC_KLOOP_STOP on '%s'\n", ctx->ifname_ext);
1341 nmreq_hdr_init(&hdr, ctx->ifname_ext);
1342 hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
1343 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
1345 perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
1352 sync_kloop_worker(void *opaque)
1354 struct TestContext *ctx = opaque;
1355 struct nmreq_sync_kloop_start req;
1356 struct nmreq_header hdr;
1359 printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname_ext);
1361 nmreq_hdr_init(&hdr, ctx->ifname_ext);
1362 hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
1363 hdr.nr_body = (uintptr_t)&req;
1364 hdr.nr_options = (uintptr_t)ctx->nr_opt;
1365 memset(&req, 0, sizeof(req));
1367 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
1369 perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
1376 pthread_exit(ret ? (void *)THRET_FAILURE : (void *)THRET_SUCCESS);
1380 sync_kloop_start_stop(struct TestContext *ctx)
1383 void *thret = THRET_FAILURE;
1386 ret = pthread_create(&th, NULL, sync_kloop_worker, ctx);
1388 printf("pthread_create(kloop): %s\n", strerror(ret));
1392 ret = sync_kloop_stop(ctx);
1397 ret = pthread_join(th, &thret);
1399 printf("pthread_join(kloop): %s\n", strerror(ret));
1402 return thret == THRET_SUCCESS ? 0 : -1;
1406 sync_kloop(struct TestContext *ctx)
1410 ret = csb_mode(ctx);
1415 return sync_kloop_start_stop(ctx);
1419 sync_kloop_eventfds(struct TestContext *ctx)
1421 struct nmreq_opt_sync_kloop_eventfds *evopt = NULL;
1422 struct nmreq_opt_sync_kloop_mode modeopt;
1423 struct nmreq_option evsave;
1428 memset(&modeopt, 0, sizeof(modeopt));
1429 modeopt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_MODE;
1430 modeopt.mode = ctx->sync_kloop_mode;
1431 push_option(&modeopt.nro_opt, ctx);
1433 num_entries = num_registered_rings(ctx);
1434 opt_size = sizeof(*evopt) + num_entries * sizeof(evopt->eventfds[0]);
1435 evopt = calloc(1, opt_size);
1436 evopt->nro_opt.nro_next = 0;
1437 evopt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
1438 evopt->nro_opt.nro_status = 0;
1439 evopt->nro_opt.nro_size = opt_size;
1440 for (i = 0; i < num_entries; i++) {
1441 int efd = eventfd(0, 0);
1443 evopt->eventfds[i].ioeventfd = efd;
1444 efd = eventfd(0, 0);
1445 evopt->eventfds[i].irqfd = efd;
1448 push_option(&evopt->nro_opt, ctx);
1449 evsave = evopt->nro_opt;
1451 ret = sync_kloop_start_stop(ctx);
1458 evsave.nro_status = 0;
1459 #else /* !__linux__ */
1460 evsave.nro_status = EOPNOTSUPP;
1461 #endif /* !__linux__ */
1463 ret = checkoption(&evopt->nro_opt, &evsave);
1471 sync_kloop_eventfds_all_mode(struct TestContext *ctx,
1472 uint32_t sync_kloop_mode)
1476 ret = csb_mode(ctx);
1481 ctx->sync_kloop_mode = sync_kloop_mode;
1483 return sync_kloop_eventfds(ctx);
1487 sync_kloop_eventfds_all(struct TestContext *ctx)
1489 return sync_kloop_eventfds_all_mode(ctx, 0);
1493 sync_kloop_eventfds_all_tx(struct TestContext *ctx)
1495 struct nmreq_opt_csb opt;
1498 ret = push_csb_option(ctx, &opt);
1503 ret = port_register_hwall_tx(ctx);
1509 return sync_kloop_eventfds(ctx);
1513 sync_kloop_eventfds_all_direct(struct TestContext *ctx)
1515 return sync_kloop_eventfds_all_mode(ctx,
1516 NM_OPT_SYNC_KLOOP_DIRECT_TX | NM_OPT_SYNC_KLOOP_DIRECT_RX);
1520 sync_kloop_eventfds_all_direct_tx(struct TestContext *ctx)
1522 return sync_kloop_eventfds_all_mode(ctx,
1523 NM_OPT_SYNC_KLOOP_DIRECT_TX);
1527 sync_kloop_eventfds_all_direct_rx(struct TestContext *ctx)
1529 return sync_kloop_eventfds_all_mode(ctx,
1530 NM_OPT_SYNC_KLOOP_DIRECT_RX);
1534 sync_kloop_nocsb(struct TestContext *ctx)
1538 ret = port_register_hwall(ctx);
1543 /* Sync kloop must fail because we did not use
1544 * NETMAP_REQ_CSB_ENABLE. */
1545 return sync_kloop_start_stop(ctx) != 0 ? 0 : -1;
1549 csb_enable(struct TestContext *ctx)
1551 struct nmreq_option saveopt;
1552 struct nmreq_opt_csb opt;
1553 struct nmreq_header hdr;
1556 ret = push_csb_option(ctx, &opt);
1560 saveopt = opt.nro_opt;
1561 saveopt.nro_status = 0;
1563 nmreq_hdr_init(&hdr, ctx->ifname_ext);
1564 hdr.nr_reqtype = NETMAP_REQ_CSB_ENABLE;
1565 hdr.nr_options = (uintptr_t)ctx->nr_opt;
1566 hdr.nr_body = (uintptr_t)NULL;
1568 printf("Testing NETMAP_REQ_CSB_ENABLE on '%s'\n", ctx->ifname_ext);
1570 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
1572 perror("ioctl(/dev/netmap, NIOCCTRL, CSB_ENABLE)");
1576 ret = checkoption(&opt.nro_opt, &saveopt);
1583 sync_kloop_csb_enable(struct TestContext *ctx)
1587 ctx->nr_flags |= NR_EXCLUSIVE;
1588 ret = port_register_hwall(ctx);
1593 ret = csb_enable(ctx);
1598 return sync_kloop_start_stop(ctx);
1602 sync_kloop_conflict(struct TestContext *ctx)
1604 struct nmreq_opt_csb opt;
1606 void *thret1 = THRET_FAILURE, *thret2 = THRET_FAILURE;
1612 ret = push_csb_option(ctx, &opt);
1617 ret = port_register_hwall(ctx);
1623 ret = sem_init(&sem, 0, 0);
1625 printf("sem_init() failed: %s\n", strerror(ret));
1630 ret = pthread_create(&th1, NULL, sync_kloop_worker, ctx);
1633 printf("pthread_create(kloop1): %s\n", strerror(ret));
1636 ret = pthread_create(&th2, NULL, sync_kloop_worker, ctx);
1639 printf("pthread_create(kloop2): %s\n", strerror(ret));
1642 /* Wait for one of the two threads to fail to start the kloop, to
1643 * avoid a race condition where th1 starts the loop and stops,
1644 * and after that th2 starts the loop successfully. */
1645 clock_gettime(CLOCK_REALTIME, &to);
1647 ret = sem_timedwait(&sem, &to);
1650 printf("sem_timedwait() failed: %s\n", strerror(errno));
1653 err |= sync_kloop_stop(ctx);
1655 ret = pthread_join(th1, &thret1);
1658 printf("pthread_join(kloop1): %s\n", strerror(ret));
1661 ret = pthread_join(th2, &thret2);
1664 printf("pthread_join(kloop2): %s %d\n", strerror(ret), ret);
1673 /* Check that one of the two failed, while the other one succeeded. */
1674 return ((thret1 == THRET_SUCCESS && thret2 == THRET_FAILURE) ||
1675 (thret1 == THRET_FAILURE && thret2 == THRET_SUCCESS))
1681 sync_kloop_eventfds_mismatch(struct TestContext *ctx)
1683 struct nmreq_opt_csb opt;
1686 ret = push_csb_option(ctx, &opt);
1691 ret = port_register_hwall_rx(ctx);
1697 /* Deceive num_registered_rings() to trigger a failure of
1698 * sync_kloop_eventfds(). The latter will think that all the
1699 * rings were registered, and allocate the wrong number of
1701 ctx->nr_flags &= ~NR_RX_RINGS_ONLY;
1703 return (sync_kloop_eventfds(ctx) != 0) ? 0 : -1;
1707 null_port(struct TestContext *ctx)
1712 ctx->nr_mode = NR_REG_NULL;
1713 ctx->nr_tx_rings = 10;
1714 ctx->nr_rx_rings = 5;
1715 ctx->nr_tx_slots = 256;
1716 ctx->nr_rx_slots = 100;
1717 ret = port_register(ctx);
1725 null_port_all_zero(struct TestContext *ctx)
1730 ctx->nr_mode = NR_REG_NULL;
1731 ctx->nr_tx_rings = 0;
1732 ctx->nr_rx_rings = 0;
1733 ctx->nr_tx_slots = 0;
1734 ctx->nr_rx_slots = 0;
1735 ret = port_register(ctx);
1743 null_port_sync(struct TestContext *ctx)
1748 ctx->nr_mode = NR_REG_NULL;
1749 ctx->nr_tx_rings = 10;
1750 ctx->nr_rx_rings = 5;
1751 ctx->nr_tx_slots = 256;
1752 ctx->nr_rx_slots = 100;
1753 ret = port_register(ctx);
1757 ret = ioctl(ctx->fd, NIOCTXSYNC, 0);
1764 struct nmreq_parse_test {
1766 const char *exp_port;
1767 const char *exp_suff;
1770 uint16_t exp_ringid;
1774 static struct nmreq_parse_test nmreq_parse_tests[] = {
1775 /* port spec is the input. The expected results are as follows:
1776 * - port: what should go into hdr.nr_name
1777 * - suff: the trailing part of the input after parsing (NULL means equal to port spec)
1778 * - err: the expected return value, interpreted as follows
1779 * err > 0 => nmreq_header_parse should fail with the given error
1780 * err < 0 => nrmeq_header_parse should succeed, but nmreq_register_decode should
1781 * fail with error |err|
1782 * err = 0 => should succeed
1783 * - mode, ringid flags: what should go into the corresponding nr_* fields in the
1784 * nmreq_register struct in case of success
1787 /*port spec*/ /*port*/ /*suff*/ /*err*/ /*mode*/ /*ringid*/ /*flags*/
1788 { "netmap:eth0", "eth0", "", 0, NR_REG_ALL_NIC, 0, 0 },
1789 { "netmap:eth0-1", "eth0", "", 0, NR_REG_ONE_NIC, 1, 0 },
1790 { "netmap:eth0-", "eth0", "-", -EINVAL,0, 0, 0 },
1791 { "netmap:eth0/x", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_EXCLUSIVE },
1792 { "netmap:eth0/z", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_ZCOPY_MON },
1793 { "netmap:eth0/r", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_MONITOR_RX },
1794 { "netmap:eth0/t", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_MONITOR_TX },
1795 { "netmap:eth0-2/Tx", "eth0", "", 0, NR_REG_ONE_NIC, 2, NR_TX_RINGS_ONLY|NR_EXCLUSIVE },
1796 { "netmap:eth0*", "eth0", "", 0, NR_REG_NIC_SW, 0, 0 },
1797 { "netmap:eth0^", "eth0", "", 0, NR_REG_SW, 0, 0 },
1798 { "netmap:eth0@2", "eth0", "", 0, NR_REG_ALL_NIC, 0, 0 },
1799 { "netmap:eth0@2/R", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_RX_RINGS_ONLY },
1800 { "netmap:eth0@netmap:lo/R", "eth0", "@netmap:lo/R", 0, NR_REG_ALL_NIC, 0, 0 },
1801 { "netmap:eth0/R@xxx", "eth0", "@xxx", 0, NR_REG_ALL_NIC, 0, NR_RX_RINGS_ONLY },
1802 { "netmap:eth0@2/R@2", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_RX_RINGS_ONLY },
1803 { "netmap:eth0@2/R@3", "eth0", "@2/R@3", -EINVAL,0, 0, 0 },
1804 { "netmap:eth0@", "eth0", "@", -EINVAL,0, 0, 0 },
1805 { "netmap:", "", NULL, EINVAL, 0, 0, 0 },
1806 { "netmap:^", "", NULL, EINVAL, 0, 0, 0 },
1807 { "netmap:{", "", NULL, EINVAL, 0, 0, 0 },
1808 { "netmap:vale0:0", NULL, NULL, EINVAL, 0, 0, 0 },
1809 { "eth0", NULL, NULL, EINVAL, 0, 0, 0 },
1810 { "vale0:0", "vale0:0", "", 0, NR_REG_ALL_NIC, 0, 0 },
1811 { "vale:0", "vale:0", "", 0, NR_REG_ALL_NIC, 0, 0 },
1812 { "valeXXX:YYY", "valeXXX:YYY", "", 0, NR_REG_ALL_NIC, 0, 0 },
1813 { "valeXXX:YYY-4", "valeXXX:YYY", "", 0, NR_REG_ONE_NIC, 4, 0 },
1814 { "netmapXXX:eth0", NULL, NULL, EINVAL, 0, 0, 0 },
1815 { "netmap:14", "14", "", 0, NR_REG_ALL_NIC, 0, 0 },
1816 { "netmap:eth0&", NULL, NULL, EINVAL, 0, 0, 0 },
1817 { "netmap:pipe{0", "pipe{0", "", 0, NR_REG_ALL_NIC, 0, 0 },
1818 { "netmap:pipe{in", "pipe{in", "", 0, NR_REG_ALL_NIC, 0, 0 },
1819 { "netmap:pipe{in-7", "pipe{in", "", 0, NR_REG_ONE_NIC, 7, 0 },
1820 { "vale0:0{0", "vale0:0{0", "", 0, NR_REG_ALL_NIC, 0, 0 },
1821 { "netmap:pipe{1}2", NULL, NULL, EINVAL, 0, 0, 0 },
1822 { "vale0:0@opt", "vale0:0", "@opt", 0, NR_REG_ALL_NIC, 0, 0 },
1823 { "vale0:0/Tx@opt", "vale0:0", "@opt", 0, NR_REG_ALL_NIC, 0, NR_TX_RINGS_ONLY|NR_EXCLUSIVE },
1824 { "vale0:0-3@opt", "vale0:0", "@opt", 0, NR_REG_ONE_NIC, 3, 0 },
1825 { "vale0:0@", "vale0:0", "@", -EINVAL,0, 0, 0 },
1826 { "", NULL, NULL, EINVAL, 0, 0, 0 },
1827 { NULL, NULL, NULL, 0, 0, 0, 0 },
1831 randomize(void *dst, size_t n)
1836 for (i = 0; i < n; i++)
1837 dst_[i] = (char)random();
1841 nmreq_hdr_parsing(struct TestContext *ctx,
1842 struct nmreq_parse_test *t,
1843 struct nmreq_header *hdr)
1846 struct nmreq_header orig_hdr;
1848 save = ctx->ifparse = t->ifname;
1851 printf("nmreq_header: \"%s\"\n", ctx->ifparse);
1852 if (nmreq_header_decode(&ctx->ifparse, hdr, ctx->nmctx) < 0) {
1853 if (t->exp_error > 0) {
1854 if (errno != t->exp_error) {
1855 printf("!!! got errno=%d, want %d\n",
1856 errno, t->exp_error);
1859 if (ctx->ifparse != save) {
1860 printf("!!! parse error, but first arg changed\n");
1863 if (memcmp(&orig_hdr, hdr, sizeof(*hdr))) {
1864 printf("!!! parse error, but header changed\n");
1869 printf ("!!! nmreq_header_decode was expected to succeed, but it failed with error %d\n", errno);
1872 if (t->exp_error > 0) {
1873 printf("!!! nmreq_header_decode returns 0, but error %d was expected\n", t->exp_error);
1876 if (strcmp(t->exp_port, hdr->nr_name) != 0) {
1877 printf("!!! got '%s', want '%s'\n", hdr->nr_name, t->exp_port);
1880 if (hdr->nr_reqtype != orig_hdr.nr_reqtype ||
1881 hdr->nr_options != orig_hdr.nr_options ||
1882 hdr->nr_body != orig_hdr.nr_body) {
1883 printf("!!! some fields of the nmreq_header where changed unexpectedly\n");
1890 nmreq_reg_parsing(struct TestContext *ctx,
1891 struct nmreq_parse_test *t,
1892 struct nmreq_register *reg)
1895 struct nmreq_register orig_reg;
1898 save = ctx->ifparse;
1901 printf("nmreq_register: \"%s\"\n", ctx->ifparse);
1902 if (nmreq_register_decode(&ctx->ifparse, reg, ctx->nmctx) < 0) {
1903 if (t->exp_error < 0) {
1904 if (errno != -t->exp_error) {
1905 printf("!!! got errno=%d, want %d\n",
1906 errno, -t->exp_error);
1909 if (ctx->ifparse != save) {
1910 printf("!!! parse error, but first arg changed\n");
1913 if (memcmp(&orig_reg, reg, sizeof(*reg))) {
1914 printf("!!! parse error, but nmreq_register changed\n");
1919 printf ("!!! parse failed but it should have succeeded\n");
1922 if (t->exp_error < 0) {
1923 printf("!!! nmreq_register_decode returns 0, but error %d was expected\n", -t->exp_error);
1926 if (reg->nr_mode != t->exp_mode) {
1927 printf("!!! got nr_mode '%d', want '%d'\n", reg->nr_mode, t->exp_mode);
1930 if (reg->nr_ringid != t->exp_ringid) {
1931 printf("!!! got nr_ringid '%d', want '%d'\n", reg->nr_ringid, t->exp_ringid);
1934 if (reg->nr_flags != t->exp_flags) {
1935 printf("!!! got nm_flags '%llx', want '%llx\n", (unsigned long long)reg->nr_flags,
1936 (unsigned long long)t->exp_flags);
1939 if (reg->nr_offset != orig_reg.nr_offset ||
1940 reg->nr_memsize != orig_reg.nr_memsize ||
1941 reg->nr_tx_slots != orig_reg.nr_tx_slots ||
1942 reg->nr_rx_slots != orig_reg.nr_rx_slots ||
1943 reg->nr_tx_rings != orig_reg.nr_tx_rings ||
1944 reg->nr_rx_rings != orig_reg.nr_rx_rings ||
1945 reg->nr_extra_bufs != orig_reg.nr_extra_bufs)
1947 printf("!!! some fields of the nmreq_register where changed unexpectedly\n");
1954 nmctx_parsing_error(struct nmctx *ctx, const char *msg)
1957 printf(" got message: %s\n", msg);
1961 nmreq_parsing(struct TestContext *ctx)
1963 struct nmreq_parse_test *t;
1964 struct nmreq_header hdr;
1965 struct nmreq_register reg;
1966 struct nmctx test_nmctx, *nmctx;
1969 nmctx = nmctx_get();
1970 if (nmctx == NULL) {
1971 printf("Failed to acquire nmctx: %s", strerror(errno));
1974 test_nmctx = *nmctx;
1975 test_nmctx.error = nmctx_parsing_error;
1976 ctx->nmctx = &test_nmctx;
1977 for (t = nmreq_parse_tests; t->ifname != NULL; t++) {
1978 const char *exp_suff = t->exp_suff != NULL ?
1979 t->exp_suff : t->ifname;
1981 randomize(&hdr, sizeof(hdr));
1982 randomize(®, sizeof(reg));
1984 if (nmreq_hdr_parsing(ctx, t, &hdr) < 0) {
1986 } else if (t->exp_error <= 0 && nmreq_reg_parsing(ctx, t, ®) < 0) {
1989 if (strcmp(ctx->ifparse, exp_suff) != 0) {
1990 printf("!!! string suffix after parse is '%s', but it should be '%s'\n",
1991 ctx->ifparse, exp_suff);
2000 binarycomp(struct TestContext *ctx)
2002 #define ckroff(f, o) do {\
2003 if (offsetof(struct netmap_ring, f) != (o)) {\
2004 printf("offset of netmap_ring.%s is %zd, but it should be %d",\
2005 #f, offsetof(struct netmap_ring, f), (o));\
2013 ckroff(num_slots, 8);
2014 ckroff(nr_buf_size, 12);
2022 ckroff(offset_mask, 56);
2023 ckroff(buf_align, 64);
2031 usage(const char *prog)
2033 printf("%s -i IFNAME\n"
2034 "[-j TEST_NUM1[-[TEST_NUM2]] | -[TEST_NUM_2]]\n"
2035 "[-l (list test cases)]\n",
2044 #define decltest(f) \
2046 .test = f, .name = #f \
2049 static struct mytest tests[] = {
2050 decltest(port_info_get),
2051 decltest(port_register_hwall_host),
2052 decltest(port_register_hwall),
2053 decltest(port_register_hostall),
2054 decltest(port_register_single_hw_pair),
2055 decltest(port_register_single_host_pair),
2056 decltest(port_register_hostall_many),
2057 decltest(vale_attach_detach),
2058 decltest(vale_attach_detach_host_rings),
2059 decltest(vale_ephemeral_port_hdr_manipulation),
2060 decltest(vale_persistent_port),
2061 decltest(pools_info_get_and_register),
2062 decltest(pools_info_get_empty_ifname),
2063 decltest(pipe_master),
2064 decltest(pipe_slave),
2065 decltest(pipe_port_info_get),
2066 decltest(pipe_pools_info_get),
2067 decltest(vale_polling_enable_disable),
2068 decltest(unsupported_option),
2069 decltest(infinite_options),
2070 decltest(infinite_options2),
2071 #ifdef CONFIG_NETMAP_EXTMEM
2072 decltest(extmem_option),
2073 decltest(bad_extmem_option),
2074 decltest(duplicate_extmem_options),
2075 #endif /* CONFIG_NETMAP_EXTMEM */
2077 decltest(csb_mode_invalid_memory),
2078 decltest(sync_kloop),
2079 decltest(sync_kloop_eventfds_all),
2080 decltest(sync_kloop_eventfds_all_tx),
2081 decltest(sync_kloop_eventfds_all_direct),
2082 decltest(sync_kloop_eventfds_all_direct_tx),
2083 decltest(sync_kloop_eventfds_all_direct_rx),
2084 decltest(sync_kloop_nocsb),
2085 decltest(sync_kloop_csb_enable),
2086 decltest(sync_kloop_conflict),
2087 decltest(sync_kloop_eventfds_mismatch),
2088 decltest(null_port),
2089 decltest(null_port_all_zero),
2090 decltest(null_port_sync),
2091 decltest(legacy_regif_default),
2092 decltest(legacy_regif_all_nic),
2093 decltest(legacy_regif_12),
2094 decltest(legacy_regif_sw),
2095 decltest(legacy_regif_future),
2096 decltest(legacy_regif_extra_bufs),
2097 decltest(legacy_regif_extra_bufs_pipe),
2098 decltest(legacy_regif_extra_bufs_pipe_vale),
2099 decltest(nmreq_parsing),
2100 decltest(binarycomp),
2104 context_cleanup(struct TestContext *ctx)
2116 parse_interval(const char *arg, int *j, int *k)
2118 const char *scan = arg;
2127 if (!isdigit(*scan))
2129 *k = strtol(scan, &rest, 10);
2139 if (!isdigit(*scan))
2141 *k = strtol(scan, &rest, 10);
2143 if (!(*scan == '\0'))
2149 fprintf(stderr, "syntax error in '%s', must be num[-[num]] or -[num]\n", arg);
2153 #define ARGV_APPEND(_av, _ac, _x)\
2155 assert((int)(_ac) < (int)(sizeof(_av)/sizeof((_av)[0])));\
2156 (_av)[(_ac)++] = _x;\
2160 tap_cleanup(int signo)
2167 ARGV_APPEND(av, ac, "ifconfig");
2168 ARGV_APPEND(av, ac, ctx_.ifname);
2169 ARGV_APPEND(av, ac, "destroy");
2171 ARGV_APPEND(av, ac, "ip");
2172 ARGV_APPEND(av, ac, "link");
2173 ARGV_APPEND(av, ac, "del");
2174 ARGV_APPEND(av, ac, ctx_.ifname);
2176 ARGV_APPEND(av, ac, NULL);
2177 if (exec_command(ac, av)) {
2178 printf("Failed to destroy tap interface\n");
2183 main(int argc, char **argv)
2195 PLAIN_REQUIRE_KERNEL_MODULE("if_tap", 0);
2196 PLAIN_REQUIRE_KERNEL_MODULE("netmap", 0);
2199 memset(&ctx_, 0, sizeof(ctx_));
2205 clock_gettime(CLOCK_REALTIME, &t);
2206 srand((unsigned int)t.tv_nsec);
2207 idx = rand() % 8000 + 100;
2208 snprintf(ctx_.ifname, sizeof(ctx_.ifname), "tap%d", idx);
2209 idx = rand() % 800 + 100;
2210 snprintf(ctx_.bdgname, sizeof(ctx_.bdgname), "vale%d", idx);
2213 while ((opt = getopt(argc, argv, "hi:j:l")) != -1) {
2220 strncpy(ctx_.ifname, optarg, sizeof(ctx_.ifname) - 1);
2225 if (parse_interval(optarg, &j, &k) < 0) {
2237 printf(" Unrecognized option %c\n", opt);
2243 num_tests = sizeof(tests) / sizeof(tests[0]);
2245 if (j < 0 || j >= num_tests || k > num_tests) {
2246 fprintf(stderr, "Test interval %d-%d out of range (%d-%d)\n",
2247 j + 1, k, 1, num_tests + 1);
2255 printf("Available tests:\n");
2256 for (i = 0; i < num_tests; i++) {
2257 printf("#%03d: %s\n", i + 1, tests[i].name);
2263 struct sigaction sa;
2267 ARGV_APPEND(av, ac, "ifconfig");
2268 ARGV_APPEND(av, ac, ctx_.ifname);
2269 ARGV_APPEND(av, ac, "create");
2270 ARGV_APPEND(av, ac, "up");
2272 ARGV_APPEND(av, ac, "ip");
2273 ARGV_APPEND(av, ac, "tuntap");
2274 ARGV_APPEND(av, ac, "add");
2275 ARGV_APPEND(av, ac, "mode");
2276 ARGV_APPEND(av, ac, "tap");
2277 ARGV_APPEND(av, ac, "name");
2278 ARGV_APPEND(av, ac, ctx_.ifname);
2280 ARGV_APPEND(av, ac, NULL);
2281 if (exec_command(ac, av)) {
2282 printf("Failed to create tap interface\n");
2286 sa.sa_handler = tap_cleanup;
2287 sigemptyset(&sa.sa_mask);
2288 sa.sa_flags = SA_RESTART;
2289 ret = sigaction(SIGINT, &sa, NULL);
2291 perror("sigaction(SIGINT)");
2294 ret = sigaction(SIGTERM, &sa, NULL);
2296 perror("sigaction(SIGTERM)");
2301 for (i = j; i < k; i++) {
2302 struct TestContext ctxcopy;
2304 printf("==> Start of Test #%d [%s]\n", i + 1, tests[i].name);
2305 fd = open("/dev/netmap", O_RDWR);
2307 perror("open(/dev/netmap)");
2311 memcpy(&ctxcopy, &ctx_, sizeof(ctxcopy));
2313 memcpy(ctxcopy.ifname_ext, ctxcopy.ifname,
2314 sizeof(ctxcopy.ifname));
2315 ret = tests[i].test(&ctxcopy);
2317 printf("Test #%d [%s] failed\n", i + 1, tests[i].name);
2320 printf("==> Test #%d [%s] successful\n", i + 1, tests[i].name);
2321 context_cleanup(&ctxcopy);