]> Git Repo - J-linux.git/blob - tools/testing/selftests/bpf/test_sockmap.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / tools / testing / selftests / bpf / test_sockmap.c
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
41 int running;
42 static 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 */
62 int s1, s2, c1, c2, p1, p2;
63 int test_cnt;
64 int passed;
65 int failed;
66 int map_fd[9];
67 struct bpf_map *maps[9];
68 struct bpf_program *progs[9];
69 struct bpf_link *links[9];
70
71 int txmsg_pass;
72 int txmsg_redir;
73 int txmsg_drop;
74 int txmsg_apply;
75 int txmsg_cork;
76 int txmsg_start;
77 int txmsg_end;
78 int txmsg_start_push;
79 int txmsg_end_push;
80 int txmsg_start_pop;
81 int txmsg_pop;
82 int txmsg_ingress;
83 int txmsg_redir_skb;
84 int txmsg_ktls_skb;
85 int txmsg_ktls_skb_drop;
86 int txmsg_ktls_skb_redir;
87 int ktls;
88 int peek_flag;
89 int skb_use_parser;
90 int txmsg_omit_skb_parser;
91 int verify_push_start;
92 int verify_push_len;
93 int verify_pop_start;
94 int verify_pop_len;
95
96 static 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
126 struct 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
139 struct test_env env;
140
141 struct 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
158 struct _test {
159         char *title;
160         void (*tester)(int cg_fd, struct sockmap_options *opt);
161 };
162
163 static void test_start(void)
164 {
165         env.subtest_num++;
166 }
167
168 static void test_fail(void)
169 {
170         env.fail_cnt++;
171 }
172
173 static void test_pass(void)
174 {
175         env.succ_cnt++;
176 }
177
178 static 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
191 static 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
203 static 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
218 static void test_print_results(void)
219 {
220         fprintf(stdout, "Pass: %d Fail: %d\n",
221                 env.succ_cnt, env.fail_cnt);
222 }
223
224 static 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
241 char *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
259 static 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 }
306 static 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
414 struct msg_stats {
415         size_t bytes_sent;
416         size_t bytes_recvd;
417         struct timespec start;
418         struct timespec end;
419 };
420
421 static 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
470 static 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
481 static 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;
515 unwind_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 */
522 static 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
549 static 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;
577 revisit_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
629 static 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;
817 out_errno:
818         msg_free_iov(&msg);
819         msg_free_iov(&msg_peek);
820         return errno;
821 }
822
823 static float giga = 1000000000;
824
825 static inline float sentBps(struct msg_stats s)
826 {
827         return s.bytes_sent / (s.end.tv_sec - s.start.tv_sec);
828 }
829
830 static inline float recvdBps(struct msg_stats s)
831 {
832         return s.bytes_recvd / (s.end.tv_sec - s.start.tv_sec);
833 }
834
835 static 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         }
961 out:
962         return err;
963 }
964
965 static 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
1040 enum {
1041         SELFTESTS,
1042         PING_PONG,
1043         SENDMSG,
1044         BASE,
1045         BASE_SENDPAGE,
1046         SENDPAGE,
1047 };
1048
1049 static 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
1104 run:
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");
1374 out:
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
1401 static 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
1412 static 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
1423 static 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
1468 static 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
1501 static 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
1519 static 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
1538 static 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
1551 static 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
1559 static 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
1567 static 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
1574 static void test_txmsg_redir(int cgrp, struct sockmap_options *opt)
1575 {
1576         txmsg_redir = 1;
1577         test_send(opt, cgrp);
1578 }
1579
1580 static 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
1592 static void test_txmsg_drop(int cgrp, struct sockmap_options *opt)
1593 {
1594         txmsg_drop = 1;
1595         test_send(opt, cgrp);
1596 }
1597
1598 static 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
1605 static 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  */
1663 static 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
1684 static 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
1719 static 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
1763 static 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
1800 static 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
1847 static 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
1892 static 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
1907 static 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
1919 static 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
1932 char *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
1944 static 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
1985 struct _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
2003 static 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
2026 static 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
2049 static 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
2076 static 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
2082 static 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
2088 static 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
2097 static 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
2106 int 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);
2233 out:
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
2244 void running_handler(int a)
2245 {
2246         running = 0;
2247 }
This page took 0.161922 seconds and 4 git commands to generate.