2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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
30 #include <sys/ioctl.h>
40 #include <net/netmap.h>
42 #include <semaphore.h>
52 #include <sys/eventfd.h>
55 eventfd(int x __unused, int y __unused)
60 #endif /* __linux__ */
63 exec_command(int argc, const char *const argv[])
70 printf("Executing command: ");
71 for (i = 0; i < argc - 1; i++) {
73 /* Invalid argument. */
79 printf("%s", argv[i]);
87 /* Child process. Redirect stdin, stdout
92 if (open("/dev/null", O_RDONLY) < 0 ||
93 open("/dev/null", O_RDONLY) < 0 ||
94 open("/dev/null", O_RDONLY) < 0) {
98 /* Make a copy of the arguments, passing them to execvp. */
99 av = calloc(argc, sizeof(av[0]));
103 for (i = 0; i < argc - 1; i++) {
104 av[i] = strdup(argv[i]);
114 wret = waitpid(child_pid, &child_status, 0);
116 fprintf(stderr, "waitpid() failed: %s\n", strerror(errno));
119 if (WIFEXITED(child_status)) {
120 return WEXITSTATUS(child_status);
127 #define THRET_SUCCESS ((void *)128)
128 #define THRET_FAILURE ((void *)0)
133 uint32_t nr_tx_slots; /* slots in tx rings */
134 uint32_t nr_rx_slots; /* slots in rx rings */
135 uint16_t nr_tx_rings; /* number of tx rings */
136 uint16_t nr_rx_rings; /* number of rx rings */
137 uint16_t nr_mem_id; /* id of the memory allocator */
138 uint16_t nr_ringid; /* ring(s) we care about */
139 uint32_t nr_mode; /* specify NR_REG_* modes */
140 uint32_t nr_extra_bufs; /* number of requested extra buffers */
141 uint64_t nr_flags; /* additional flags (see below) */
142 uint32_t nr_hdr_len; /* for PORT_HDR_SET and PORT_HDR_GET */
143 uint32_t nr_first_cpu_id; /* vale polling */
144 uint32_t nr_num_polling_cpus; /* vale polling */
145 int fd; /* netmap file descriptor */
147 void *csb; /* CSB entries (atok and ktoa) */
148 struct nmreq_option *nr_opt; /* list of options */
149 sem_t *sem; /* for thread synchronization */
150 struct nmport_d *nmport; /* nmport descriptor from libnetmap */
153 static struct TestContext ctx_;
155 typedef int (*testfunc_t)(struct TestContext *ctx);
158 nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
160 memset(hdr, 0, sizeof(*hdr));
161 hdr->nr_version = NETMAP_API;
162 strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name) - 1);
165 /* Single NETMAP_REQ_PORT_INFO_GET. */
167 port_info_get(struct TestContext *ctx)
169 struct nmreq_port_info_get req;
170 struct nmreq_header hdr;
174 printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ctx->ifname);
176 nmreq_hdr_init(&hdr, ctx->ifname);
177 hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
178 hdr.nr_body = (uintptr_t)&req;
179 memset(&req, 0, sizeof(req));
180 req.nr_mem_id = ctx->nr_mem_id;
181 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
183 perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
186 printf("nr_memsize %lu\n", req.nr_memsize);
187 printf("nr_tx_slots %u\n", req.nr_tx_slots);
188 printf("nr_rx_slots %u\n", req.nr_rx_slots);
189 printf("nr_tx_rings %u\n", req.nr_tx_rings);
190 printf("nr_rx_rings %u\n", req.nr_rx_rings);
191 printf("nr_mem_id %u\n", req.nr_mem_id);
193 success = req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
194 req.nr_tx_rings && req.nr_rx_rings && req.nr_tx_rings;
199 /* Write back results to the context structure. */
200 ctx->nr_tx_slots = req.nr_tx_slots;
201 ctx->nr_rx_slots = req.nr_rx_slots;
202 ctx->nr_tx_rings = req.nr_tx_rings;
203 ctx->nr_rx_rings = req.nr_rx_rings;
204 ctx->nr_mem_id = req.nr_mem_id;
209 /* Single NETMAP_REQ_REGISTER, no use. */
211 port_register(struct TestContext *ctx)
213 struct nmreq_register req;
214 struct nmreq_header hdr;
218 printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
219 "flags=0x%lx) on '%s'\n",
220 ctx->nr_mode, ctx->nr_ringid, ctx->nr_flags, ctx->ifname);
222 nmreq_hdr_init(&hdr, ctx->ifname);
223 hdr.nr_reqtype = NETMAP_REQ_REGISTER;
224 hdr.nr_body = (uintptr_t)&req;
225 hdr.nr_options = (uintptr_t)ctx->nr_opt;
226 memset(&req, 0, sizeof(req));
227 req.nr_mem_id = ctx->nr_mem_id;
228 req.nr_mode = ctx->nr_mode;
229 req.nr_ringid = ctx->nr_ringid;
230 req.nr_flags = ctx->nr_flags;
231 req.nr_tx_slots = ctx->nr_tx_slots;
232 req.nr_rx_slots = ctx->nr_rx_slots;
233 req.nr_tx_rings = ctx->nr_tx_rings;
234 req.nr_rx_rings = ctx->nr_rx_rings;
235 req.nr_extra_bufs = ctx->nr_extra_bufs;
236 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
238 perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
241 printf("nr_offset 0x%lx\n", req.nr_offset);
242 printf("nr_memsize %lu\n", req.nr_memsize);
243 printf("nr_tx_slots %u\n", req.nr_tx_slots);
244 printf("nr_rx_slots %u\n", req.nr_rx_slots);
245 printf("nr_tx_rings %u\n", req.nr_tx_rings);
246 printf("nr_rx_rings %u\n", req.nr_rx_rings);
247 printf("nr_mem_id %u\n", req.nr_mem_id);
248 printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
250 success = req.nr_memsize && (ctx->nr_mode == req.nr_mode) &&
251 (ctx->nr_ringid == req.nr_ringid) &&
252 (ctx->nr_flags == req.nr_flags) &&
253 ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
254 (ctx->nr_tx_slots == req.nr_tx_slots)) &&
255 ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
256 (ctx->nr_rx_slots == req.nr_rx_slots)) &&
257 ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
258 (ctx->nr_tx_rings == req.nr_tx_rings)) &&
259 ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
260 (ctx->nr_rx_rings == req.nr_rx_rings)) &&
261 ((!ctx->nr_mem_id && req.nr_mem_id) ||
262 (ctx->nr_mem_id == req.nr_mem_id)) &&
263 (ctx->nr_extra_bufs == req.nr_extra_bufs);
268 /* Write back results to the context structure.*/
269 ctx->nr_tx_slots = req.nr_tx_slots;
270 ctx->nr_rx_slots = req.nr_rx_slots;
271 ctx->nr_tx_rings = req.nr_tx_rings;
272 ctx->nr_rx_rings = req.nr_rx_rings;
273 ctx->nr_mem_id = req.nr_mem_id;
274 ctx->nr_extra_bufs = req.nr_extra_bufs;
280 niocregif(struct TestContext *ctx, int netmap_api)
286 printf("Testing legacy NIOCREGIF on '%s'\n", ctx->ifname);
288 memset(&req, 0, sizeof(req));
289 memcpy(req.nr_name, ctx->ifname, sizeof(req.nr_name));
290 req.nr_name[sizeof(req.nr_name) - 1] = '\0';
291 req.nr_version = netmap_api;
292 req.nr_ringid = ctx->nr_ringid;
293 req.nr_flags = ctx->nr_mode | ctx->nr_flags;
294 req.nr_tx_slots = ctx->nr_tx_slots;
295 req.nr_rx_slots = ctx->nr_rx_slots;
296 req.nr_tx_rings = ctx->nr_tx_rings;
297 req.nr_rx_rings = ctx->nr_rx_rings;
298 req.nr_arg2 = ctx->nr_mem_id;
299 req.nr_arg3 = ctx->nr_extra_bufs;
301 ret = ioctl(ctx->fd, NIOCREGIF, &req);
303 perror("ioctl(/dev/netmap, NIOCREGIF)");
307 printf("nr_offset 0x%x\n", req.nr_offset);
308 printf("nr_memsize %u\n", req.nr_memsize);
309 printf("nr_tx_slots %u\n", req.nr_tx_slots);
310 printf("nr_rx_slots %u\n", req.nr_rx_slots);
311 printf("nr_tx_rings %u\n", req.nr_tx_rings);
312 printf("nr_rx_rings %u\n", req.nr_rx_rings);
313 printf("nr_version %d\n", req.nr_version);
314 printf("nr_ringid %x\n", req.nr_ringid);
315 printf("nr_flags %x\n", req.nr_flags);
316 printf("nr_arg2 %u\n", req.nr_arg2);
317 printf("nr_arg3 %u\n", req.nr_arg3);
319 success = req.nr_memsize &&
320 (ctx->nr_ringid == req.nr_ringid) &&
321 ((ctx->nr_mode | ctx->nr_flags) == req.nr_flags) &&
322 ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
323 (ctx->nr_tx_slots == req.nr_tx_slots)) &&
324 ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
325 (ctx->nr_rx_slots == req.nr_rx_slots)) &&
326 ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
327 (ctx->nr_tx_rings == req.nr_tx_rings)) &&
328 ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
329 (ctx->nr_rx_rings == req.nr_rx_rings)) &&
330 ((!ctx->nr_mem_id && req.nr_arg2) ||
331 (ctx->nr_mem_id == req.nr_arg2)) &&
332 (ctx->nr_extra_bufs == req.nr_arg3);
337 /* Write back results to the context structure.*/
338 ctx->nr_tx_slots = req.nr_tx_slots;
339 ctx->nr_rx_slots = req.nr_rx_slots;
340 ctx->nr_tx_rings = req.nr_tx_rings;
341 ctx->nr_rx_rings = req.nr_rx_rings;
342 ctx->nr_mem_id = req.nr_arg2;
343 ctx->nr_extra_bufs = req.nr_arg3;
348 /* The 11 ABI is the one right before the introduction of the new NIOCCTRL
349 * ABI. The 11 ABI is useful to perform tests with legacy applications
350 * (which use the 11 ABI) and new kernel (which uses 12, or higher). */
351 #define NETMAP_API_NIOCREGIF 11
354 legacy_regif_default(struct TestContext *ctx)
356 return niocregif(ctx, NETMAP_API_NIOCREGIF);
360 legacy_regif_all_nic(struct TestContext *ctx)
362 ctx->nr_mode = NR_REG_ALL_NIC;
363 return niocregif(ctx, NETMAP_API);
367 legacy_regif_12(struct TestContext *ctx)
369 ctx->nr_mode = NR_REG_ALL_NIC;
370 return niocregif(ctx, NETMAP_API_NIOCREGIF+1);
374 legacy_regif_sw(struct TestContext *ctx)
376 ctx->nr_mode = NR_REG_SW;
377 return niocregif(ctx, NETMAP_API_NIOCREGIF);
381 legacy_regif_future(struct TestContext *ctx)
383 ctx->nr_mode = NR_REG_NIC_SW;
384 /* Test forward compatibility for the legacy ABI. This means
385 * using an older kernel (with ABI 12 or higher) and a newer
386 * application (with ABI greater than NETMAP_API). */
387 return niocregif(ctx, NETMAP_API+2);
391 legacy_regif_extra_bufs(struct TestContext *ctx)
393 ctx->nr_mode = NR_REG_ALL_NIC;
394 ctx->nr_extra_bufs = 20; /* arbitrary number of extra bufs */
395 return niocregif(ctx, NETMAP_API_NIOCREGIF);
399 legacy_regif_extra_bufs_pipe(struct TestContext *ctx)
401 strncat(ctx->ifname, "{pipeexbuf", sizeof(ctx->ifname));
402 ctx->nr_mode = NR_REG_ALL_NIC;
403 ctx->nr_extra_bufs = 58; /* arbitrary number of extra bufs */
405 return niocregif(ctx, NETMAP_API_NIOCREGIF);
409 legacy_regif_extra_bufs_pipe_vale(struct TestContext *ctx)
411 strncpy(ctx->ifname, "valeX1:Y4", sizeof(ctx->ifname));
412 return legacy_regif_extra_bufs_pipe(ctx);
415 /* Only valid after a successful port_register(). */
417 num_registered_rings(struct TestContext *ctx)
419 if (ctx->nr_flags & NR_TX_RINGS_ONLY) {
420 return ctx->nr_tx_rings;
422 if (ctx->nr_flags & NR_RX_RINGS_ONLY) {
423 return ctx->nr_rx_rings;
426 return ctx->nr_tx_rings + ctx->nr_rx_rings;
430 port_register_hwall_host(struct TestContext *ctx)
432 ctx->nr_mode = NR_REG_NIC_SW;
433 return port_register(ctx);
437 port_register_host(struct TestContext *ctx)
439 ctx->nr_mode = NR_REG_SW;
440 return port_register(ctx);
444 port_register_hwall(struct TestContext *ctx)
446 ctx->nr_mode = NR_REG_ALL_NIC;
447 return port_register(ctx);
451 port_register_single_ring_couple(struct TestContext *ctx)
453 ctx->nr_mode = NR_REG_ONE_NIC;
455 return port_register(ctx);
459 port_register_hwall_tx(struct TestContext *ctx)
461 ctx->nr_mode = NR_REG_ALL_NIC;
462 ctx->nr_flags |= NR_TX_RINGS_ONLY;
463 return port_register(ctx);
467 port_register_hwall_rx(struct TestContext *ctx)
469 ctx->nr_mode = NR_REG_ALL_NIC;
470 ctx->nr_flags |= NR_RX_RINGS_ONLY;
471 return port_register(ctx);
474 /* NETMAP_REQ_VALE_ATTACH */
476 vale_attach(struct TestContext *ctx)
478 struct nmreq_vale_attach req;
479 struct nmreq_header hdr;
480 char vpname[sizeof(ctx->bdgname) + 1 + sizeof(ctx->ifname)];
483 snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
485 printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
486 nmreq_hdr_init(&hdr, vpname);
487 hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
488 hdr.nr_body = (uintptr_t)&req;
489 memset(&req, 0, sizeof(req));
490 req.reg.nr_mem_id = ctx->nr_mem_id;
491 if (ctx->nr_mode == 0) {
492 ctx->nr_mode = NR_REG_ALL_NIC; /* default */
494 req.reg.nr_mode = ctx->nr_mode;
495 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
497 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
500 printf("nr_mem_id %u\n", req.reg.nr_mem_id);
502 return ((!ctx->nr_mem_id && req.reg.nr_mem_id > 1) ||
503 (ctx->nr_mem_id == req.reg.nr_mem_id)) &&
504 (ctx->nr_flags == req.reg.nr_flags)
509 /* NETMAP_REQ_VALE_DETACH */
511 vale_detach(struct TestContext *ctx)
513 struct nmreq_header hdr;
514 struct nmreq_vale_detach req;
518 snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
520 printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
521 nmreq_hdr_init(&hdr, vpname);
522 hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
523 hdr.nr_body = (uintptr_t)&req;
524 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
526 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
533 /* First NETMAP_REQ_VALE_ATTACH, then NETMAP_REQ_VALE_DETACH. */
535 vale_attach_detach(struct TestContext *ctx)
539 if ((ret = vale_attach(ctx)) != 0) {
543 return vale_detach(ctx);
547 vale_attach_detach_host_rings(struct TestContext *ctx)
549 ctx->nr_mode = NR_REG_NIC_SW;
550 return vale_attach_detach(ctx);
553 /* First NETMAP_REQ_PORT_HDR_SET and the NETMAP_REQ_PORT_HDR_GET
554 * to check that we get the same value. */
556 port_hdr_set_and_get(struct TestContext *ctx)
558 struct nmreq_port_hdr req;
559 struct nmreq_header hdr;
562 printf("Testing NETMAP_REQ_PORT_HDR_SET on '%s'\n", ctx->ifname);
564 nmreq_hdr_init(&hdr, ctx->ifname);
565 hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
566 hdr.nr_body = (uintptr_t)&req;
567 memset(&req, 0, sizeof(req));
568 req.nr_hdr_len = ctx->nr_hdr_len;
569 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
571 perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
575 if (req.nr_hdr_len != ctx->nr_hdr_len) {
579 printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname);
580 hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
582 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
584 perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
587 printf("nr_hdr_len %u\n", req.nr_hdr_len);
589 return (req.nr_hdr_len == ctx->nr_hdr_len) ? 0 : -1;
593 * Possible lengths for the VirtIO network header, as specified by
595 * http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html
597 #define VIRTIO_NET_HDR_LEN 10
598 #define VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS 12
601 vale_ephemeral_port_hdr_manipulation(struct TestContext *ctx)
605 strncpy(ctx->ifname, "vale:eph0", sizeof(ctx->ifname));
606 ctx->nr_mode = NR_REG_ALL_NIC;
607 if ((ret = port_register(ctx))) {
610 /* Try to set and get all the acceptable values. */
611 ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS;
612 if ((ret = port_hdr_set_and_get(ctx))) {
616 if ((ret = port_hdr_set_and_get(ctx))) {
619 ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN;
620 if ((ret = port_hdr_set_and_get(ctx))) {
627 vale_persistent_port(struct TestContext *ctx)
629 struct nmreq_vale_newif req;
630 struct nmreq_header hdr;
634 strncpy(ctx->ifname, "per4", sizeof(ctx->ifname));
636 printf("Testing NETMAP_REQ_VALE_NEWIF on '%s'\n", ctx->ifname);
638 nmreq_hdr_init(&hdr, ctx->ifname);
639 hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
640 hdr.nr_body = (uintptr_t)&req;
641 memset(&req, 0, sizeof(req));
642 req.nr_mem_id = ctx->nr_mem_id;
643 req.nr_tx_slots = ctx->nr_tx_slots;
644 req.nr_rx_slots = ctx->nr_rx_slots;
645 req.nr_tx_rings = ctx->nr_tx_rings;
646 req.nr_rx_rings = ctx->nr_rx_rings;
647 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
649 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
653 /* Attach the persistent VALE port to a switch and then detach. */
654 result = vale_attach_detach(ctx);
656 printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname);
657 hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
658 hdr.nr_body = (uintptr_t)NULL;
659 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
661 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
670 /* Single NETMAP_REQ_POOLS_INFO_GET. */
672 pools_info_get(struct TestContext *ctx)
674 struct nmreq_pools_info req;
675 struct nmreq_header hdr;
678 printf("Testing NETMAP_REQ_POOLS_INFO_GET on '%s'\n", ctx->ifname);
680 nmreq_hdr_init(&hdr, ctx->ifname);
681 hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
682 hdr.nr_body = (uintptr_t)&req;
683 memset(&req, 0, sizeof(req));
684 req.nr_mem_id = ctx->nr_mem_id;
685 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
687 perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
690 printf("nr_memsize %lu\n", req.nr_memsize);
691 printf("nr_mem_id %u\n", req.nr_mem_id);
692 printf("nr_if_pool_offset 0x%lx\n", req.nr_if_pool_offset);
693 printf("nr_if_pool_objtotal %u\n", req.nr_if_pool_objtotal);
694 printf("nr_if_pool_objsize %u\n", req.nr_if_pool_objsize);
695 printf("nr_ring_pool_offset 0x%lx\n", req.nr_if_pool_offset);
696 printf("nr_ring_pool_objtotal %u\n", req.nr_ring_pool_objtotal);
697 printf("nr_ring_pool_objsize %u\n", req.nr_ring_pool_objsize);
698 printf("nr_buf_pool_offset 0x%lx\n", req.nr_buf_pool_offset);
699 printf("nr_buf_pool_objtotal %u\n", req.nr_buf_pool_objtotal);
700 printf("nr_buf_pool_objsize %u\n", req.nr_buf_pool_objsize);
702 return req.nr_memsize && req.nr_if_pool_objtotal &&
703 req.nr_if_pool_objsize &&
704 req.nr_ring_pool_objtotal &&
705 req.nr_ring_pool_objsize &&
706 req.nr_buf_pool_objtotal &&
707 req.nr_buf_pool_objsize
713 pools_info_get_and_register(struct TestContext *ctx)
717 /* Check that we can get pools info before we register
718 * a netmap interface. */
719 ret = pools_info_get(ctx);
724 ctx->nr_mode = NR_REG_ONE_NIC;
725 ret = port_register(ctx);
731 /* Check that we can get pools info also after we register. */
732 return pools_info_get(ctx);
736 pools_info_get_empty_ifname(struct TestContext *ctx)
738 strncpy(ctx->ifname, "", sizeof(ctx->ifname));
739 return pools_info_get(ctx) != 0 ? 0 : -1;
743 pipe_master(struct TestContext *ctx)
745 strncat(ctx->ifname, "{pipeid1", sizeof(ctx->ifname));
746 ctx->nr_mode = NR_REG_NIC_SW;
748 if (port_register(ctx) == 0) {
749 printf("pipes should not accept NR_REG_NIC_SW\n");
752 ctx->nr_mode = NR_REG_ALL_NIC;
754 return port_register(ctx);
758 pipe_slave(struct TestContext *ctx)
760 strncat(ctx->ifname, "}pipeid2", sizeof(ctx->ifname));
761 ctx->nr_mode = NR_REG_ALL_NIC;
763 return port_register(ctx);
766 /* Test PORT_INFO_GET and POOLS_INFO_GET on a pipe. This is useful to test the
767 * registration request used internall by netmap. */
769 pipe_port_info_get(struct TestContext *ctx)
771 strncat(ctx->ifname, "}pipeid3", sizeof(ctx->ifname));
773 return port_info_get(ctx);
777 pipe_pools_info_get(struct TestContext *ctx)
779 strncat(ctx->ifname, "{xid", sizeof(ctx->ifname));
781 return pools_info_get(ctx);
784 /* NETMAP_REQ_VALE_POLLING_ENABLE */
786 vale_polling_enable(struct TestContext *ctx)
788 struct nmreq_vale_polling req;
789 struct nmreq_header hdr;
793 snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
794 printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", vpname);
796 nmreq_hdr_init(&hdr, vpname);
797 hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
798 hdr.nr_body = (uintptr_t)&req;
799 memset(&req, 0, sizeof(req));
800 req.nr_mode = ctx->nr_mode;
801 req.nr_first_cpu_id = ctx->nr_first_cpu_id;
802 req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
803 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
805 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
809 return (req.nr_mode == ctx->nr_mode &&
810 req.nr_first_cpu_id == ctx->nr_first_cpu_id &&
811 req.nr_num_polling_cpus == ctx->nr_num_polling_cpus)
816 /* NETMAP_REQ_VALE_POLLING_DISABLE */
818 vale_polling_disable(struct TestContext *ctx)
820 struct nmreq_vale_polling req;
821 struct nmreq_header hdr;
825 snprintf(vpname, sizeof(vpname), "%s:%s", ctx->bdgname, ctx->ifname);
826 printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", vpname);
828 nmreq_hdr_init(&hdr, vpname);
829 hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
830 hdr.nr_body = (uintptr_t)&req;
831 memset(&req, 0, sizeof(req));
832 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
834 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
842 vale_polling_enable_disable(struct TestContext *ctx)
846 if ((ret = vale_attach(ctx)) != 0) {
850 ctx->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
851 ctx->nr_num_polling_cpus = 1;
852 ctx->nr_first_cpu_id = 0;
853 if ((ret = vale_polling_enable(ctx))) {
856 /* NETMAP_REQ_VALE_POLLING_DISABLE is disabled on FreeBSD,
857 * because it is currently broken. We are happy to see that
864 if ((ret = vale_polling_disable(ctx))) {
869 return vale_detach(ctx);
873 push_option(struct nmreq_option *opt, struct TestContext *ctx)
875 opt->nro_next = (uintptr_t)ctx->nr_opt;
880 clear_options(struct TestContext *ctx)
886 checkoption(struct nmreq_option *opt, struct nmreq_option *exp)
888 if (opt->nro_next != exp->nro_next) {
889 printf("nro_next %p expected %p\n",
890 (void *)(uintptr_t)opt->nro_next,
891 (void *)(uintptr_t)exp->nro_next);
894 if (opt->nro_reqtype != exp->nro_reqtype) {
895 printf("nro_reqtype %u expected %u\n", opt->nro_reqtype,
899 if (opt->nro_status != exp->nro_status) {
900 printf("nro_status %u expected %u\n", opt->nro_status,
908 unsupported_option(struct TestContext *ctx)
910 struct nmreq_option opt, save;
912 printf("Testing unsupported option on %s\n", ctx->ifname);
914 memset(&opt, 0, sizeof(opt));
915 opt.nro_reqtype = 1234;
916 push_option(&opt, ctx);
919 if (port_register_hwall(ctx) >= 0)
923 save.nro_status = EOPNOTSUPP;
924 return checkoption(&opt, &save);
928 infinite_options(struct TestContext *ctx)
930 struct nmreq_option opt;
932 printf("Testing infinite list of options on %s\n", ctx->ifname);
934 opt.nro_reqtype = 1234;
935 push_option(&opt, ctx);
936 opt.nro_next = (uintptr_t)&opt;
937 if (port_register_hwall(ctx) >= 0)
940 return (errno == EMSGSIZE ? 0 : -1);
943 #ifdef CONFIG_NETMAP_EXTMEM
945 change_param(const char *pname, unsigned long newv, unsigned long *poldv)
948 char param[256] = "/sys/module/netmap/parameters/";
952 strncat(param, pname, sizeof(param) - 1);
954 f = fopen(param, "r+");
959 if (fscanf(f, "%ld", &oldv) != 1) {
967 if (fprintf(f, "%ld\n", newv) < 0) {
973 printf("change_param: %s: %ld -> %ld\n", pname, oldv, newv);
974 #endif /* __linux__ */
979 push_extmem_option(struct TestContext *ctx, const struct nmreq_pools_info *pi,
980 struct nmreq_opt_extmem *e)
984 addr = mmap(NULL, pi->nr_memsize, PROT_READ | PROT_WRITE,
985 MAP_ANONYMOUS | MAP_SHARED, -1, 0);
986 if (addr == MAP_FAILED) {
991 memset(e, 0, sizeof(*e));
992 e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
994 e->nro_usrptr = (uintptr_t)addr;
996 push_option(&e->nro_opt, ctx);
1002 pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
1004 struct nmreq_opt_extmem *e;
1007 e = (struct nmreq_opt_extmem *)(uintptr_t)ctx->nr_opt;
1008 ctx->nr_opt = (struct nmreq_option *)(uintptr_t)ctx->nr_opt->nro_next;
1010 if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
1014 if (e->nro_usrptr != exp->nro_usrptr) {
1015 printf("usrptr %" PRIu64 " expected %" PRIu64 "\n",
1016 e->nro_usrptr, exp->nro_usrptr);
1019 if (e->nro_info.nr_memsize != exp->nro_info.nr_memsize) {
1020 printf("memsize %" PRIu64 " expected %" PRIu64 "\n",
1021 e->nro_info.nr_memsize, exp->nro_info.nr_memsize);
1025 if ((ret = munmap((void *)(uintptr_t)e->nro_usrptr,
1026 e->nro_info.nr_memsize)))
1033 _extmem_option(struct TestContext *ctx,
1034 const struct nmreq_pools_info *pi)
1036 struct nmreq_opt_extmem e, save;
1039 if ((ret = push_extmem_option(ctx, pi, &e)) < 0)
1044 strncpy(ctx->ifname, "vale0:0", sizeof(ctx->ifname));
1045 ctx->nr_tx_slots = 16;
1046 ctx->nr_rx_slots = 16;
1048 if ((ret = port_register_hwall(ctx)))
1051 ret = pop_extmem_option(ctx, &save);
1057 pools_info_min_memsize(const struct nmreq_pools_info *pi)
1061 tot += pi->nr_if_pool_objtotal * pi->nr_if_pool_objsize;
1062 tot += pi->nr_ring_pool_objtotal * pi->nr_ring_pool_objsize;
1063 tot += pi->nr_buf_pool_objtotal * pi->nr_buf_pool_objsize;
1069 * Fill the specification of a netmap memory allocator to be
1070 * used with the 'struct nmreq_opt_extmem' option. Arbitrary
1071 * values are used for the parameters, but with enough netmap
1072 * rings, netmap ifs, and buffers to support a VALE port.
1075 pools_info_fill(struct nmreq_pools_info *pi)
1077 pi->nr_if_pool_objtotal = 2;
1078 pi->nr_if_pool_objsize = 1024;
1079 pi->nr_ring_pool_objtotal = 64;
1080 pi->nr_ring_pool_objsize = 512;
1081 pi->nr_buf_pool_objtotal = 4096;
1082 pi->nr_buf_pool_objsize = 2048;
1083 pi->nr_memsize = pools_info_min_memsize(pi);
1087 extmem_option(struct TestContext *ctx)
1089 struct nmreq_pools_info pools_info;
1091 pools_info_fill(&pools_info);
1093 printf("Testing extmem option on vale0:0\n");
1094 return _extmem_option(ctx, &pools_info);
1098 bad_extmem_option(struct TestContext *ctx)
1100 struct nmreq_pools_info pools_info;
1102 printf("Testing bad extmem option on vale0:0\n");
1104 pools_info_fill(&pools_info);
1105 /* Request a large ring size, to make sure that the kernel
1106 * rejects our request. */
1107 pools_info.nr_ring_pool_objsize = (1 << 16);
1109 return _extmem_option(ctx, &pools_info) < 0 ? 0 : -1;
1113 duplicate_extmem_options(struct TestContext *ctx)
1115 struct nmreq_opt_extmem e1, save1, e2, save2;
1116 struct nmreq_pools_info pools_info;
1119 printf("Testing duplicate extmem option on vale0:0\n");
1121 pools_info_fill(&pools_info);
1123 if ((ret = push_extmem_option(ctx, &pools_info, &e1)) < 0)
1126 if ((ret = push_extmem_option(ctx, &pools_info, &e2)) < 0) {
1134 ret = port_register_hwall(ctx);
1136 printf("duplicate option not detected\n");
1140 save2.nro_opt.nro_status = EINVAL;
1141 if ((ret = pop_extmem_option(ctx, &save2)))
1144 save1.nro_opt.nro_status = EINVAL;
1145 if ((ret = pop_extmem_option(ctx, &save1)))
1150 #endif /* CONFIG_NETMAP_EXTMEM */
1153 push_csb_option(struct TestContext *ctx, struct nmreq_opt_csb *opt)
1159 ctx->nr_flags |= NR_EXCLUSIVE;
1161 /* Get port info in order to use num_registered_rings(). */
1162 ret = port_info_get(ctx);
1166 num_entries = num_registered_rings(ctx);
1168 csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
1170 assert(csb_size > 0);
1174 ret = posix_memalign(&ctx->csb, sizeof(struct nm_csb_atok), csb_size);
1176 printf("Failed to allocate CSB memory\n");
1180 memset(opt, 0, sizeof(*opt));
1181 opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
1182 opt->csb_atok = (uintptr_t)ctx->csb;
1183 opt->csb_ktoa = (uintptr_t)(((uint8_t *)ctx->csb) +
1184 sizeof(struct nm_csb_atok) * num_entries);
1186 printf("Pushing option NETMAP_REQ_OPT_CSB\n");
1187 push_option(&opt->nro_opt, ctx);
1193 csb_mode(struct TestContext *ctx)
1195 struct nmreq_opt_csb opt;
1198 ret = push_csb_option(ctx, &opt);
1203 ret = port_register_hwall(ctx);
1210 csb_mode_invalid_memory(struct TestContext *ctx)
1212 struct nmreq_opt_csb opt;
1215 memset(&opt, 0, sizeof(opt));
1216 opt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
1217 opt.csb_atok = (uintptr_t)0x10;
1218 opt.csb_ktoa = (uintptr_t)0x800;
1219 push_option(&opt.nro_opt, ctx);
1221 ctx->nr_flags = NR_EXCLUSIVE;
1222 ret = port_register_hwall(ctx);
1225 return (ret < 0) ? 0 : -1;
1229 sync_kloop_stop(struct TestContext *ctx)
1231 struct nmreq_header hdr;
1234 printf("Testing NETMAP_REQ_SYNC_KLOOP_STOP on '%s'\n", ctx->ifname);
1236 nmreq_hdr_init(&hdr, ctx->ifname);
1237 hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
1238 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
1240 perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
1247 sync_kloop_worker(void *opaque)
1249 struct TestContext *ctx = opaque;
1250 struct nmreq_sync_kloop_start req;
1251 struct nmreq_header hdr;
1254 printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname);
1256 nmreq_hdr_init(&hdr, ctx->ifname);
1257 hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
1258 hdr.nr_body = (uintptr_t)&req;
1259 hdr.nr_options = (uintptr_t)ctx->nr_opt;
1260 memset(&req, 0, sizeof(req));
1262 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
1264 perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
1271 pthread_exit(ret ? (void *)THRET_FAILURE : (void *)THRET_SUCCESS);
1275 sync_kloop_start_stop(struct TestContext *ctx)
1278 void *thret = THRET_FAILURE;
1281 ret = pthread_create(&th, NULL, sync_kloop_worker, ctx);
1283 printf("pthread_create(kloop): %s\n", strerror(ret));
1287 ret = sync_kloop_stop(ctx);
1292 ret = pthread_join(th, &thret);
1294 printf("pthread_join(kloop): %s\n", strerror(ret));
1297 return thret == THRET_SUCCESS ? 0 : -1;
1301 sync_kloop(struct TestContext *ctx)
1305 ret = csb_mode(ctx);
1310 return sync_kloop_start_stop(ctx);
1314 sync_kloop_eventfds(struct TestContext *ctx)
1316 struct nmreq_opt_sync_kloop_eventfds *opt = NULL;
1317 struct nmreq_option save;
1322 num_entries = num_registered_rings(ctx);
1323 opt_size = sizeof(*opt) + num_entries * sizeof(opt->eventfds[0]);
1324 opt = calloc(1, opt_size);
1325 opt->nro_opt.nro_next = 0;
1326 opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
1327 opt->nro_opt.nro_status = 0;
1328 opt->nro_opt.nro_size = opt_size;
1329 for (i = 0; i < num_entries; i++) {
1330 int efd = eventfd(0, 0);
1332 opt->eventfds[i].ioeventfd = efd;
1333 efd = eventfd(0, 0);
1334 opt->eventfds[i].irqfd = efd;
1337 push_option(&opt->nro_opt, ctx);
1338 save = opt->nro_opt;
1340 ret = sync_kloop_start_stop(ctx);
1347 save.nro_status = 0;
1348 #else /* !__linux__ */
1349 save.nro_status = EOPNOTSUPP;
1350 #endif /* !__linux__ */
1352 ret = checkoption(&opt->nro_opt, &save);
1360 sync_kloop_eventfds_all(struct TestContext *ctx)
1364 ret = csb_mode(ctx);
1369 return sync_kloop_eventfds(ctx);
1373 sync_kloop_eventfds_all_tx(struct TestContext *ctx)
1375 struct nmreq_opt_csb opt;
1378 ret = push_csb_option(ctx, &opt);
1383 ret = port_register_hwall_tx(ctx);
1389 return sync_kloop_eventfds(ctx);
1393 sync_kloop_nocsb(struct TestContext *ctx)
1397 ret = port_register_hwall(ctx);
1402 /* Sync kloop must fail because we did not use
1403 * NETMAP_REQ_CSB_ENABLE. */
1404 return sync_kloop_start_stop(ctx) != 0 ? 0 : -1;
1408 csb_enable(struct TestContext *ctx)
1410 struct nmreq_option saveopt;
1411 struct nmreq_opt_csb opt;
1412 struct nmreq_header hdr;
1415 ret = push_csb_option(ctx, &opt);
1419 saveopt = opt.nro_opt;
1420 saveopt.nro_status = 0;
1422 nmreq_hdr_init(&hdr, ctx->ifname);
1423 hdr.nr_reqtype = NETMAP_REQ_CSB_ENABLE;
1424 hdr.nr_options = (uintptr_t)ctx->nr_opt;
1425 hdr.nr_body = (uintptr_t)NULL;
1427 printf("Testing NETMAP_REQ_CSB_ENABLE on '%s'\n", ctx->ifname);
1429 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
1431 perror("ioctl(/dev/netmap, NIOCCTRL, CSB_ENABLE)");
1435 ret = checkoption(&opt.nro_opt, &saveopt);
1442 sync_kloop_csb_enable(struct TestContext *ctx)
1446 ctx->nr_flags |= NR_EXCLUSIVE;
1447 ret = port_register_hwall(ctx);
1452 ret = csb_enable(ctx);
1457 return sync_kloop_start_stop(ctx);
1461 sync_kloop_conflict(struct TestContext *ctx)
1463 struct nmreq_opt_csb opt;
1465 void *thret1 = THRET_FAILURE, *thret2 = THRET_FAILURE;
1471 ret = push_csb_option(ctx, &opt);
1476 ret = port_register_hwall(ctx);
1482 ret = sem_init(&sem, 0, 0);
1484 printf("sem_init() failed: %s\n", strerror(ret));
1489 ret = pthread_create(&th1, NULL, sync_kloop_worker, ctx);
1492 printf("pthread_create(kloop1): %s\n", strerror(ret));
1495 ret = pthread_create(&th2, NULL, sync_kloop_worker, ctx);
1498 printf("pthread_create(kloop2): %s\n", strerror(ret));
1501 /* Wait for one of the two threads to fail to start the kloop, to
1502 * avoid a race condition where th1 starts the loop and stops,
1503 * and after that th2 starts the loop successfully. */
1504 clock_gettime(CLOCK_REALTIME, &to);
1506 ret = sem_timedwait(&sem, &to);
1509 printf("sem_timedwait() failed: %s\n", strerror(errno));
1512 err |= sync_kloop_stop(ctx);
1514 ret = pthread_join(th1, &thret1);
1517 printf("pthread_join(kloop1): %s\n", strerror(ret));
1520 ret = pthread_join(th2, &thret2);
1523 printf("pthread_join(kloop2): %s %d\n", strerror(ret), ret);
1532 /* Check that one of the two failed, while the other one succeeded. */
1533 return ((thret1 == THRET_SUCCESS && thret2 == THRET_FAILURE) ||
1534 (thret1 == THRET_FAILURE && thret2 == THRET_SUCCESS))
1540 sync_kloop_eventfds_mismatch(struct TestContext *ctx)
1542 struct nmreq_opt_csb opt;
1545 ret = push_csb_option(ctx, &opt);
1550 ret = port_register_hwall_rx(ctx);
1556 /* Deceive num_registered_rings() to trigger a failure of
1557 * sync_kloop_eventfds(). The latter will think that all the
1558 * rings were registered, and allocate the wrong number of
1560 ctx->nr_flags &= ~NR_RX_RINGS_ONLY;
1562 return (sync_kloop_eventfds(ctx) != 0) ? 0 : -1;
1566 null_port(struct TestContext *ctx)
1571 ctx->nr_mode = NR_REG_NULL;
1572 ctx->nr_tx_rings = 10;
1573 ctx->nr_rx_rings = 5;
1574 ctx->nr_tx_slots = 256;
1575 ctx->nr_rx_slots = 100;
1576 ret = port_register(ctx);
1584 null_port_all_zero(struct TestContext *ctx)
1589 ctx->nr_mode = NR_REG_NULL;
1590 ctx->nr_tx_rings = 0;
1591 ctx->nr_rx_rings = 0;
1592 ctx->nr_tx_slots = 0;
1593 ctx->nr_rx_slots = 0;
1594 ret = port_register(ctx);
1602 null_port_sync(struct TestContext *ctx)
1607 ctx->nr_mode = NR_REG_NULL;
1608 ctx->nr_tx_rings = 10;
1609 ctx->nr_rx_rings = 5;
1610 ctx->nr_tx_slots = 256;
1611 ctx->nr_rx_slots = 100;
1612 ret = port_register(ctx);
1616 ret = ioctl(ctx->fd, NIOCTXSYNC, 0);
1624 usage(const char *prog)
1626 printf("%s -i IFNAME\n"
1627 "[-j TEST_NUM1[-[TEST_NUM2]] | -[TEST_NUM_2]]\n"
1628 "[-l (list test cases)]\n",
1637 #define decltest(f) \
1639 .test = f, .name = #f \
1642 static struct mytest tests[] = {
1643 decltest(port_info_get),
1644 decltest(port_register_hwall_host),
1645 decltest(port_register_hwall),
1646 decltest(port_register_host),
1647 decltest(port_register_single_ring_couple),
1648 decltest(vale_attach_detach),
1649 decltest(vale_attach_detach_host_rings),
1650 decltest(vale_ephemeral_port_hdr_manipulation),
1651 decltest(vale_persistent_port),
1652 decltest(pools_info_get_and_register),
1653 decltest(pools_info_get_empty_ifname),
1654 decltest(pipe_master),
1655 decltest(pipe_slave),
1656 decltest(pipe_port_info_get),
1657 decltest(pipe_pools_info_get),
1658 decltest(vale_polling_enable_disable),
1659 decltest(unsupported_option),
1660 decltest(infinite_options),
1661 #ifdef CONFIG_NETMAP_EXTMEM
1662 decltest(extmem_option),
1663 decltest(bad_extmem_option),
1664 decltest(duplicate_extmem_options),
1665 #endif /* CONFIG_NETMAP_EXTMEM */
1667 decltest(csb_mode_invalid_memory),
1668 decltest(sync_kloop),
1669 decltest(sync_kloop_eventfds_all),
1670 decltest(sync_kloop_eventfds_all_tx),
1671 decltest(sync_kloop_nocsb),
1672 decltest(sync_kloop_csb_enable),
1673 decltest(sync_kloop_conflict),
1674 decltest(sync_kloop_eventfds_mismatch),
1675 decltest(null_port),
1676 decltest(null_port_all_zero),
1677 decltest(null_port_sync),
1678 decltest(legacy_regif_default),
1679 decltest(legacy_regif_all_nic),
1680 decltest(legacy_regif_12),
1681 decltest(legacy_regif_sw),
1682 decltest(legacy_regif_future),
1683 decltest(legacy_regif_extra_bufs),
1684 decltest(legacy_regif_extra_bufs_pipe),
1685 decltest(legacy_regif_extra_bufs_pipe_vale),
1689 context_cleanup(struct TestContext *ctx)
1701 parse_interval(const char *arg, int *j, int *k)
1703 const char *scan = arg;
1712 if (!isdigit(*scan))
1714 *k = strtol(scan, &rest, 10);
1724 if (!isdigit(*scan))
1726 *k = strtol(scan, &rest, 10);
1728 if (!(*scan == '\0'))
1734 fprintf(stderr, "syntax error in '%s', must be num[-[num]] or -[num]\n", arg);
1738 #define ARGV_APPEND(_av, _ac, _x)\
1740 assert((int)(_ac) < (int)(sizeof(_av)/sizeof((_av)[0])));\
1741 (_av)[(_ac)++] = _x;\
1745 tap_cleanup(int signo)
1752 ARGV_APPEND(av, ac, "ifconfig");
1753 ARGV_APPEND(av, ac, ctx_.ifname);
1754 ARGV_APPEND(av, ac, "destroy");
1756 ARGV_APPEND(av, ac, "ip");
1757 ARGV_APPEND(av, ac, "link");
1758 ARGV_APPEND(av, ac, "del");
1759 ARGV_APPEND(av, ac, ctx_.ifname);
1761 ARGV_APPEND(av, ac, NULL);
1762 if (exec_command(ac, av)) {
1763 printf("Failed to destroy tap interface\n");
1768 main(int argc, char **argv)
1779 memset(&ctx_, 0, sizeof(ctx_));
1785 clock_gettime(CLOCK_REALTIME, &t);
1786 srand((unsigned int)t.tv_nsec);
1787 idx = rand() % 8000 + 100;
1788 snprintf(ctx_.ifname, sizeof(ctx_.ifname), "tap%d", idx);
1789 idx = rand() % 800 + 100;
1790 snprintf(ctx_.bdgname, sizeof(ctx_.bdgname), "vale%d", idx);
1793 while ((opt = getopt(argc, argv, "hi:j:l")) != -1) {
1800 strncpy(ctx_.ifname, optarg, sizeof(ctx_.ifname) - 1);
1805 if (parse_interval(optarg, &j, &k) < 0) {
1817 printf(" Unrecognized option %c\n", opt);
1823 num_tests = sizeof(tests) / sizeof(tests[0]);
1825 if (j < 0 || j >= num_tests || k > num_tests) {
1826 fprintf(stderr, "Test interval %d-%d out of range (%d-%d)\n",
1827 j + 1, k, 1, num_tests + 1);
1835 printf("Available tests:\n");
1836 for (i = 0; i < num_tests; i++) {
1837 printf("#%03d: %s\n", i + 1, tests[i].name);
1843 struct sigaction sa;
1847 ARGV_APPEND(av, ac, "ifconfig");
1848 ARGV_APPEND(av, ac, ctx_.ifname);
1849 ARGV_APPEND(av, ac, "create");
1850 ARGV_APPEND(av, ac, "up");
1852 ARGV_APPEND(av, ac, "ip");
1853 ARGV_APPEND(av, ac, "tuntap");
1854 ARGV_APPEND(av, ac, "add");
1855 ARGV_APPEND(av, ac, "mode");
1856 ARGV_APPEND(av, ac, "tap");
1857 ARGV_APPEND(av, ac, "name");
1858 ARGV_APPEND(av, ac, ctx_.ifname);
1860 ARGV_APPEND(av, ac, NULL);
1861 if (exec_command(ac, av)) {
1862 printf("Failed to create tap interface\n");
1866 sa.sa_handler = tap_cleanup;
1867 sigemptyset(&sa.sa_mask);
1868 sa.sa_flags = SA_RESTART;
1869 ret = sigaction(SIGINT, &sa, NULL);
1871 perror("sigaction(SIGINT)");
1874 ret = sigaction(SIGTERM, &sa, NULL);
1876 perror("sigaction(SIGTERM)");
1881 for (i = j; i < k; i++) {
1882 struct TestContext ctxcopy;
1884 printf("==> Start of Test #%d [%s]\n", i + 1, tests[i].name);
1885 fd = open("/dev/netmap", O_RDWR);
1887 perror("open(/dev/netmap)");
1891 memcpy(&ctxcopy, &ctx_, sizeof(ctxcopy));
1893 ret = tests[i].test(&ctxcopy);
1895 printf("Test #%d [%s] failed\n", i + 1, tests[i].name);
1898 printf("==> Test #%d [%s] successful\n", i + 1, tests[i].name);
1899 context_cleanup(&ctxcopy);