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