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