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