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