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