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