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