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