0001
0002
0003 #include <stdio.h>
0004 #include <stdlib.h>
0005 #include <sys/socket.h>
0006 #include <sys/ioctl.h>
0007 #include <sys/select.h>
0008 #include <netinet/in.h>
0009 #include <arpa/inet.h>
0010 #include <unistd.h>
0011 #include <string.h>
0012 #include <errno.h>
0013 #include <stdbool.h>
0014 #include <signal.h>
0015 #include <fcntl.h>
0016 #include <sys/wait.h>
0017 #include <time.h>
0018 #include <sched.h>
0019
0020 #include <sys/time.h>
0021 #include <sys/types.h>
0022 #include <sys/sendfile.h>
0023
0024 #include <linux/netlink.h>
0025 #include <linux/socket.h>
0026 #include <linux/sock_diag.h>
0027 #include <linux/bpf.h>
0028 #include <linux/if_link.h>
0029 #include <linux/tls.h>
0030 #include <assert.h>
0031 #include <libgen.h>
0032
0033 #include <getopt.h>
0034
0035 #include <bpf/bpf.h>
0036 #include <bpf/libbpf.h>
0037
0038 #include "bpf_util.h"
0039 #include "cgroup_helpers.h"
0040
0041 int running;
0042 static void running_handler(int a);
0043
0044 #ifndef TCP_ULP
0045 # define TCP_ULP 31
0046 #endif
0047 #ifndef SOL_TLS
0048 # define SOL_TLS 282
0049 #endif
0050
0051
0052 #define S1_PORT 10000
0053 #define S2_PORT 10001
0054
0055 #define BPF_SOCKMAP_FILENAME "test_sockmap_kern.o"
0056 #define BPF_SOCKHASH_FILENAME "test_sockhash_kern.o"
0057 #define CG_PATH "/sockmap"
0058
0059
0060 int s1, s2, c1, c2, p1, p2;
0061 int test_cnt;
0062 int passed;
0063 int failed;
0064 int map_fd[9];
0065 struct bpf_map *maps[9];
0066 int prog_fd[11];
0067
0068 int txmsg_pass;
0069 int txmsg_redir;
0070 int txmsg_drop;
0071 int txmsg_apply;
0072 int txmsg_cork;
0073 int txmsg_start;
0074 int txmsg_end;
0075 int txmsg_start_push;
0076 int txmsg_end_push;
0077 int txmsg_start_pop;
0078 int txmsg_pop;
0079 int txmsg_ingress;
0080 int txmsg_redir_skb;
0081 int txmsg_ktls_skb;
0082 int txmsg_ktls_skb_drop;
0083 int txmsg_ktls_skb_redir;
0084 int ktls;
0085 int peek_flag;
0086 int skb_use_parser;
0087 int txmsg_omit_skb_parser;
0088
0089 static const struct option long_options[] = {
0090 {"help", no_argument, NULL, 'h' },
0091 {"cgroup", required_argument, NULL, 'c' },
0092 {"rate", required_argument, NULL, 'r' },
0093 {"verbose", optional_argument, NULL, 'v' },
0094 {"iov_count", required_argument, NULL, 'i' },
0095 {"length", required_argument, NULL, 'l' },
0096 {"test", required_argument, NULL, 't' },
0097 {"data_test", no_argument, NULL, 'd' },
0098 {"txmsg", no_argument, &txmsg_pass, 1 },
0099 {"txmsg_redir", no_argument, &txmsg_redir, 1 },
0100 {"txmsg_drop", no_argument, &txmsg_drop, 1 },
0101 {"txmsg_apply", required_argument, NULL, 'a'},
0102 {"txmsg_cork", required_argument, NULL, 'k'},
0103 {"txmsg_start", required_argument, NULL, 's'},
0104 {"txmsg_end", required_argument, NULL, 'e'},
0105 {"txmsg_start_push", required_argument, NULL, 'p'},
0106 {"txmsg_end_push", required_argument, NULL, 'q'},
0107 {"txmsg_start_pop", required_argument, NULL, 'w'},
0108 {"txmsg_pop", required_argument, NULL, 'x'},
0109 {"txmsg_ingress", no_argument, &txmsg_ingress, 1 },
0110 {"txmsg_redir_skb", no_argument, &txmsg_redir_skb, 1 },
0111 {"ktls", no_argument, &ktls, 1 },
0112 {"peek", no_argument, &peek_flag, 1 },
0113 {"txmsg_omit_skb_parser", no_argument, &txmsg_omit_skb_parser, 1},
0114 {"whitelist", required_argument, NULL, 'n' },
0115 {"blacklist", required_argument, NULL, 'b' },
0116 {0, 0, NULL, 0 }
0117 };
0118
0119 struct test_env {
0120 const char *type;
0121 const char *subtest;
0122 const char *prepend;
0123
0124 int test_num;
0125 int subtest_num;
0126
0127 int succ_cnt;
0128 int fail_cnt;
0129 int fail_last;
0130 };
0131
0132 struct test_env env;
0133
0134 struct sockmap_options {
0135 int verbose;
0136 bool base;
0137 bool sendpage;
0138 bool data_test;
0139 bool drop_expected;
0140 bool check_recved_len;
0141 int iov_count;
0142 int iov_length;
0143 int rate;
0144 char *map;
0145 char *whitelist;
0146 char *blacklist;
0147 char *prepend;
0148 };
0149
0150 struct _test {
0151 char *title;
0152 void (*tester)(int cg_fd, struct sockmap_options *opt);
0153 };
0154
0155 static void test_start(void)
0156 {
0157 env.subtest_num++;
0158 }
0159
0160 static void test_fail(void)
0161 {
0162 env.fail_cnt++;
0163 }
0164
0165 static void test_pass(void)
0166 {
0167 env.succ_cnt++;
0168 }
0169
0170 static void test_reset(void)
0171 {
0172 txmsg_start = txmsg_end = 0;
0173 txmsg_start_pop = txmsg_pop = 0;
0174 txmsg_start_push = txmsg_end_push = 0;
0175 txmsg_pass = txmsg_drop = txmsg_redir = 0;
0176 txmsg_apply = txmsg_cork = 0;
0177 txmsg_ingress = txmsg_redir_skb = 0;
0178 txmsg_ktls_skb = txmsg_ktls_skb_drop = txmsg_ktls_skb_redir = 0;
0179 txmsg_omit_skb_parser = 0;
0180 skb_use_parser = 0;
0181 }
0182
0183 static int test_start_subtest(const struct _test *t, struct sockmap_options *o)
0184 {
0185 env.type = o->map;
0186 env.subtest = t->title;
0187 env.prepend = o->prepend;
0188 env.test_num++;
0189 env.subtest_num = 0;
0190 env.fail_last = env.fail_cnt;
0191 test_reset();
0192 return 0;
0193 }
0194
0195 static void test_end_subtest(void)
0196 {
0197 int error = env.fail_cnt - env.fail_last;
0198 int type = strcmp(env.type, BPF_SOCKMAP_FILENAME);
0199
0200 if (!error)
0201 test_pass();
0202
0203 fprintf(stdout, "#%2d/%2d %8s:%s:%s:%s\n",
0204 env.test_num, env.subtest_num,
0205 !type ? "sockmap" : "sockhash",
0206 env.prepend ? : "",
0207 env.subtest, error ? "FAIL" : "OK");
0208 }
0209
0210 static void test_print_results(void)
0211 {
0212 fprintf(stdout, "Pass: %d Fail: %d\n",
0213 env.succ_cnt, env.fail_cnt);
0214 }
0215
0216 static void usage(char *argv[])
0217 {
0218 int i;
0219
0220 printf(" Usage: %s --cgroup <cgroup_path>\n", argv[0]);
0221 printf(" options:\n");
0222 for (i = 0; long_options[i].name != 0; i++) {
0223 printf(" --%-12s", long_options[i].name);
0224 if (long_options[i].flag != NULL)
0225 printf(" flag (internal value:%d)\n",
0226 *long_options[i].flag);
0227 else
0228 printf(" -%c\n", long_options[i].val);
0229 }
0230 printf("\n");
0231 }
0232
0233 char *sock_to_string(int s)
0234 {
0235 if (s == c1)
0236 return "client1";
0237 else if (s == c2)
0238 return "client2";
0239 else if (s == s1)
0240 return "server1";
0241 else if (s == s2)
0242 return "server2";
0243 else if (s == p1)
0244 return "peer1";
0245 else if (s == p2)
0246 return "peer2";
0247 else
0248 return "unknown";
0249 }
0250
0251 static int sockmap_init_ktls(int verbose, int s)
0252 {
0253 struct tls12_crypto_info_aes_gcm_128 tls_tx = {
0254 .info = {
0255 .version = TLS_1_2_VERSION,
0256 .cipher_type = TLS_CIPHER_AES_GCM_128,
0257 },
0258 };
0259 struct tls12_crypto_info_aes_gcm_128 tls_rx = {
0260 .info = {
0261 .version = TLS_1_2_VERSION,
0262 .cipher_type = TLS_CIPHER_AES_GCM_128,
0263 },
0264 };
0265 int so_buf = 6553500;
0266 int err;
0267
0268 err = setsockopt(s, 6, TCP_ULP, "tls", sizeof("tls"));
0269 if (err) {
0270 fprintf(stderr, "setsockopt: TCP_ULP(%s) failed with error %i\n", sock_to_string(s), err);
0271 return -EINVAL;
0272 }
0273 err = setsockopt(s, SOL_TLS, TLS_TX, (void *)&tls_tx, sizeof(tls_tx));
0274 if (err) {
0275 fprintf(stderr, "setsockopt: TLS_TX(%s) failed with error %i\n", sock_to_string(s), err);
0276 return -EINVAL;
0277 }
0278 err = setsockopt(s, SOL_TLS, TLS_RX, (void *)&tls_rx, sizeof(tls_rx));
0279 if (err) {
0280 fprintf(stderr, "setsockopt: TLS_RX(%s) failed with error %i\n", sock_to_string(s), err);
0281 return -EINVAL;
0282 }
0283 err = setsockopt(s, SOL_SOCKET, SO_SNDBUF, &so_buf, sizeof(so_buf));
0284 if (err) {
0285 fprintf(stderr, "setsockopt: (%s) failed sndbuf with error %i\n", sock_to_string(s), err);
0286 return -EINVAL;
0287 }
0288 err = setsockopt(s, SOL_SOCKET, SO_RCVBUF, &so_buf, sizeof(so_buf));
0289 if (err) {
0290 fprintf(stderr, "setsockopt: (%s) failed rcvbuf with error %i\n", sock_to_string(s), err);
0291 return -EINVAL;
0292 }
0293
0294 if (verbose)
0295 fprintf(stdout, "socket(%s) kTLS enabled\n", sock_to_string(s));
0296 return 0;
0297 }
0298 static int sockmap_init_sockets(int verbose)
0299 {
0300 int i, err, one = 1;
0301 struct sockaddr_in addr;
0302 int *fds[4] = {&s1, &s2, &c1, &c2};
0303
0304 s1 = s2 = p1 = p2 = c1 = c2 = 0;
0305
0306
0307 for (i = 0; i < 4; i++) {
0308 *fds[i] = socket(AF_INET, SOCK_STREAM, 0);
0309 if (*fds[i] < 0) {
0310 perror("socket s1 failed()");
0311 return errno;
0312 }
0313 }
0314
0315
0316 for (i = 0; i < 2; i++) {
0317 err = setsockopt(*fds[i], SOL_SOCKET, SO_REUSEADDR,
0318 (char *)&one, sizeof(one));
0319 if (err) {
0320 perror("setsockopt failed()");
0321 return errno;
0322 }
0323 }
0324
0325
0326 for (i = 0; i < 2; i++) {
0327 err = ioctl(*fds[i], FIONBIO, (char *)&one);
0328 if (err < 0) {
0329 perror("ioctl s1 failed()");
0330 return errno;
0331 }
0332 }
0333
0334
0335 memset(&addr, 0, sizeof(struct sockaddr_in));
0336 addr.sin_family = AF_INET;
0337 addr.sin_addr.s_addr = inet_addr("127.0.0.1");
0338
0339 addr.sin_port = htons(S1_PORT);
0340 err = bind(s1, (struct sockaddr *)&addr, sizeof(addr));
0341 if (err < 0) {
0342 perror("bind s1 failed()");
0343 return errno;
0344 }
0345
0346 addr.sin_port = htons(S2_PORT);
0347 err = bind(s2, (struct sockaddr *)&addr, sizeof(addr));
0348 if (err < 0) {
0349 perror("bind s2 failed()");
0350 return errno;
0351 }
0352
0353
0354 addr.sin_port = htons(S1_PORT);
0355 err = listen(s1, 32);
0356 if (err < 0) {
0357 perror("listen s1 failed()");
0358 return errno;
0359 }
0360
0361 addr.sin_port = htons(S2_PORT);
0362 err = listen(s2, 32);
0363 if (err < 0) {
0364 perror("listen s1 failed()");
0365 return errno;
0366 }
0367
0368
0369 addr.sin_port = htons(S1_PORT);
0370 err = connect(c1, (struct sockaddr *)&addr, sizeof(addr));
0371 if (err < 0 && errno != EINPROGRESS) {
0372 perror("connect c1 failed()");
0373 return errno;
0374 }
0375
0376 addr.sin_port = htons(S2_PORT);
0377 err = connect(c2, (struct sockaddr *)&addr, sizeof(addr));
0378 if (err < 0 && errno != EINPROGRESS) {
0379 perror("connect c2 failed()");
0380 return errno;
0381 } else if (err < 0) {
0382 err = 0;
0383 }
0384
0385
0386 p1 = accept(s1, NULL, NULL);
0387 if (p1 < 0) {
0388 perror("accept s1 failed()");
0389 return errno;
0390 }
0391
0392 p2 = accept(s2, NULL, NULL);
0393 if (p2 < 0) {
0394 perror("accept s1 failed()");
0395 return errno;
0396 }
0397
0398 if (verbose > 1) {
0399 printf("connected sockets: c1 <-> p1, c2 <-> p2\n");
0400 printf("cgroups binding: c1(%i) <-> s1(%i) - - - c2(%i) <-> s2(%i)\n",
0401 c1, s1, c2, s2);
0402 }
0403 return 0;
0404 }
0405
0406 struct msg_stats {
0407 size_t bytes_sent;
0408 size_t bytes_recvd;
0409 struct timespec start;
0410 struct timespec end;
0411 };
0412
0413 static int msg_loop_sendpage(int fd, int iov_length, int cnt,
0414 struct msg_stats *s,
0415 struct sockmap_options *opt)
0416 {
0417 bool drop = opt->drop_expected;
0418 unsigned char k = 0;
0419 FILE *file;
0420 int i, fp;
0421
0422 file = tmpfile();
0423 if (!file) {
0424 perror("create file for sendpage");
0425 return 1;
0426 }
0427 for (i = 0; i < iov_length * cnt; i++, k++)
0428 fwrite(&k, sizeof(char), 1, file);
0429 fflush(file);
0430 fseek(file, 0, SEEK_SET);
0431
0432 fp = fileno(file);
0433
0434 clock_gettime(CLOCK_MONOTONIC, &s->start);
0435 for (i = 0; i < cnt; i++) {
0436 int sent;
0437
0438 errno = 0;
0439 sent = sendfile(fd, fp, NULL, iov_length);
0440
0441 if (!drop && sent < 0) {
0442 perror("sendpage loop error");
0443 fclose(file);
0444 return sent;
0445 } else if (drop && sent >= 0) {
0446 printf("sendpage loop error expected: %i errno %i\n",
0447 sent, errno);
0448 fclose(file);
0449 return -EIO;
0450 }
0451
0452 if (sent > 0)
0453 s->bytes_sent += sent;
0454 }
0455 clock_gettime(CLOCK_MONOTONIC, &s->end);
0456 fclose(file);
0457 return 0;
0458 }
0459
0460 static void msg_free_iov(struct msghdr *msg)
0461 {
0462 int i;
0463
0464 for (i = 0; i < msg->msg_iovlen; i++)
0465 free(msg->msg_iov[i].iov_base);
0466 free(msg->msg_iov);
0467 msg->msg_iov = NULL;
0468 msg->msg_iovlen = 0;
0469 }
0470
0471 static int msg_alloc_iov(struct msghdr *msg,
0472 int iov_count, int iov_length,
0473 bool data, bool xmit)
0474 {
0475 unsigned char k = 0;
0476 struct iovec *iov;
0477 int i;
0478
0479 iov = calloc(iov_count, sizeof(struct iovec));
0480 if (!iov)
0481 return errno;
0482
0483 for (i = 0; i < iov_count; i++) {
0484 unsigned char *d = calloc(iov_length, sizeof(char));
0485
0486 if (!d) {
0487 fprintf(stderr, "iov_count %i/%i OOM\n", i, iov_count);
0488 goto unwind_iov;
0489 }
0490 iov[i].iov_base = d;
0491 iov[i].iov_len = iov_length;
0492
0493 if (data && xmit) {
0494 int j;
0495
0496 for (j = 0; j < iov_length; j++)
0497 d[j] = k++;
0498 }
0499 }
0500
0501 msg->msg_iov = iov;
0502 msg->msg_iovlen = iov_count;
0503
0504 return 0;
0505 unwind_iov:
0506 for (i--; i >= 0 ; i--)
0507 free(msg->msg_iov[i].iov_base);
0508 return -ENOMEM;
0509 }
0510
0511 static int msg_verify_data(struct msghdr *msg, int size, int chunk_sz)
0512 {
0513 int i, j = 0, bytes_cnt = 0;
0514 unsigned char k = 0;
0515
0516 for (i = 0; i < msg->msg_iovlen; i++) {
0517 unsigned char *d = msg->msg_iov[i].iov_base;
0518
0519
0520 if (i == 0 && txmsg_ktls_skb) {
0521 if (msg->msg_iov[i].iov_len < 4)
0522 return -EIO;
0523 if (memcmp(d, "PASS", 4) != 0) {
0524 fprintf(stderr,
0525 "detected skb data error with skb ingress update @iov[%i]:%i \"%02x %02x %02x %02x\" != \"PASS\"\n",
0526 i, 0, d[0], d[1], d[2], d[3]);
0527 return -EIO;
0528 }
0529 j = 4;
0530 }
0531
0532 for (; j < msg->msg_iov[i].iov_len && size; j++) {
0533 if (d[j] != k++) {
0534 fprintf(stderr,
0535 "detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n",
0536 i, j, d[j], k - 1, d[j+1], k);
0537 return -EIO;
0538 }
0539 bytes_cnt++;
0540 if (bytes_cnt == chunk_sz) {
0541 k = 0;
0542 bytes_cnt = 0;
0543 }
0544 size--;
0545 }
0546 }
0547 return 0;
0548 }
0549
0550 static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
0551 struct msg_stats *s, bool tx,
0552 struct sockmap_options *opt)
0553 {
0554 struct msghdr msg = {0}, msg_peek = {0};
0555 int err, i, flags = MSG_NOSIGNAL;
0556 bool drop = opt->drop_expected;
0557 bool data = opt->data_test;
0558 int iov_alloc_length = iov_length;
0559
0560 if (!tx && opt->check_recved_len)
0561 iov_alloc_length *= 2;
0562
0563 err = msg_alloc_iov(&msg, iov_count, iov_alloc_length, data, tx);
0564 if (err)
0565 goto out_errno;
0566 if (peek_flag) {
0567 err = msg_alloc_iov(&msg_peek, iov_count, iov_length, data, tx);
0568 if (err)
0569 goto out_errno;
0570 }
0571
0572 if (tx) {
0573 clock_gettime(CLOCK_MONOTONIC, &s->start);
0574 for (i = 0; i < cnt; i++) {
0575 int sent;
0576
0577 errno = 0;
0578 sent = sendmsg(fd, &msg, flags);
0579
0580 if (!drop && sent < 0) {
0581 perror("sendmsg loop error");
0582 goto out_errno;
0583 } else if (drop && sent >= 0) {
0584 fprintf(stderr,
0585 "sendmsg loop error expected: %i errno %i\n",
0586 sent, errno);
0587 errno = -EIO;
0588 goto out_errno;
0589 }
0590 if (sent > 0)
0591 s->bytes_sent += sent;
0592 }
0593 clock_gettime(CLOCK_MONOTONIC, &s->end);
0594 } else {
0595 int slct, recvp = 0, recv, max_fd = fd;
0596 float total_bytes, txmsg_pop_total;
0597 int fd_flags = O_NONBLOCK;
0598 struct timeval timeout;
0599 fd_set w;
0600
0601 fcntl(fd, fd_flags);
0602
0603
0604
0605
0606
0607
0608
0609
0610
0611
0612 total_bytes = (float)iov_count * (float)iov_length * (float)cnt;
0613 if (txmsg_apply)
0614 txmsg_pop_total = txmsg_pop * (total_bytes / txmsg_apply);
0615 else
0616 txmsg_pop_total = txmsg_pop * cnt;
0617 total_bytes -= txmsg_pop_total;
0618 err = clock_gettime(CLOCK_MONOTONIC, &s->start);
0619 if (err < 0)
0620 perror("recv start time");
0621 while (s->bytes_recvd < total_bytes) {
0622 if (txmsg_cork) {
0623 timeout.tv_sec = 0;
0624 timeout.tv_usec = 300000;
0625 } else {
0626 timeout.tv_sec = 3;
0627 timeout.tv_usec = 0;
0628 }
0629
0630
0631 FD_ZERO(&w);
0632 FD_SET(fd, &w);
0633
0634 slct = select(max_fd + 1, &w, NULL, NULL, &timeout);
0635 if (slct == -1) {
0636 perror("select()");
0637 clock_gettime(CLOCK_MONOTONIC, &s->end);
0638 goto out_errno;
0639 } else if (!slct) {
0640 if (opt->verbose)
0641 fprintf(stderr, "unexpected timeout: recved %zu/%f pop_total %f\n", s->bytes_recvd, total_bytes, txmsg_pop_total);
0642 errno = -EIO;
0643 clock_gettime(CLOCK_MONOTONIC, &s->end);
0644 goto out_errno;
0645 }
0646
0647 errno = 0;
0648 if (peek_flag) {
0649 flags |= MSG_PEEK;
0650 recvp = recvmsg(fd, &msg_peek, flags);
0651 if (recvp < 0) {
0652 if (errno != EWOULDBLOCK) {
0653 clock_gettime(CLOCK_MONOTONIC, &s->end);
0654 goto out_errno;
0655 }
0656 }
0657 flags = 0;
0658 }
0659
0660 recv = recvmsg(fd, &msg, flags);
0661 if (recv < 0) {
0662 if (errno != EWOULDBLOCK) {
0663 clock_gettime(CLOCK_MONOTONIC, &s->end);
0664 perror("recv failed()");
0665 goto out_errno;
0666 }
0667 }
0668
0669 s->bytes_recvd += recv;
0670
0671 if (opt->check_recved_len && s->bytes_recvd > total_bytes) {
0672 errno = EMSGSIZE;
0673 fprintf(stderr, "recv failed(), bytes_recvd:%zd, total_bytes:%f\n",
0674 s->bytes_recvd, total_bytes);
0675 goto out_errno;
0676 }
0677
0678 if (data) {
0679 int chunk_sz = opt->sendpage ?
0680 iov_length * cnt :
0681 iov_length * iov_count;
0682
0683 errno = msg_verify_data(&msg, recv, chunk_sz);
0684 if (errno) {
0685 perror("data verify msg failed");
0686 goto out_errno;
0687 }
0688 if (recvp) {
0689 errno = msg_verify_data(&msg_peek,
0690 recvp,
0691 chunk_sz);
0692 if (errno) {
0693 perror("data verify msg_peek failed");
0694 goto out_errno;
0695 }
0696 }
0697 }
0698 }
0699 clock_gettime(CLOCK_MONOTONIC, &s->end);
0700 }
0701
0702 msg_free_iov(&msg);
0703 msg_free_iov(&msg_peek);
0704 return err;
0705 out_errno:
0706 msg_free_iov(&msg);
0707 msg_free_iov(&msg_peek);
0708 return errno;
0709 }
0710
0711 static float giga = 1000000000;
0712
0713 static inline float sentBps(struct msg_stats s)
0714 {
0715 return s.bytes_sent / (s.end.tv_sec - s.start.tv_sec);
0716 }
0717
0718 static inline float recvdBps(struct msg_stats s)
0719 {
0720 return s.bytes_recvd / (s.end.tv_sec - s.start.tv_sec);
0721 }
0722
0723 static int sendmsg_test(struct sockmap_options *opt)
0724 {
0725 float sent_Bps = 0, recvd_Bps = 0;
0726 int rx_fd, txpid, rxpid, err = 0;
0727 struct msg_stats s = {0};
0728 int iov_count = opt->iov_count;
0729 int iov_buf = opt->iov_length;
0730 int rx_status, tx_status;
0731 int cnt = opt->rate;
0732
0733 errno = 0;
0734
0735 if (opt->base)
0736 rx_fd = p1;
0737 else
0738 rx_fd = p2;
0739
0740 if (ktls) {
0741
0742
0743
0744
0745 if (!txmsg_redir || txmsg_ingress) {
0746 err = sockmap_init_ktls(opt->verbose, rx_fd);
0747 if (err)
0748 return err;
0749 }
0750 err = sockmap_init_ktls(opt->verbose, c1);
0751 if (err)
0752 return err;
0753 }
0754
0755 rxpid = fork();
0756 if (rxpid == 0) {
0757 if (txmsg_pop || txmsg_start_pop)
0758 iov_buf -= (txmsg_pop - txmsg_start_pop + 1);
0759 if (opt->drop_expected || txmsg_ktls_skb_drop)
0760 _exit(0);
0761
0762 if (!iov_buf)
0763 _exit(0);
0764
0765 if (opt->sendpage)
0766 iov_count = 1;
0767 err = msg_loop(rx_fd, iov_count, iov_buf,
0768 cnt, &s, false, opt);
0769 if (opt->verbose > 1)
0770 fprintf(stderr,
0771 "msg_loop_rx: iov_count %i iov_buf %i cnt %i err %i\n",
0772 iov_count, iov_buf, cnt, err);
0773 if (s.end.tv_sec - s.start.tv_sec) {
0774 sent_Bps = sentBps(s);
0775 recvd_Bps = recvdBps(s);
0776 }
0777 if (opt->verbose > 1)
0778 fprintf(stdout,
0779 "rx_sendmsg: TX: %zuB %fB/s %fGB/s RX: %zuB %fB/s %fGB/s %s\n",
0780 s.bytes_sent, sent_Bps, sent_Bps/giga,
0781 s.bytes_recvd, recvd_Bps, recvd_Bps/giga,
0782 peek_flag ? "(peek_msg)" : "");
0783 if (err && txmsg_cork)
0784 err = 0;
0785 exit(err ? 1 : 0);
0786 } else if (rxpid == -1) {
0787 perror("msg_loop_rx");
0788 return errno;
0789 }
0790
0791 txpid = fork();
0792 if (txpid == 0) {
0793 if (opt->sendpage)
0794 err = msg_loop_sendpage(c1, iov_buf, cnt, &s, opt);
0795 else
0796 err = msg_loop(c1, iov_count, iov_buf,
0797 cnt, &s, true, opt);
0798
0799 if (err)
0800 fprintf(stderr,
0801 "msg_loop_tx: iov_count %i iov_buf %i cnt %i err %i\n",
0802 iov_count, iov_buf, cnt, err);
0803 if (s.end.tv_sec - s.start.tv_sec) {
0804 sent_Bps = sentBps(s);
0805 recvd_Bps = recvdBps(s);
0806 }
0807 if (opt->verbose > 1)
0808 fprintf(stdout,
0809 "tx_sendmsg: TX: %zuB %fB/s %f GB/s RX: %zuB %fB/s %fGB/s\n",
0810 s.bytes_sent, sent_Bps, sent_Bps/giga,
0811 s.bytes_recvd, recvd_Bps, recvd_Bps/giga);
0812 exit(err ? 1 : 0);
0813 } else if (txpid == -1) {
0814 perror("msg_loop_tx");
0815 return errno;
0816 }
0817
0818 assert(waitpid(rxpid, &rx_status, 0) == rxpid);
0819 assert(waitpid(txpid, &tx_status, 0) == txpid);
0820 if (WIFEXITED(rx_status)) {
0821 err = WEXITSTATUS(rx_status);
0822 if (err) {
0823 fprintf(stderr, "rx thread exited with err %d.\n", err);
0824 goto out;
0825 }
0826 }
0827 if (WIFEXITED(tx_status)) {
0828 err = WEXITSTATUS(tx_status);
0829 if (err)
0830 fprintf(stderr, "tx thread exited with err %d.\n", err);
0831 }
0832 out:
0833 return err;
0834 }
0835
0836 static int forever_ping_pong(int rate, struct sockmap_options *opt)
0837 {
0838 struct timeval timeout;
0839 char buf[1024] = {0};
0840 int sc;
0841
0842 timeout.tv_sec = 10;
0843 timeout.tv_usec = 0;
0844
0845
0846 sc = send(c1, buf, sizeof(buf), 0);
0847 if (sc < 0) {
0848 perror("send failed()");
0849 return sc;
0850 }
0851
0852 do {
0853 int s, rc, i, max_fd = p2;
0854 fd_set w;
0855
0856
0857 FD_ZERO(&w);
0858 FD_SET(c1, &w);
0859 FD_SET(c2, &w);
0860 FD_SET(p1, &w);
0861 FD_SET(p2, &w);
0862
0863 s = select(max_fd + 1, &w, NULL, NULL, &timeout);
0864 if (s == -1) {
0865 perror("select()");
0866 break;
0867 } else if (!s) {
0868 fprintf(stderr, "unexpected timeout\n");
0869 break;
0870 }
0871
0872 for (i = 0; i <= max_fd && s > 0; ++i) {
0873 if (!FD_ISSET(i, &w))
0874 continue;
0875
0876 s--;
0877
0878 rc = recv(i, buf, sizeof(buf), 0);
0879 if (rc < 0) {
0880 if (errno != EWOULDBLOCK) {
0881 perror("recv failed()");
0882 return rc;
0883 }
0884 }
0885
0886 if (rc == 0) {
0887 close(i);
0888 break;
0889 }
0890
0891 sc = send(i, buf, rc, 0);
0892 if (sc < 0) {
0893 perror("send failed()");
0894 return sc;
0895 }
0896 }
0897
0898 if (rate)
0899 sleep(rate);
0900
0901 if (opt->verbose) {
0902 printf(".");
0903 fflush(stdout);
0904
0905 }
0906 } while (running);
0907
0908 return 0;
0909 }
0910
0911 enum {
0912 SELFTESTS,
0913 PING_PONG,
0914 SENDMSG,
0915 BASE,
0916 BASE_SENDPAGE,
0917 SENDPAGE,
0918 };
0919
0920 static int run_options(struct sockmap_options *options, int cg_fd, int test)
0921 {
0922 int i, key, next_key, err, tx_prog_fd = -1, zero = 0;
0923
0924
0925 if (test == BASE || test == BASE_SENDPAGE)
0926 goto run;
0927
0928
0929 if (!txmsg_omit_skb_parser) {
0930 err = bpf_prog_attach(prog_fd[0], map_fd[0],
0931 BPF_SK_SKB_STREAM_PARSER, 0);
0932 if (err) {
0933 fprintf(stderr,
0934 "ERROR: bpf_prog_attach (sockmap %i->%i): %d (%s)\n",
0935 prog_fd[0], map_fd[0], err, strerror(errno));
0936 return err;
0937 }
0938 }
0939
0940 err = bpf_prog_attach(prog_fd[1], map_fd[0],
0941 BPF_SK_SKB_STREAM_VERDICT, 0);
0942 if (err) {
0943 fprintf(stderr, "ERROR: bpf_prog_attach (sockmap): %d (%s)\n",
0944 err, strerror(errno));
0945 return err;
0946 }
0947
0948
0949 if (txmsg_ktls_skb) {
0950 if (!txmsg_omit_skb_parser) {
0951 err = bpf_prog_attach(prog_fd[0], map_fd[8],
0952 BPF_SK_SKB_STREAM_PARSER, 0);
0953 if (err) {
0954 fprintf(stderr,
0955 "ERROR: bpf_prog_attach (TLS sockmap %i->%i): %d (%s)\n",
0956 prog_fd[0], map_fd[8], err, strerror(errno));
0957 return err;
0958 }
0959 }
0960
0961 err = bpf_prog_attach(prog_fd[2], map_fd[8],
0962 BPF_SK_SKB_STREAM_VERDICT, 0);
0963 if (err) {
0964 fprintf(stderr, "ERROR: bpf_prog_attach (TLS sockmap): %d (%s)\n",
0965 err, strerror(errno));
0966 return err;
0967 }
0968 }
0969
0970
0971 err = bpf_prog_attach(prog_fd[3], cg_fd, BPF_CGROUP_SOCK_OPS, 0);
0972 if (err) {
0973 fprintf(stderr, "ERROR: bpf_prog_attach (groups): %d (%s)\n",
0974 err, strerror(errno));
0975 return err;
0976 }
0977
0978 run:
0979 err = sockmap_init_sockets(options->verbose);
0980 if (err) {
0981 fprintf(stderr, "ERROR: test socket failed: %d\n", err);
0982 goto out;
0983 }
0984
0985
0986 if (txmsg_pass)
0987 tx_prog_fd = prog_fd[4];
0988 else if (txmsg_redir)
0989 tx_prog_fd = prog_fd[5];
0990 else if (txmsg_apply)
0991 tx_prog_fd = prog_fd[6];
0992 else if (txmsg_cork)
0993 tx_prog_fd = prog_fd[7];
0994 else if (txmsg_drop)
0995 tx_prog_fd = prog_fd[8];
0996 else
0997 tx_prog_fd = 0;
0998
0999 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");
1247 out:
1248
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
1276 static 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
1287 static 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)
1292 return;
1293
1294 strncat(dst, src, avail - 1);
1295 }
1296
1297 #define OPTSTRING 60
1298 static 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
1343 static 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
1376 static 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
1394 static 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
1413 static 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
1426 static 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
1434 static 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
1442 static void test_txmsg_pass(int cgrp, struct sockmap_options *opt)
1443 {
1444
1445 txmsg_pass = 1;
1446 test_send(opt, cgrp);
1447 }
1448
1449 static void test_txmsg_redir(int cgrp, struct sockmap_options *opt)
1450 {
1451 txmsg_redir = 1;
1452 test_send(opt, cgrp);
1453 }
1454
1455 static void test_txmsg_drop(int cgrp, struct sockmap_options *opt)
1456 {
1457 txmsg_drop = 1;
1458 test_send(opt, cgrp);
1459 }
1460
1461 static 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
1468 static 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
1482
1483
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
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
1520
1521
1522
1523
1524
1525
1526 static 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
1547 static void test_txmsg_pull(int cgrp, struct sockmap_options *opt)
1548 {
1549
1550 txmsg_start = 1;
1551 txmsg_end = 2;
1552 test_send(opt, cgrp);
1553
1554
1555 txmsg_start = 4096;
1556 txmsg_end = 9182;
1557 test_send_large(opt, cgrp);
1558
1559
1560 txmsg_redir = 0;
1561 txmsg_start = 1;
1562 txmsg_end = 2;
1563 test_send(opt, cgrp);
1564
1565
1566 txmsg_redir = 0;
1567 txmsg_cork = 512;
1568 txmsg_start = 1;
1569 txmsg_end = 2;
1570 test_send_many(opt, cgrp);
1571
1572
1573 txmsg_redir = 1;
1574 txmsg_cork = 512;
1575 txmsg_start = 1;
1576 txmsg_end = 2;
1577 test_send_many(opt, cgrp);
1578 }
1579
1580 static void test_txmsg_pop(int cgrp, struct sockmap_options *opt)
1581 {
1582
1583 txmsg_start_pop = 1;
1584 txmsg_pop = 2;
1585 test_send_many(opt, cgrp);
1586
1587
1588 txmsg_start_pop = 4096;
1589 txmsg_pop = 4096;
1590 test_send_large(opt, cgrp);
1591
1592
1593 txmsg_redir = 1;
1594 txmsg_start_pop = 1;
1595 txmsg_pop = 2;
1596 test_send_many(opt, cgrp);
1597
1598
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
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
1613 static void test_txmsg_push(int cgrp, struct sockmap_options *opt)
1614 {
1615
1616 txmsg_start_push = 1;
1617 txmsg_end_push = 1;
1618 test_send(opt, cgrp);
1619
1620
1621 txmsg_start_push = 4096;
1622 txmsg_end_push = 4096;
1623 test_send_large(opt, cgrp);
1624
1625
1626 txmsg_redir = 1;
1627 txmsg_start_push = 1;
1628 txmsg_end_push = 2;
1629 test_send_many(opt, cgrp);
1630
1631
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
1639 static 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
1648 static 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
1675 static 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
1690 static 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
1702 static 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
1715 char *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
1727 int 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
1741 int 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
1755 static 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
1800 struct _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
1817 static 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
1837 static 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
1857 static 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
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
1884 static 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
1890 static 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
1896 static 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
1905 static 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
1915 int 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
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
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);
2042 out:
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
2053 void running_handler(int a)
2054 {
2055 running = 0;
2056 }