1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2017-2018 Covalent IO, Inc. http://covalent.io 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <sys/socket.h> 6 #include <sys/ioctl.h> 7 #include <sys/select.h> 8 #include <netinet/in.h> 9 #include <arpa/inet.h> 10 #include <unistd.h> 11 #include <string.h> 12 #include <errno.h> 13 #include <sys/ioctl.h> 14 #include <stdbool.h> 15 #include <signal.h> 16 #include <fcntl.h> 17 #include <sys/wait.h> 18 #include <time.h> 19 #include <sched.h> 20 21 #include <sys/time.h> 22 #include <sys/resource.h> 23 #include <sys/types.h> 24 #include <sys/sendfile.h> 25 26 #include <linux/netlink.h> 27 #include <linux/socket.h> 28 #include <linux/sock_diag.h> 29 #include <linux/bpf.h> 30 #include <linux/if_link.h> 31 #include <assert.h> 32 #include <libgen.h> 33 34 #include <getopt.h> 35 36 #include <bpf/bpf.h> 37 #include <bpf/libbpf.h> 38 39 #include "bpf_util.h" 40 #include "bpf_rlimit.h" 41 #include "cgroup_helpers.h" 42 43 int running; 44 static void running_handler(int a); 45 46 /* randomly selected ports for testing on lo */ 47 #define S1_PORT 10000 48 #define S2_PORT 10001 49 50 #define BPF_SOCKMAP_FILENAME "test_sockmap_kern.o" 51 #define BPF_SOCKHASH_FILENAME "test_sockhash_kern.o" 52 #define CG_PATH "/sockmap" 53 54 /* global sockets */ 55 int s1, s2, c1, c2, p1, p2; 56 int test_cnt; 57 int passed; 58 int failed; 59 int map_fd[8]; 60 struct bpf_map *maps[8]; 61 int prog_fd[11]; 62 63 int txmsg_pass; 64 int txmsg_noisy; 65 int txmsg_redir; 66 int txmsg_redir_noisy; 67 int txmsg_drop; 68 int txmsg_apply; 69 int txmsg_cork; 70 int txmsg_start; 71 int txmsg_end; 72 int txmsg_ingress; 73 int txmsg_skb; 74 int ktls; 75 76 static const struct option long_options[] = { 77 {"help", no_argument, NULL, 'h' }, 78 {"cgroup", required_argument, NULL, 'c' }, 79 {"rate", required_argument, NULL, 'r' }, 80 {"verbose", no_argument, NULL, 'v' }, 81 {"iov_count", required_argument, NULL, 'i' }, 82 {"length", required_argument, NULL, 'l' }, 83 {"test", required_argument, NULL, 't' }, 84 {"data_test", no_argument, NULL, 'd' }, 85 {"txmsg", no_argument, &txmsg_pass, 1 }, 86 {"txmsg_noisy", no_argument, &txmsg_noisy, 1 }, 87 {"txmsg_redir", no_argument, &txmsg_redir, 1 }, 88 {"txmsg_redir_noisy", no_argument, &txmsg_redir_noisy, 1}, 89 {"txmsg_drop", no_argument, &txmsg_drop, 1 }, 90 {"txmsg_apply", required_argument, NULL, 'a'}, 91 {"txmsg_cork", required_argument, NULL, 'k'}, 92 {"txmsg_start", required_argument, NULL, 's'}, 93 {"txmsg_end", required_argument, NULL, 'e'}, 94 {"txmsg_ingress", no_argument, &txmsg_ingress, 1 }, 95 {"txmsg_skb", no_argument, &txmsg_skb, 1 }, 96 {"ktls", no_argument, &ktls, 1 }, 97 {0, 0, NULL, 0 } 98 }; 99 100 static void usage(char *argv[]) 101 { 102 int i; 103 104 printf(" Usage: %s --cgroup <cgroup_path>\n", argv[0]); 105 printf(" options:\n"); 106 for (i = 0; long_options[i].name != 0; i++) { 107 printf(" --%-12s", long_options[i].name); 108 if (long_options[i].flag != NULL) 109 printf(" flag (internal value:%d)\n", 110 *long_options[i].flag); 111 else 112 printf(" -%c\n", long_options[i].val); 113 } 114 printf("\n"); 115 } 116 117 #define TCP_ULP 31 118 #define TLS_TX 1 119 #define TLS_RX 2 120 #include <linux/tls.h> 121 122 char *sock_to_string(int s) 123 { 124 if (s == c1) 125 return "client1"; 126 else if (s == c2) 127 return "client2"; 128 else if (s == s1) 129 return "server1"; 130 else if (s == s2) 131 return "server2"; 132 else if (s == p1) 133 return "peer1"; 134 else if (s == p2) 135 return "peer2"; 136 else 137 return "unknown"; 138 } 139 140 static int sockmap_init_ktls(int verbose, int s) 141 { 142 struct tls12_crypto_info_aes_gcm_128 tls_tx = { 143 .info = { 144 .version = TLS_1_2_VERSION, 145 .cipher_type = TLS_CIPHER_AES_GCM_128, 146 }, 147 }; 148 struct tls12_crypto_info_aes_gcm_128 tls_rx = { 149 .info = { 150 .version = TLS_1_2_VERSION, 151 .cipher_type = TLS_CIPHER_AES_GCM_128, 152 }, 153 }; 154 int so_buf = 6553500; 155 int err; 156 157 err = setsockopt(s, 6, TCP_ULP, "tls", sizeof("tls")); 158 if (err) { 159 fprintf(stderr, "setsockopt: TCP_ULP(%s) failed with error %i\n", sock_to_string(s), err); 160 return -EINVAL; 161 } 162 err = setsockopt(s, SOL_TLS, TLS_TX, (void *)&tls_tx, sizeof(tls_tx)); 163 if (err) { 164 fprintf(stderr, "setsockopt: TLS_TX(%s) failed with error %i\n", sock_to_string(s), err); 165 return -EINVAL; 166 } 167 err = setsockopt(s, SOL_TLS, TLS_RX, (void *)&tls_rx, sizeof(tls_rx)); 168 if (err) { 169 fprintf(stderr, "setsockopt: TLS_RX(%s) failed with error %i\n", sock_to_string(s), err); 170 return -EINVAL; 171 } 172 err = setsockopt(s, SOL_SOCKET, SO_SNDBUF, &so_buf, sizeof(so_buf)); 173 if (err) { 174 fprintf(stderr, "setsockopt: (%s) failed sndbuf with error %i\n", sock_to_string(s), err); 175 return -EINVAL; 176 } 177 err = setsockopt(s, SOL_SOCKET, SO_RCVBUF, &so_buf, sizeof(so_buf)); 178 if (err) { 179 fprintf(stderr, "setsockopt: (%s) failed rcvbuf with error %i\n", sock_to_string(s), err); 180 return -EINVAL; 181 } 182 183 if (verbose) 184 fprintf(stdout, "socket(%s) kTLS enabled\n", sock_to_string(s)); 185 return 0; 186 } 187 static int sockmap_init_sockets(int verbose) 188 { 189 int i, err, one = 1; 190 struct sockaddr_in addr; 191 int *fds[4] = {&s1, &s2, &c1, &c2}; 192 193 s1 = s2 = p1 = p2 = c1 = c2 = 0; 194 195 /* Init sockets */ 196 for (i = 0; i < 4; i++) { 197 *fds[i] = socket(AF_INET, SOCK_STREAM, 0); 198 if (*fds[i] < 0) { 199 perror("socket s1 failed()"); 200 return errno; 201 } 202 } 203 204 /* Allow reuse */ 205 for (i = 0; i < 2; i++) { 206 err = setsockopt(*fds[i], SOL_SOCKET, SO_REUSEADDR, 207 (char *)&one, sizeof(one)); 208 if (err) { 209 perror("setsockopt failed()"); 210 return errno; 211 } 212 } 213 214 /* Non-blocking sockets */ 215 for (i = 0; i < 2; i++) { 216 err = ioctl(*fds[i], FIONBIO, (char *)&one); 217 if (err < 0) { 218 perror("ioctl s1 failed()"); 219 return errno; 220 } 221 } 222 223 /* Bind server sockets */ 224 memset(&addr, 0, sizeof(struct sockaddr_in)); 225 addr.sin_family = AF_INET; 226 addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 227 228 addr.sin_port = htons(S1_PORT); 229 err = bind(s1, (struct sockaddr *)&addr, sizeof(addr)); 230 if (err < 0) { 231 perror("bind s1 failed()\n"); 232 return errno; 233 } 234 235 addr.sin_port = htons(S2_PORT); 236 err = bind(s2, (struct sockaddr *)&addr, sizeof(addr)); 237 if (err < 0) { 238 perror("bind s2 failed()\n"); 239 return errno; 240 } 241 242 /* Listen server sockets */ 243 addr.sin_port = htons(S1_PORT); 244 err = listen(s1, 32); 245 if (err < 0) { 246 perror("listen s1 failed()\n"); 247 return errno; 248 } 249 250 addr.sin_port = htons(S2_PORT); 251 err = listen(s2, 32); 252 if (err < 0) { 253 perror("listen s1 failed()\n"); 254 return errno; 255 } 256 257 /* Initiate Connect */ 258 addr.sin_port = htons(S1_PORT); 259 err = connect(c1, (struct sockaddr *)&addr, sizeof(addr)); 260 if (err < 0 && errno != EINPROGRESS) { 261 perror("connect c1 failed()\n"); 262 return errno; 263 } 264 265 addr.sin_port = htons(S2_PORT); 266 err = connect(c2, (struct sockaddr *)&addr, sizeof(addr)); 267 if (err < 0 && errno != EINPROGRESS) { 268 perror("connect c2 failed()\n"); 269 return errno; 270 } else if (err < 0) { 271 err = 0; 272 } 273 274 /* Accept Connecrtions */ 275 p1 = accept(s1, NULL, NULL); 276 if (p1 < 0) { 277 perror("accept s1 failed()\n"); 278 return errno; 279 } 280 281 p2 = accept(s2, NULL, NULL); 282 if (p2 < 0) { 283 perror("accept s1 failed()\n"); 284 return errno; 285 } 286 287 if (verbose) { 288 printf("connected sockets: c1 <-> p1, c2 <-> p2\n"); 289 printf("cgroups binding: c1(%i) <-> s1(%i) - - - c2(%i) <-> s2(%i)\n", 290 c1, s1, c2, s2); 291 } 292 return 0; 293 } 294 295 struct msg_stats { 296 size_t bytes_sent; 297 size_t bytes_recvd; 298 struct timespec start; 299 struct timespec end; 300 }; 301 302 struct sockmap_options { 303 int verbose; 304 bool base; 305 bool sendpage; 306 bool data_test; 307 bool drop_expected; 308 int iov_count; 309 int iov_length; 310 int rate; 311 }; 312 313 static int msg_loop_sendpage(int fd, int iov_length, int cnt, 314 struct msg_stats *s, 315 struct sockmap_options *opt) 316 { 317 bool drop = opt->drop_expected; 318 unsigned char k = 0; 319 FILE *file; 320 int i, fp; 321 322 file = fopen(".sendpage_tst.tmp", "w+"); 323 for (i = 0; i < iov_length * cnt; i++, k++) 324 fwrite(&k, sizeof(char), 1, file); 325 fflush(file); 326 fseek(file, 0, SEEK_SET); 327 fclose(file); 328 329 fp = open(".sendpage_tst.tmp", O_RDONLY); 330 clock_gettime(CLOCK_MONOTONIC, &s->start); 331 for (i = 0; i < cnt; i++) { 332 int sent = sendfile(fd, fp, NULL, iov_length); 333 334 if (!drop && sent < 0) { 335 perror("send loop error:"); 336 close(fp); 337 return sent; 338 } else if (drop && sent >= 0) { 339 printf("sendpage loop error expected: %i\n", sent); 340 close(fp); 341 return -EIO; 342 } 343 344 if (sent > 0) 345 s->bytes_sent += sent; 346 } 347 clock_gettime(CLOCK_MONOTONIC, &s->end); 348 close(fp); 349 return 0; 350 } 351 352 static int msg_loop(int fd, int iov_count, int iov_length, int cnt, 353 struct msg_stats *s, bool tx, 354 struct sockmap_options *opt) 355 { 356 struct msghdr msg = {0}; 357 int err, i, flags = MSG_NOSIGNAL; 358 struct iovec *iov; 359 unsigned char k; 360 bool data_test = opt->data_test; 361 bool drop = opt->drop_expected; 362 363 iov = calloc(iov_count, sizeof(struct iovec)); 364 if (!iov) 365 return errno; 366 367 k = 0; 368 for (i = 0; i < iov_count; i++) { 369 unsigned char *d = calloc(iov_length, sizeof(char)); 370 371 if (!d) { 372 fprintf(stderr, "iov_count %i/%i OOM\n", i, iov_count); 373 goto out_errno; 374 } 375 iov[i].iov_base = d; 376 iov[i].iov_len = iov_length; 377 378 if (data_test && tx) { 379 int j; 380 381 for (j = 0; j < iov_length; j++) 382 d[j] = k++; 383 } 384 } 385 386 msg.msg_iov = iov; 387 msg.msg_iovlen = iov_count; 388 k = 0; 389 390 if (tx) { 391 clock_gettime(CLOCK_MONOTONIC, &s->start); 392 for (i = 0; i < cnt; i++) { 393 int sent = sendmsg(fd, &msg, flags); 394 395 if (!drop && sent < 0) { 396 perror("send loop error:"); 397 goto out_errno; 398 } else if (drop && sent >= 0) { 399 printf("send loop error expected: %i\n", sent); 400 errno = -EIO; 401 goto out_errno; 402 } 403 if (sent > 0) 404 s->bytes_sent += sent; 405 } 406 clock_gettime(CLOCK_MONOTONIC, &s->end); 407 } else { 408 int slct, recv, max_fd = fd; 409 int fd_flags = O_NONBLOCK; 410 struct timeval timeout; 411 float total_bytes; 412 int bytes_cnt = 0; 413 int chunk_sz; 414 fd_set w; 415 416 if (opt->sendpage) 417 chunk_sz = iov_length * cnt; 418 else 419 chunk_sz = iov_length * iov_count; 420 421 fcntl(fd, fd_flags); 422 total_bytes = (float)iov_count * (float)iov_length * (float)cnt; 423 err = clock_gettime(CLOCK_MONOTONIC, &s->start); 424 if (err < 0) 425 perror("recv start time: "); 426 while (s->bytes_recvd < total_bytes) { 427 if (txmsg_cork) { 428 timeout.tv_sec = 0; 429 timeout.tv_usec = 300000; 430 } else { 431 timeout.tv_sec = 1; 432 timeout.tv_usec = 0; 433 } 434 435 /* FD sets */ 436 FD_ZERO(&w); 437 FD_SET(fd, &w); 438 439 slct = select(max_fd + 1, &w, NULL, NULL, &timeout); 440 if (slct == -1) { 441 perror("select()"); 442 clock_gettime(CLOCK_MONOTONIC, &s->end); 443 goto out_errno; 444 } else if (!slct) { 445 if (opt->verbose) 446 fprintf(stderr, "unexpected timeout\n"); 447 errno = -EIO; 448 clock_gettime(CLOCK_MONOTONIC, &s->end); 449 goto out_errno; 450 } 451 452 recv = recvmsg(fd, &msg, flags); 453 if (recv < 0) { 454 if (errno != EWOULDBLOCK) { 455 clock_gettime(CLOCK_MONOTONIC, &s->end); 456 perror("recv failed()\n"); 457 goto out_errno; 458 } 459 } 460 461 s->bytes_recvd += recv; 462 463 if (data_test) { 464 int j; 465 466 for (i = 0; i < msg.msg_iovlen; i++) { 467 unsigned char *d = iov[i].iov_base; 468 469 for (j = 0; 470 j < iov[i].iov_len && recv; j++) { 471 if (d[j] != k++) { 472 errno = -EIO; 473 fprintf(stderr, 474 "detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n", 475 i, j, d[j], k - 1, d[j+1], k); 476 goto out_errno; 477 } 478 bytes_cnt++; 479 if (bytes_cnt == chunk_sz) { 480 k = 0; 481 bytes_cnt = 0; 482 } 483 recv--; 484 } 485 } 486 } 487 } 488 clock_gettime(CLOCK_MONOTONIC, &s->end); 489 } 490 491 for (i = 0; i < iov_count; i++) 492 free(iov[i].iov_base); 493 free(iov); 494 return 0; 495 out_errno: 496 for (i = 0; i < iov_count; i++) 497 free(iov[i].iov_base); 498 free(iov); 499 return errno; 500 } 501 502 static float giga = 1000000000; 503 504 static inline float sentBps(struct msg_stats s) 505 { 506 return s.bytes_sent / (s.end.tv_sec - s.start.tv_sec); 507 } 508 509 static inline float recvdBps(struct msg_stats s) 510 { 511 return s.bytes_recvd / (s.end.tv_sec - s.start.tv_sec); 512 } 513 514 static int sendmsg_test(struct sockmap_options *opt) 515 { 516 float sent_Bps = 0, recvd_Bps = 0; 517 int rx_fd, txpid, rxpid, err = 0; 518 struct msg_stats s = {0}; 519 int iov_count = opt->iov_count; 520 int iov_buf = opt->iov_length; 521 int rx_status, tx_status; 522 int cnt = opt->rate; 523 524 errno = 0; 525 526 if (opt->base) 527 rx_fd = p1; 528 else 529 rx_fd = p2; 530 531 if (ktls) { 532 /* Redirecting into non-TLS socket which sends into a TLS 533 * socket is not a valid test. So in this case lets not 534 * enable kTLS but still run the test. 535 */ 536 if (!txmsg_redir || (txmsg_redir && txmsg_ingress)) { 537 err = sockmap_init_ktls(opt->verbose, rx_fd); 538 if (err) 539 return err; 540 } 541 err = sockmap_init_ktls(opt->verbose, c1); 542 if (err) 543 return err; 544 } 545 546 rxpid = fork(); 547 if (rxpid == 0) { 548 if (opt->drop_expected) 549 exit(0); 550 551 if (opt->sendpage) 552 iov_count = 1; 553 err = msg_loop(rx_fd, iov_count, iov_buf, 554 cnt, &s, false, opt); 555 if (err && opt->verbose) 556 fprintf(stderr, 557 "msg_loop_rx: iov_count %i iov_buf %i cnt %i err %i\n", 558 iov_count, iov_buf, cnt, err); 559 if (s.end.tv_sec - s.start.tv_sec) { 560 sent_Bps = sentBps(s); 561 recvd_Bps = recvdBps(s); 562 } 563 if (opt->verbose) 564 fprintf(stdout, 565 "rx_sendmsg: TX: %zuB %fB/s %fGB/s RX: %zuB %fB/s %fGB/s\n", 566 s.bytes_sent, sent_Bps, sent_Bps/giga, 567 s.bytes_recvd, recvd_Bps, recvd_Bps/giga); 568 if (err && txmsg_cork) 569 err = 0; 570 exit(err ? 1 : 0); 571 } else if (rxpid == -1) { 572 perror("msg_loop_rx: "); 573 return errno; 574 } 575 576 txpid = fork(); 577 if (txpid == 0) { 578 if (opt->sendpage) 579 err = msg_loop_sendpage(c1, iov_buf, cnt, &s, opt); 580 else 581 err = msg_loop(c1, iov_count, iov_buf, 582 cnt, &s, true, opt); 583 584 if (err) 585 fprintf(stderr, 586 "msg_loop_tx: iov_count %i iov_buf %i cnt %i err %i\n", 587 iov_count, iov_buf, cnt, err); 588 if (s.end.tv_sec - s.start.tv_sec) { 589 sent_Bps = sentBps(s); 590 recvd_Bps = recvdBps(s); 591 } 592 if (opt->verbose) 593 fprintf(stdout, 594 "tx_sendmsg: TX: %zuB %fB/s %f GB/s RX: %zuB %fB/s %fGB/s\n", 595 s.bytes_sent, sent_Bps, sent_Bps/giga, 596 s.bytes_recvd, recvd_Bps, recvd_Bps/giga); 597 exit(err ? 1 : 0); 598 } else if (txpid == -1) { 599 perror("msg_loop_tx: "); 600 return errno; 601 } 602 603 assert(waitpid(rxpid, &rx_status, 0) == rxpid); 604 assert(waitpid(txpid, &tx_status, 0) == txpid); 605 if (WIFEXITED(rx_status)) { 606 err = WEXITSTATUS(rx_status); 607 if (err) { 608 fprintf(stderr, "rx thread exited with err %d. ", err); 609 goto out; 610 } 611 } 612 if (WIFEXITED(tx_status)) { 613 err = WEXITSTATUS(tx_status); 614 if (err) 615 fprintf(stderr, "tx thread exited with err %d. ", err); 616 } 617 out: 618 return err; 619 } 620 621 static int forever_ping_pong(int rate, struct sockmap_options *opt) 622 { 623 struct timeval timeout; 624 char buf[1024] = {0}; 625 int sc; 626 627 timeout.tv_sec = 10; 628 timeout.tv_usec = 0; 629 630 /* Ping/Pong data from client to server */ 631 sc = send(c1, buf, sizeof(buf), 0); 632 if (sc < 0) { 633 perror("send failed()\n"); 634 return sc; 635 } 636 637 do { 638 int s, rc, i, max_fd = p2; 639 fd_set w; 640 641 /* FD sets */ 642 FD_ZERO(&w); 643 FD_SET(c1, &w); 644 FD_SET(c2, &w); 645 FD_SET(p1, &w); 646 FD_SET(p2, &w); 647 648 s = select(max_fd + 1, &w, NULL, NULL, &timeout); 649 if (s == -1) { 650 perror("select()"); 651 break; 652 } else if (!s) { 653 fprintf(stderr, "unexpected timeout\n"); 654 break; 655 } 656 657 for (i = 0; i <= max_fd && s > 0; ++i) { 658 if (!FD_ISSET(i, &w)) 659 continue; 660 661 s--; 662 663 rc = recv(i, buf, sizeof(buf), 0); 664 if (rc < 0) { 665 if (errno != EWOULDBLOCK) { 666 perror("recv failed()\n"); 667 return rc; 668 } 669 } 670 671 if (rc == 0) { 672 close(i); 673 break; 674 } 675 676 sc = send(i, buf, rc, 0); 677 if (sc < 0) { 678 perror("send failed()\n"); 679 return sc; 680 } 681 } 682 683 if (rate) 684 sleep(rate); 685 686 if (opt->verbose) { 687 printf("."); 688 fflush(stdout); 689 690 } 691 } while (running); 692 693 return 0; 694 } 695 696 enum { 697 PING_PONG, 698 SENDMSG, 699 BASE, 700 BASE_SENDPAGE, 701 SENDPAGE, 702 }; 703 704 static int run_options(struct sockmap_options *options, int cg_fd, int test) 705 { 706 int i, key, next_key, err, tx_prog_fd = -1, zero = 0; 707 708 /* If base test skip BPF setup */ 709 if (test == BASE || test == BASE_SENDPAGE) 710 goto run; 711 712 /* Attach programs to sockmap */ 713 err = bpf_prog_attach(prog_fd[0], map_fd[0], 714 BPF_SK_SKB_STREAM_PARSER, 0); 715 if (err) { 716 fprintf(stderr, 717 "ERROR: bpf_prog_attach (sockmap %i->%i): %d (%s)\n", 718 prog_fd[0], map_fd[0], err, strerror(errno)); 719 return err; 720 } 721 722 err = bpf_prog_attach(prog_fd[1], map_fd[0], 723 BPF_SK_SKB_STREAM_VERDICT, 0); 724 if (err) { 725 fprintf(stderr, "ERROR: bpf_prog_attach (sockmap): %d (%s)\n", 726 err, strerror(errno)); 727 return err; 728 } 729 730 /* Attach to cgroups */ 731 err = bpf_prog_attach(prog_fd[2], cg_fd, BPF_CGROUP_SOCK_OPS, 0); 732 if (err) { 733 fprintf(stderr, "ERROR: bpf_prog_attach (groups): %d (%s)\n", 734 err, strerror(errno)); 735 return err; 736 } 737 738 run: 739 err = sockmap_init_sockets(options->verbose); 740 if (err) { 741 fprintf(stderr, "ERROR: test socket failed: %d\n", err); 742 goto out; 743 } 744 745 /* Attach txmsg program to sockmap */ 746 if (txmsg_pass) 747 tx_prog_fd = prog_fd[3]; 748 else if (txmsg_noisy) 749 tx_prog_fd = prog_fd[4]; 750 else if (txmsg_redir) 751 tx_prog_fd = prog_fd[5]; 752 else if (txmsg_redir_noisy) 753 tx_prog_fd = prog_fd[6]; 754 else if (txmsg_drop) 755 tx_prog_fd = prog_fd[9]; 756 /* apply and cork must be last */ 757 else if (txmsg_apply) 758 tx_prog_fd = prog_fd[7]; 759 else if (txmsg_cork) 760 tx_prog_fd = prog_fd[8]; 761 else 762 tx_prog_fd = 0; 763 764 if (tx_prog_fd) { 765 int redir_fd, i = 0; 766 767 err = bpf_prog_attach(tx_prog_fd, 768 map_fd[1], BPF_SK_MSG_VERDICT, 0); 769 if (err) { 770 fprintf(stderr, 771 "ERROR: bpf_prog_attach (txmsg): %d (%s)\n", 772 err, strerror(errno)); 773 goto out; 774 } 775 776 err = bpf_map_update_elem(map_fd[1], &i, &c1, BPF_ANY); 777 if (err) { 778 fprintf(stderr, 779 "ERROR: bpf_map_update_elem (txmsg): %d (%s\n", 780 err, strerror(errno)); 781 goto out; 782 } 783 784 if (txmsg_redir || txmsg_redir_noisy) 785 redir_fd = c2; 786 else 787 redir_fd = c1; 788 789 err = bpf_map_update_elem(map_fd[2], &i, &redir_fd, BPF_ANY); 790 if (err) { 791 fprintf(stderr, 792 "ERROR: bpf_map_update_elem (txmsg): %d (%s\n", 793 err, strerror(errno)); 794 goto out; 795 } 796 797 if (txmsg_apply) { 798 err = bpf_map_update_elem(map_fd[3], 799 &i, &txmsg_apply, BPF_ANY); 800 if (err) { 801 fprintf(stderr, 802 "ERROR: bpf_map_update_elem (apply_bytes): %d (%s\n", 803 err, strerror(errno)); 804 goto out; 805 } 806 } 807 808 if (txmsg_cork) { 809 err = bpf_map_update_elem(map_fd[4], 810 &i, &txmsg_cork, BPF_ANY); 811 if (err) { 812 fprintf(stderr, 813 "ERROR: bpf_map_update_elem (cork_bytes): %d (%s\n", 814 err, strerror(errno)); 815 goto out; 816 } 817 } 818 819 if (txmsg_start) { 820 err = bpf_map_update_elem(map_fd[5], 821 &i, &txmsg_start, BPF_ANY); 822 if (err) { 823 fprintf(stderr, 824 "ERROR: bpf_map_update_elem (txmsg_start): %d (%s)\n", 825 err, strerror(errno)); 826 goto out; 827 } 828 } 829 830 if (txmsg_end) { 831 i = 1; 832 err = bpf_map_update_elem(map_fd[5], 833 &i, &txmsg_end, BPF_ANY); 834 if (err) { 835 fprintf(stderr, 836 "ERROR: bpf_map_update_elem (txmsg_end): %d (%s)\n", 837 err, strerror(errno)); 838 goto out; 839 } 840 } 841 842 if (txmsg_ingress) { 843 int in = BPF_F_INGRESS; 844 845 i = 0; 846 err = bpf_map_update_elem(map_fd[6], &i, &in, BPF_ANY); 847 if (err) { 848 fprintf(stderr, 849 "ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n", 850 err, strerror(errno)); 851 } 852 i = 1; 853 err = bpf_map_update_elem(map_fd[1], &i, &p1, BPF_ANY); 854 if (err) { 855 fprintf(stderr, 856 "ERROR: bpf_map_update_elem (p1 txmsg): %d (%s)\n", 857 err, strerror(errno)); 858 } 859 err = bpf_map_update_elem(map_fd[2], &i, &p1, BPF_ANY); 860 if (err) { 861 fprintf(stderr, 862 "ERROR: bpf_map_update_elem (p1 redir): %d (%s)\n", 863 err, strerror(errno)); 864 } 865 866 i = 2; 867 err = bpf_map_update_elem(map_fd[2], &i, &p2, BPF_ANY); 868 if (err) { 869 fprintf(stderr, 870 "ERROR: bpf_map_update_elem (p2 txmsg): %d (%s)\n", 871 err, strerror(errno)); 872 } 873 } 874 875 if (txmsg_skb) { 876 int skb_fd = (test == SENDMSG || test == SENDPAGE) ? 877 p2 : p1; 878 int ingress = BPF_F_INGRESS; 879 880 i = 0; 881 err = bpf_map_update_elem(map_fd[7], 882 &i, &ingress, BPF_ANY); 883 if (err) { 884 fprintf(stderr, 885 "ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n", 886 err, strerror(errno)); 887 } 888 889 i = 3; 890 err = bpf_map_update_elem(map_fd[0], 891 &i, &skb_fd, BPF_ANY); 892 if (err) { 893 fprintf(stderr, 894 "ERROR: bpf_map_update_elem (c1 sockmap): %d (%s)\n", 895 err, strerror(errno)); 896 } 897 } 898 } 899 900 if (txmsg_drop) 901 options->drop_expected = true; 902 903 if (test == PING_PONG) 904 err = forever_ping_pong(options->rate, options); 905 else if (test == SENDMSG) { 906 options->base = false; 907 options->sendpage = false; 908 err = sendmsg_test(options); 909 } else if (test == SENDPAGE) { 910 options->base = false; 911 options->sendpage = true; 912 err = sendmsg_test(options); 913 } else if (test == BASE) { 914 options->base = true; 915 options->sendpage = false; 916 err = sendmsg_test(options); 917 } else if (test == BASE_SENDPAGE) { 918 options->base = true; 919 options->sendpage = true; 920 err = sendmsg_test(options); 921 } else 922 fprintf(stderr, "unknown test\n"); 923 out: 924 /* Detatch and zero all the maps */ 925 bpf_prog_detach2(prog_fd[2], cg_fd, BPF_CGROUP_SOCK_OPS); 926 bpf_prog_detach2(prog_fd[0], map_fd[0], BPF_SK_SKB_STREAM_PARSER); 927 bpf_prog_detach2(prog_fd[1], map_fd[0], BPF_SK_SKB_STREAM_VERDICT); 928 if (tx_prog_fd >= 0) 929 bpf_prog_detach2(tx_prog_fd, map_fd[1], BPF_SK_MSG_VERDICT); 930 931 for (i = 0; i < 8; i++) { 932 key = next_key = 0; 933 bpf_map_update_elem(map_fd[i], &key, &zero, BPF_ANY); 934 while (bpf_map_get_next_key(map_fd[i], &key, &next_key) == 0) { 935 bpf_map_update_elem(map_fd[i], &key, &zero, BPF_ANY); 936 key = next_key; 937 } 938 } 939 940 close(s1); 941 close(s2); 942 close(p1); 943 close(p2); 944 close(c1); 945 close(c2); 946 return err; 947 } 948 949 static char *test_to_str(int test) 950 { 951 switch (test) { 952 case SENDMSG: 953 return "sendmsg"; 954 case SENDPAGE: 955 return "sendpage"; 956 } 957 return "unknown"; 958 } 959 960 #define OPTSTRING 60 961 static void test_options(char *options) 962 { 963 char tstr[OPTSTRING]; 964 965 memset(options, 0, OPTSTRING); 966 967 if (txmsg_pass) 968 strncat(options, "pass,", OPTSTRING); 969 if (txmsg_noisy) 970 strncat(options, "pass_noisy,", OPTSTRING); 971 if (txmsg_redir) 972 strncat(options, "redir,", OPTSTRING); 973 if (txmsg_redir_noisy) 974 strncat(options, "redir_noisy,", OPTSTRING); 975 if (txmsg_drop) 976 strncat(options, "drop,", OPTSTRING); 977 if (txmsg_apply) { 978 snprintf(tstr, OPTSTRING, "apply %d,", txmsg_apply); 979 strncat(options, tstr, OPTSTRING); 980 } 981 if (txmsg_cork) { 982 snprintf(tstr, OPTSTRING, "cork %d,", txmsg_cork); 983 strncat(options, tstr, OPTSTRING); 984 } 985 if (txmsg_start) { 986 snprintf(tstr, OPTSTRING, "start %d,", txmsg_start); 987 strncat(options, tstr, OPTSTRING); 988 } 989 if (txmsg_end) { 990 snprintf(tstr, OPTSTRING, "end %d,", txmsg_end); 991 strncat(options, tstr, OPTSTRING); 992 } 993 if (txmsg_ingress) 994 strncat(options, "ingress,", OPTSTRING); 995 if (txmsg_skb) 996 strncat(options, "skb,", OPTSTRING); 997 if (ktls) 998 strncat(options, "ktls,", OPTSTRING); 999 } 1000 1001 static int __test_exec(int cgrp, int test, struct sockmap_options *opt) 1002 { 1003 char *options = calloc(OPTSTRING, sizeof(char)); 1004 int err; 1005 1006 if (test == SENDPAGE) 1007 opt->sendpage = true; 1008 else 1009 opt->sendpage = false; 1010 1011 if (txmsg_drop) 1012 opt->drop_expected = true; 1013 else 1014 opt->drop_expected = false; 1015 1016 test_options(options); 1017 1018 fprintf(stdout, 1019 "[TEST %i]: (%i, %i, %i, %s, %s): ", 1020 test_cnt, opt->rate, opt->iov_count, opt->iov_length, 1021 test_to_str(test), options); 1022 fflush(stdout); 1023 err = run_options(opt, cgrp, test); 1024 fprintf(stdout, "%s\n", !err ? "PASS" : "FAILED"); 1025 test_cnt++; 1026 !err ? passed++ : failed++; 1027 free(options); 1028 return err; 1029 } 1030 1031 static int test_exec(int cgrp, struct sockmap_options *opt) 1032 { 1033 int err = __test_exec(cgrp, SENDMSG, opt); 1034 1035 if (err) 1036 goto out; 1037 1038 err = __test_exec(cgrp, SENDPAGE, opt); 1039 out: 1040 return err; 1041 } 1042 1043 static int test_loop(int cgrp) 1044 { 1045 struct sockmap_options opt; 1046 1047 int err, i, l, r; 1048 1049 opt.verbose = 0; 1050 opt.base = false; 1051 opt.sendpage = false; 1052 opt.data_test = false; 1053 opt.drop_expected = false; 1054 opt.iov_count = 0; 1055 opt.iov_length = 0; 1056 opt.rate = 0; 1057 1058 r = 1; 1059 for (i = 1; i < 100; i += 33) { 1060 for (l = 1; l < 100; l += 33) { 1061 opt.rate = r; 1062 opt.iov_count = i; 1063 opt.iov_length = l; 1064 err = test_exec(cgrp, &opt); 1065 if (err) 1066 goto out; 1067 } 1068 } 1069 sched_yield(); 1070 out: 1071 return err; 1072 } 1073 1074 static int test_txmsg(int cgrp) 1075 { 1076 int err; 1077 1078 txmsg_pass = txmsg_noisy = txmsg_redir_noisy = txmsg_drop = 0; 1079 txmsg_apply = txmsg_cork = 0; 1080 txmsg_ingress = txmsg_skb = 0; 1081 1082 txmsg_pass = 1; 1083 err = test_loop(cgrp); 1084 txmsg_pass = 0; 1085 if (err) 1086 goto out; 1087 1088 txmsg_redir = 1; 1089 err = test_loop(cgrp); 1090 txmsg_redir = 0; 1091 if (err) 1092 goto out; 1093 1094 txmsg_drop = 1; 1095 err = test_loop(cgrp); 1096 txmsg_drop = 0; 1097 if (err) 1098 goto out; 1099 1100 txmsg_redir = 1; 1101 txmsg_ingress = 1; 1102 err = test_loop(cgrp); 1103 txmsg_redir = 0; 1104 txmsg_ingress = 0; 1105 if (err) 1106 goto out; 1107 out: 1108 txmsg_pass = 0; 1109 txmsg_redir = 0; 1110 txmsg_drop = 0; 1111 return err; 1112 } 1113 1114 static int test_send(struct sockmap_options *opt, int cgrp) 1115 { 1116 int err; 1117 1118 opt->iov_length = 1; 1119 opt->iov_count = 1; 1120 opt->rate = 1; 1121 err = test_exec(cgrp, opt); 1122 if (err) 1123 goto out; 1124 1125 opt->iov_length = 1; 1126 opt->iov_count = 1024; 1127 opt->rate = 1; 1128 err = test_exec(cgrp, opt); 1129 if (err) 1130 goto out; 1131 1132 opt->iov_length = 1024; 1133 opt->iov_count = 1; 1134 opt->rate = 1; 1135 err = test_exec(cgrp, opt); 1136 if (err) 1137 goto out; 1138 1139 opt->iov_length = 1; 1140 opt->iov_count = 1; 1141 opt->rate = 512; 1142 err = test_exec(cgrp, opt); 1143 if (err) 1144 goto out; 1145 1146 opt->iov_length = 256; 1147 opt->iov_count = 1024; 1148 opt->rate = 2; 1149 err = test_exec(cgrp, opt); 1150 if (err) 1151 goto out; 1152 1153 opt->rate = 100; 1154 opt->iov_count = 1; 1155 opt->iov_length = 5; 1156 err = test_exec(cgrp, opt); 1157 if (err) 1158 goto out; 1159 out: 1160 sched_yield(); 1161 return err; 1162 } 1163 1164 static int test_mixed(int cgrp) 1165 { 1166 struct sockmap_options opt = {0}; 1167 int err; 1168 1169 txmsg_pass = txmsg_noisy = txmsg_redir_noisy = txmsg_drop = 0; 1170 txmsg_apply = txmsg_cork = 0; 1171 txmsg_start = txmsg_end = 0; 1172 /* Test small and large iov_count values with pass/redir/apply/cork */ 1173 txmsg_pass = 1; 1174 txmsg_redir = 0; 1175 txmsg_apply = 1; 1176 txmsg_cork = 0; 1177 err = test_send(&opt, cgrp); 1178 if (err) 1179 goto out; 1180 1181 txmsg_pass = 1; 1182 txmsg_redir = 0; 1183 txmsg_apply = 0; 1184 txmsg_cork = 1; 1185 err = test_send(&opt, cgrp); 1186 if (err) 1187 goto out; 1188 1189 txmsg_pass = 1; 1190 txmsg_redir = 0; 1191 txmsg_apply = 1; 1192 txmsg_cork = 1; 1193 err = test_send(&opt, cgrp); 1194 if (err) 1195 goto out; 1196 1197 txmsg_pass = 1; 1198 txmsg_redir = 0; 1199 txmsg_apply = 1024; 1200 txmsg_cork = 0; 1201 err = test_send(&opt, cgrp); 1202 if (err) 1203 goto out; 1204 1205 txmsg_pass = 1; 1206 txmsg_redir = 0; 1207 txmsg_apply = 0; 1208 txmsg_cork = 1024; 1209 err = test_send(&opt, cgrp); 1210 if (err) 1211 goto out; 1212 1213 txmsg_pass = 1; 1214 txmsg_redir = 0; 1215 txmsg_apply = 1024; 1216 txmsg_cork = 1024; 1217 err = test_send(&opt, cgrp); 1218 if (err) 1219 goto out; 1220 1221 txmsg_pass = 1; 1222 txmsg_redir = 0; 1223 txmsg_cork = 4096; 1224 txmsg_apply = 4096; 1225 err = test_send(&opt, cgrp); 1226 if (err) 1227 goto out; 1228 1229 txmsg_pass = 0; 1230 txmsg_redir = 1; 1231 txmsg_apply = 1; 1232 txmsg_cork = 0; 1233 err = test_send(&opt, cgrp); 1234 if (err) 1235 goto out; 1236 1237 txmsg_pass = 0; 1238 txmsg_redir = 1; 1239 txmsg_apply = 0; 1240 txmsg_cork = 1; 1241 err = test_send(&opt, cgrp); 1242 if (err) 1243 goto out; 1244 1245 txmsg_pass = 0; 1246 txmsg_redir = 1; 1247 txmsg_apply = 1024; 1248 txmsg_cork = 0; 1249 err = test_send(&opt, cgrp); 1250 if (err) 1251 goto out; 1252 1253 txmsg_pass = 0; 1254 txmsg_redir = 1; 1255 txmsg_apply = 0; 1256 txmsg_cork = 1024; 1257 err = test_send(&opt, cgrp); 1258 if (err) 1259 goto out; 1260 1261 txmsg_pass = 0; 1262 txmsg_redir = 1; 1263 txmsg_apply = 1024; 1264 txmsg_cork = 1024; 1265 err = test_send(&opt, cgrp); 1266 if (err) 1267 goto out; 1268 1269 txmsg_pass = 0; 1270 txmsg_redir = 1; 1271 txmsg_cork = 4096; 1272 txmsg_apply = 4096; 1273 err = test_send(&opt, cgrp); 1274 if (err) 1275 goto out; 1276 out: 1277 return err; 1278 } 1279 1280 static int test_start_end(int cgrp) 1281 { 1282 struct sockmap_options opt = {0}; 1283 int err, i; 1284 1285 /* Test basic start/end with lots of iov_count and iov_lengths */ 1286 txmsg_start = 1; 1287 txmsg_end = 2; 1288 err = test_txmsg(cgrp); 1289 if (err) 1290 goto out; 1291 1292 /* Test start/end with cork */ 1293 opt.rate = 16; 1294 opt.iov_count = 1; 1295 opt.iov_length = 100; 1296 txmsg_cork = 1600; 1297 1298 for (i = 99; i <= 1600; i += 500) { 1299 txmsg_start = 0; 1300 txmsg_end = i; 1301 err = test_exec(cgrp, &opt); 1302 if (err) 1303 goto out; 1304 } 1305 1306 /* Test start/end with cork but pull data in middle */ 1307 for (i = 199; i <= 1600; i += 500) { 1308 txmsg_start = 100; 1309 txmsg_end = i; 1310 err = test_exec(cgrp, &opt); 1311 if (err) 1312 goto out; 1313 } 1314 1315 /* Test start/end with cork pulling last sg entry */ 1316 txmsg_start = 1500; 1317 txmsg_end = 1600; 1318 err = test_exec(cgrp, &opt); 1319 if (err) 1320 goto out; 1321 1322 /* Test start/end pull of single byte in last page */ 1323 txmsg_start = 1111; 1324 txmsg_end = 1112; 1325 err = test_exec(cgrp, &opt); 1326 if (err) 1327 goto out; 1328 1329 /* Test start/end with end < start */ 1330 txmsg_start = 1111; 1331 txmsg_end = 0; 1332 err = test_exec(cgrp, &opt); 1333 if (err) 1334 goto out; 1335 1336 /* Test start/end with end > data */ 1337 txmsg_start = 0; 1338 txmsg_end = 1601; 1339 err = test_exec(cgrp, &opt); 1340 if (err) 1341 goto out; 1342 1343 /* Test start/end with start > data */ 1344 txmsg_start = 1601; 1345 txmsg_end = 1600; 1346 err = test_exec(cgrp, &opt); 1347 1348 out: 1349 txmsg_start = 0; 1350 txmsg_end = 0; 1351 sched_yield(); 1352 return err; 1353 } 1354 1355 char *map_names[] = { 1356 "sock_map", 1357 "sock_map_txmsg", 1358 "sock_map_redir", 1359 "sock_apply_bytes", 1360 "sock_cork_bytes", 1361 "sock_pull_bytes", 1362 "sock_redir_flags", 1363 "sock_skb_opts", 1364 }; 1365 1366 int prog_attach_type[] = { 1367 BPF_SK_SKB_STREAM_PARSER, 1368 BPF_SK_SKB_STREAM_VERDICT, 1369 BPF_CGROUP_SOCK_OPS, 1370 BPF_SK_MSG_VERDICT, 1371 BPF_SK_MSG_VERDICT, 1372 BPF_SK_MSG_VERDICT, 1373 BPF_SK_MSG_VERDICT, 1374 BPF_SK_MSG_VERDICT, 1375 BPF_SK_MSG_VERDICT, 1376 BPF_SK_MSG_VERDICT, 1377 }; 1378 1379 int prog_type[] = { 1380 BPF_PROG_TYPE_SK_SKB, 1381 BPF_PROG_TYPE_SK_SKB, 1382 BPF_PROG_TYPE_SOCK_OPS, 1383 BPF_PROG_TYPE_SK_MSG, 1384 BPF_PROG_TYPE_SK_MSG, 1385 BPF_PROG_TYPE_SK_MSG, 1386 BPF_PROG_TYPE_SK_MSG, 1387 BPF_PROG_TYPE_SK_MSG, 1388 BPF_PROG_TYPE_SK_MSG, 1389 BPF_PROG_TYPE_SK_MSG, 1390 }; 1391 1392 static int populate_progs(char *bpf_file) 1393 { 1394 struct bpf_program *prog; 1395 struct bpf_object *obj; 1396 int i = 0; 1397 long err; 1398 1399 obj = bpf_object__open(bpf_file); 1400 err = libbpf_get_error(obj); 1401 if (err) { 1402 char err_buf[256]; 1403 1404 libbpf_strerror(err, err_buf, sizeof(err_buf)); 1405 printf("Unable to load eBPF objects in file '%s' : %s\n", 1406 bpf_file, err_buf); 1407 return -1; 1408 } 1409 1410 bpf_object__for_each_program(prog, obj) { 1411 bpf_program__set_type(prog, prog_type[i]); 1412 bpf_program__set_expected_attach_type(prog, 1413 prog_attach_type[i]); 1414 i++; 1415 } 1416 1417 i = bpf_object__load(obj); 1418 i = 0; 1419 bpf_object__for_each_program(prog, obj) { 1420 prog_fd[i] = bpf_program__fd(prog); 1421 i++; 1422 } 1423 1424 for (i = 0; i < sizeof(map_fd)/sizeof(int); i++) { 1425 maps[i] = bpf_object__find_map_by_name(obj, map_names[i]); 1426 map_fd[i] = bpf_map__fd(maps[i]); 1427 if (map_fd[i] < 0) { 1428 fprintf(stderr, "load_bpf_file: (%i) %s\n", 1429 map_fd[i], strerror(errno)); 1430 return -1; 1431 } 1432 } 1433 1434 return 0; 1435 } 1436 1437 static int __test_suite(int cg_fd, char *bpf_file) 1438 { 1439 int err, cleanup = cg_fd; 1440 1441 err = populate_progs(bpf_file); 1442 if (err < 0) { 1443 fprintf(stderr, "ERROR: (%i) load bpf failed\n", err); 1444 return err; 1445 } 1446 1447 if (cg_fd < 0) { 1448 if (setup_cgroup_environment()) { 1449 fprintf(stderr, "ERROR: cgroup env failed\n"); 1450 return -EINVAL; 1451 } 1452 1453 cg_fd = create_and_get_cgroup(CG_PATH); 1454 if (cg_fd < 0) { 1455 fprintf(stderr, 1456 "ERROR: (%i) open cg path failed: %s\n", 1457 cg_fd, optarg); 1458 return cg_fd; 1459 } 1460 1461 if (join_cgroup(CG_PATH)) { 1462 fprintf(stderr, "ERROR: failed to join cgroup\n"); 1463 return -EINVAL; 1464 } 1465 } 1466 1467 /* Tests basic commands and APIs with range of iov values */ 1468 txmsg_start = txmsg_end = 0; 1469 err = test_txmsg(cg_fd); 1470 if (err) 1471 goto out; 1472 1473 /* Tests interesting combinations of APIs used together */ 1474 err = test_mixed(cg_fd); 1475 if (err) 1476 goto out; 1477 1478 /* Tests pull_data API using start/end API */ 1479 err = test_start_end(cg_fd); 1480 if (err) 1481 goto out; 1482 1483 out: 1484 printf("Summary: %i PASSED %i FAILED\n", passed, failed); 1485 if (cleanup < 0) { 1486 cleanup_cgroup_environment(); 1487 close(cg_fd); 1488 } 1489 return err; 1490 } 1491 1492 static int test_suite(int cg_fd) 1493 { 1494 int err; 1495 1496 err = __test_suite(cg_fd, BPF_SOCKMAP_FILENAME); 1497 if (err) 1498 goto out; 1499 err = __test_suite(cg_fd, BPF_SOCKHASH_FILENAME); 1500 out: 1501 if (cg_fd > -1) 1502 close(cg_fd); 1503 return err; 1504 } 1505 1506 int main(int argc, char **argv) 1507 { 1508 int iov_count = 1, length = 1024, rate = 1; 1509 struct sockmap_options options = {0}; 1510 int opt, longindex, err, cg_fd = 0; 1511 char *bpf_file = BPF_SOCKMAP_FILENAME; 1512 int test = PING_PONG; 1513 1514 if (argc < 2) 1515 return test_suite(-1); 1516 1517 while ((opt = getopt_long(argc, argv, ":dhvc:r:i:l:t:", 1518 long_options, &longindex)) != -1) { 1519 switch (opt) { 1520 case 's': 1521 txmsg_start = atoi(optarg); 1522 break; 1523 case 'e': 1524 txmsg_end = atoi(optarg); 1525 break; 1526 case 'a': 1527 txmsg_apply = atoi(optarg); 1528 break; 1529 case 'k': 1530 txmsg_cork = atoi(optarg); 1531 break; 1532 case 'c': 1533 cg_fd = open(optarg, O_DIRECTORY, O_RDONLY); 1534 if (cg_fd < 0) { 1535 fprintf(stderr, 1536 "ERROR: (%i) open cg path failed: %s\n", 1537 cg_fd, optarg); 1538 return cg_fd; 1539 } 1540 break; 1541 case 'r': 1542 rate = atoi(optarg); 1543 break; 1544 case 'v': 1545 options.verbose = 1; 1546 break; 1547 case 'i': 1548 iov_count = atoi(optarg); 1549 break; 1550 case 'l': 1551 length = atoi(optarg); 1552 break; 1553 case 'd': 1554 options.data_test = true; 1555 break; 1556 case 't': 1557 if (strcmp(optarg, "ping") == 0) { 1558 test = PING_PONG; 1559 } else if (strcmp(optarg, "sendmsg") == 0) { 1560 test = SENDMSG; 1561 } else if (strcmp(optarg, "base") == 0) { 1562 test = BASE; 1563 } else if (strcmp(optarg, "base_sendpage") == 0) { 1564 test = BASE_SENDPAGE; 1565 } else if (strcmp(optarg, "sendpage") == 0) { 1566 test = SENDPAGE; 1567 } else { 1568 usage(argv); 1569 return -1; 1570 } 1571 break; 1572 case 0: 1573 break; 1574 case 'h': 1575 default: 1576 usage(argv); 1577 return -1; 1578 } 1579 } 1580 1581 if (argc <= 3 && cg_fd) 1582 return test_suite(cg_fd); 1583 1584 if (!cg_fd) { 1585 fprintf(stderr, "%s requires cgroup option: --cgroup <path>\n", 1586 argv[0]); 1587 return -1; 1588 } 1589 1590 err = populate_progs(bpf_file); 1591 if (err) { 1592 fprintf(stderr, "populate program: (%s) %s\n", 1593 bpf_file, strerror(errno)); 1594 return 1; 1595 } 1596 running = 1; 1597 1598 /* catch SIGINT */ 1599 signal(SIGINT, running_handler); 1600 1601 options.iov_count = iov_count; 1602 options.iov_length = length; 1603 options.rate = rate; 1604 1605 err = run_options(&options, cg_fd, test); 1606 close(cg_fd); 1607 return err; 1608 } 1609 1610 void running_handler(int a) 1611 { 1612 running = 0; 1613 } 1614