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