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