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