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