bpf: sockmap, code sockmap_test in C
[linux-2.6-block.git] / samples / sockmap / sockmap_user.c
CommitLineData
69e8cc13
JF
1/* Copyright (c) 2017 Covalent IO, Inc. http://covalent.io
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public
5 * License as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * General Public License for more details.
11 */
12#include <stdio.h>
13#include <stdlib.h>
14#include <sys/socket.h>
15#include <sys/ioctl.h>
16#include <sys/select.h>
17#include <netinet/in.h>
18#include <arpa/inet.h>
19#include <unistd.h>
20#include <string.h>
21#include <errno.h>
22#include <sys/ioctl.h>
23#include <stdbool.h>
24#include <signal.h>
25#include <fcntl.h>
d7d6437a 26#include <sys/wait.h>
66fdd1a3 27#include <time.h>
69e8cc13
JF
28
29#include <sys/time.h>
8e0ef380 30#include <sys/resource.h>
69e8cc13 31#include <sys/types.h>
e67463cb 32#include <sys/sendfile.h>
69e8cc13
JF
33
34#include <linux/netlink.h>
35#include <linux/socket.h>
36#include <linux/sock_diag.h>
37#include <linux/bpf.h>
38#include <linux/if_link.h>
39#include <assert.h>
40#include <libgen.h>
41
6627426f
JF
42#include <getopt.h>
43
69e8cc13
JF
44#include "../bpf/bpf_load.h"
45#include "../bpf/bpf_util.h"
46#include "../bpf/libbpf.h"
47
48int running;
49void running_handler(int a);
50
51/* randomly selected ports for testing on lo */
52#define S1_PORT 10000
53#define S2_PORT 10001
54
15f66a91
JF
55#define BPF_FILENAME "sockmap_kern.o"
56
6627426f
JF
57/* global sockets */
58int s1, s2, c1, c2, p1, p2;
59
4c4c3c27
JF
60int txmsg_pass;
61int txmsg_noisy;
62int txmsg_redir;
63int txmsg_redir_noisy;
e6373ce7 64int txmsg_drop;
1c16c312 65int txmsg_apply;
468b3fde 66int txmsg_cork;
0dcbbf67
JF
67int txmsg_start;
68int txmsg_end;
2596f64c 69int txmsg_ingress;
2e3f6c5f 70int txmsg_skb;
4c4c3c27 71
6627426f
JF
72static const struct option long_options[] = {
73 {"help", no_argument, NULL, 'h' },
74 {"cgroup", required_argument, NULL, 'c' },
75 {"rate", required_argument, NULL, 'r' },
76 {"verbose", no_argument, NULL, 'v' },
eaf8c6ee
JF
77 {"iov_count", required_argument, NULL, 'i' },
78 {"length", required_argument, NULL, 'l' },
79 {"test", required_argument, NULL, 't' },
6bce9d2c 80 {"data_test", no_argument, NULL, 'd' },
e67463cb
JF
81 {"txmsg", no_argument, &txmsg_pass, 1 },
82 {"txmsg_noisy", no_argument, &txmsg_noisy, 1 },
83 {"txmsg_redir", no_argument, &txmsg_redir, 1 },
84 {"txmsg_redir_noisy", no_argument, &txmsg_redir_noisy, 1},
e6373ce7 85 {"txmsg_drop", no_argument, &txmsg_drop, 1 },
1c16c312 86 {"txmsg_apply", required_argument, NULL, 'a'},
468b3fde 87 {"txmsg_cork", required_argument, NULL, 'k'},
0dcbbf67
JF
88 {"txmsg_start", required_argument, NULL, 's'},
89 {"txmsg_end", required_argument, NULL, 'e'},
2596f64c 90 {"txmsg_ingress", no_argument, &txmsg_ingress, 1 },
2e3f6c5f 91 {"txmsg_skb", no_argument, &txmsg_skb, 1 },
6627426f
JF
92 {0, 0, NULL, 0 }
93};
94
95static void usage(char *argv[])
69e8cc13 96{
6627426f
JF
97 int i;
98
99 printf(" Usage: %s --cgroup <cgroup_path>\n", argv[0]);
100 printf(" options:\n");
101 for (i = 0; long_options[i].name != 0; i++) {
102 printf(" --%-12s", long_options[i].name);
103 if (long_options[i].flag != NULL)
104 printf(" flag (internal value:%d)\n",
105 *long_options[i].flag);
106 else
107 printf(" -%c\n", long_options[i].val);
108 }
109 printf("\n");
110}
111
112static int sockmap_init_sockets(void)
113{
114 int i, err, one = 1;
69e8cc13 115 struct sockaddr_in addr;
69e8cc13 116 int *fds[4] = {&s1, &s2, &c1, &c2};
69e8cc13
JF
117
118 s1 = s2 = p1 = p2 = c1 = c2 = 0;
119
120 /* Init sockets */
121 for (i = 0; i < 4; i++) {
122 *fds[i] = socket(AF_INET, SOCK_STREAM, 0);
123 if (*fds[i] < 0) {
124 perror("socket s1 failed()");
6627426f 125 return errno;
69e8cc13
JF
126 }
127 }
128
129 /* Allow reuse */
130 for (i = 0; i < 2; i++) {
131 err = setsockopt(*fds[i], SOL_SOCKET, SO_REUSEADDR,
132 (char *)&one, sizeof(one));
133 if (err) {
134 perror("setsockopt failed()");
6627426f 135 return errno;
69e8cc13
JF
136 }
137 }
138
139 /* Non-blocking sockets */
ede15477 140 for (i = 0; i < 2; i++) {
69e8cc13
JF
141 err = ioctl(*fds[i], FIONBIO, (char *)&one);
142 if (err < 0) {
143 perror("ioctl s1 failed()");
6627426f 144 return errno;
69e8cc13
JF
145 }
146 }
147
148 /* Bind server sockets */
149 memset(&addr, 0, sizeof(struct sockaddr_in));
150 addr.sin_family = AF_INET;
151 addr.sin_addr.s_addr = inet_addr("127.0.0.1");
152
153 addr.sin_port = htons(S1_PORT);
154 err = bind(s1, (struct sockaddr *)&addr, sizeof(addr));
155 if (err < 0) {
156 perror("bind s1 failed()\n");
6627426f 157 return errno;
69e8cc13
JF
158 }
159
160 addr.sin_port = htons(S2_PORT);
161 err = bind(s2, (struct sockaddr *)&addr, sizeof(addr));
162 if (err < 0) {
163 perror("bind s2 failed()\n");
6627426f 164 return errno;
69e8cc13
JF
165 }
166
167 /* Listen server sockets */
168 addr.sin_port = htons(S1_PORT);
169 err = listen(s1, 32);
170 if (err < 0) {
171 perror("listen s1 failed()\n");
6627426f 172 return errno;
69e8cc13
JF
173 }
174
175 addr.sin_port = htons(S2_PORT);
176 err = listen(s2, 32);
177 if (err < 0) {
178 perror("listen s1 failed()\n");
6627426f 179 return errno;
69e8cc13
JF
180 }
181
182 /* Initiate Connect */
183 addr.sin_port = htons(S1_PORT);
184 err = connect(c1, (struct sockaddr *)&addr, sizeof(addr));
185 if (err < 0 && errno != EINPROGRESS) {
186 perror("connect c1 failed()\n");
6627426f 187 return errno;
69e8cc13
JF
188 }
189
190 addr.sin_port = htons(S2_PORT);
191 err = connect(c2, (struct sockaddr *)&addr, sizeof(addr));
192 if (err < 0 && errno != EINPROGRESS) {
193 perror("connect c2 failed()\n");
6627426f
JF
194 return errno;
195 } else if (err < 0) {
196 err = 0;
69e8cc13
JF
197 }
198
199 /* Accept Connecrtions */
200 p1 = accept(s1, NULL, NULL);
201 if (p1 < 0) {
202 perror("accept s1 failed()\n");
6627426f 203 return errno;
69e8cc13
JF
204 }
205
206 p2 = accept(s2, NULL, NULL);
207 if (p2 < 0) {
208 perror("accept s1 failed()\n");
6627426f 209 return errno;
69e8cc13
JF
210 }
211
69e8cc13
JF
212 printf("connected sockets: c1 <-> p1, c2 <-> p2\n");
213 printf("cgroups binding: c1(%i) <-> s1(%i) - - - c2(%i) <-> s2(%i)\n",
214 c1, s1, c2, s2);
6627426f
JF
215 return 0;
216}
217
eaf8c6ee
JF
218struct msg_stats {
219 size_t bytes_sent;
220 size_t bytes_recvd;
66fdd1a3
JF
221 struct timespec start;
222 struct timespec end;
eaf8c6ee
JF
223};
224
e6373ce7
JF
225struct sockmap_options {
226 int verbose;
227 bool base;
228 bool sendpage;
229 bool data_test;
230 bool drop_expected;
15f66a91
JF
231 int iov_count;
232 int iov_length;
233 int rate;
e6373ce7
JF
234};
235
e67463cb 236static int msg_loop_sendpage(int fd, int iov_length, int cnt,
e6373ce7
JF
237 struct msg_stats *s,
238 struct sockmap_options *opt)
e67463cb 239{
e6373ce7 240 bool drop = opt->drop_expected;
6bce9d2c 241 unsigned char k = 0;
e67463cb
JF
242 FILE *file;
243 int i, fp;
244
245 file = fopen(".sendpage_tst.tmp", "w+");
6bce9d2c
JF
246 for (i = 0; i < iov_length * cnt; i++, k++)
247 fwrite(&k, sizeof(char), 1, file);
248 fflush(file);
e67463cb 249 fseek(file, 0, SEEK_SET);
6bce9d2c 250 fclose(file);
e67463cb 251
6bce9d2c 252 fp = open(".sendpage_tst.tmp", O_RDONLY);
e67463cb
JF
253 clock_gettime(CLOCK_MONOTONIC, &s->start);
254 for (i = 0; i < cnt; i++) {
6bce9d2c 255 int sent = sendfile(fd, fp, NULL, iov_length);
e67463cb 256
e6373ce7 257 if (!drop && sent < 0) {
e67463cb 258 perror("send loop error:");
6bce9d2c 259 close(fp);
e67463cb 260 return sent;
e6373ce7
JF
261 } else if (drop && sent >= 0) {
262 printf("sendpage loop error expected: %i\n", sent);
263 close(fp);
264 return -EIO;
e67463cb 265 }
e6373ce7
JF
266
267 if (sent > 0)
268 s->bytes_sent += sent;
e67463cb
JF
269 }
270 clock_gettime(CLOCK_MONOTONIC, &s->end);
6bce9d2c 271 close(fp);
e67463cb
JF
272 return 0;
273}
274
eaf8c6ee 275static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
e6373ce7
JF
276 struct msg_stats *s, bool tx,
277 struct sockmap_options *opt)
eaf8c6ee
JF
278{
279 struct msghdr msg = {0};
66fdd1a3 280 int err, i, flags = MSG_NOSIGNAL;
eaf8c6ee 281 struct iovec *iov;
6bce9d2c 282 unsigned char k;
e6373ce7
JF
283 bool data_test = opt->data_test;
284 bool drop = opt->drop_expected;
eaf8c6ee
JF
285
286 iov = calloc(iov_count, sizeof(struct iovec));
287 if (!iov)
288 return errno;
289
6bce9d2c 290 k = 0;
eaf8c6ee 291 for (i = 0; i < iov_count; i++) {
6bce9d2c 292 unsigned char *d = calloc(iov_length, sizeof(char));
eaf8c6ee
JF
293
294 if (!d) {
295 fprintf(stderr, "iov_count %i/%i OOM\n", i, iov_count);
296 goto out_errno;
297 }
298 iov[i].iov_base = d;
299 iov[i].iov_len = iov_length;
6bce9d2c
JF
300
301 if (data_test && tx) {
302 int j;
303
304 for (j = 0; j < iov_length; j++)
305 d[j] = k++;
306 }
eaf8c6ee
JF
307 }
308
309 msg.msg_iov = iov;
310 msg.msg_iovlen = iov_count;
6bce9d2c 311 k = 0;
eaf8c6ee
JF
312
313 if (tx) {
66fdd1a3 314 clock_gettime(CLOCK_MONOTONIC, &s->start);
eaf8c6ee
JF
315 for (i = 0; i < cnt; i++) {
316 int sent = sendmsg(fd, &msg, flags);
317
e6373ce7 318 if (!drop && sent < 0) {
eaf8c6ee
JF
319 perror("send loop error:");
320 goto out_errno;
e6373ce7
JF
321 } else if (drop && sent >= 0) {
322 printf("send loop error expected: %i\n", sent);
323 errno = -EIO;
324 goto out_errno;
eaf8c6ee 325 }
e6373ce7
JF
326 if (sent > 0)
327 s->bytes_sent += sent;
eaf8c6ee 328 }
66fdd1a3 329 clock_gettime(CLOCK_MONOTONIC, &s->end);
eaf8c6ee
JF
330 } else {
331 int slct, recv, max_fd = fd;
332 struct timeval timeout;
333 float total_bytes;
334 fd_set w;
335
336 total_bytes = (float)iov_count * (float)iov_length * (float)cnt;
66fdd1a3
JF
337 err = clock_gettime(CLOCK_MONOTONIC, &s->start);
338 if (err < 0)
339 perror("recv start time: ");
eaf8c6ee
JF
340 while (s->bytes_recvd < total_bytes) {
341 timeout.tv_sec = 1;
342 timeout.tv_usec = 0;
343
344 /* FD sets */
345 FD_ZERO(&w);
346 FD_SET(fd, &w);
347
348 slct = select(max_fd + 1, &w, NULL, NULL, &timeout);
349 if (slct == -1) {
350 perror("select()");
66fdd1a3 351 clock_gettime(CLOCK_MONOTONIC, &s->end);
eaf8c6ee
JF
352 goto out_errno;
353 } else if (!slct) {
354 fprintf(stderr, "unexpected timeout\n");
355 errno = -EIO;
66fdd1a3 356 clock_gettime(CLOCK_MONOTONIC, &s->end);
eaf8c6ee
JF
357 goto out_errno;
358 }
359
360 recv = recvmsg(fd, &msg, flags);
361 if (recv < 0) {
362 if (errno != EWOULDBLOCK) {
66fdd1a3 363 clock_gettime(CLOCK_MONOTONIC, &s->end);
eaf8c6ee
JF
364 perror("recv failed()\n");
365 goto out_errno;
366 }
367 }
368
369 s->bytes_recvd += recv;
6bce9d2c
JF
370
371 if (data_test) {
372 int j;
373
374 for (i = 0; i < msg.msg_iovlen; i++) {
375 unsigned char *d = iov[i].iov_base;
376
377 for (j = 0;
378 j < iov[i].iov_len && recv; j++) {
379 if (d[j] != k++) {
380 errno = -EIO;
381 fprintf(stderr,
382 "detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n",
383 i, j, d[j], k - 1, d[j+1], k + 1);
384 goto out_errno;
385 }
386 recv--;
387 }
388 }
389 }
eaf8c6ee 390 }
66fdd1a3 391 clock_gettime(CLOCK_MONOTONIC, &s->end);
eaf8c6ee
JF
392 }
393
394 for (i = 0; i < iov_count; i++)
395 free(iov[i].iov_base);
396 free(iov);
397 return 0;
398out_errno:
399 for (i = 0; i < iov_count; i++)
400 free(iov[i].iov_base);
401 free(iov);
402 return errno;
403}
404
66fdd1a3
JF
405static float giga = 1000000000;
406
407static inline float sentBps(struct msg_stats s)
408{
409 return s.bytes_sent / (s.end.tv_sec - s.start.tv_sec);
410}
411
412static inline float recvdBps(struct msg_stats s)
413{
414 return s.bytes_recvd / (s.end.tv_sec - s.start.tv_sec);
415}
416
15f66a91 417static int sendmsg_test(struct sockmap_options *opt)
eaf8c6ee 418{
ce5373be
JF
419 float sent_Bps = 0, recvd_Bps = 0;
420 int rx_fd, txpid, rxpid, err = 0;
eaf8c6ee 421 struct msg_stats s = {0};
15f66a91
JF
422 int iov_count = opt->iov_count;
423 int iov_buf = opt->iov_length;
424 int cnt = opt->rate;
d7d6437a
JF
425 int status;
426
427 errno = 0;
428
6bce9d2c 429 if (opt->base)
ce5373be
JF
430 rx_fd = p1;
431 else
432 rx_fd = p2;
433
d7d6437a
JF
434 rxpid = fork();
435 if (rxpid == 0) {
e6373ce7
JF
436 if (opt->drop_expected)
437 exit(1);
438
6bce9d2c 439 if (opt->sendpage)
e67463cb 440 iov_count = 1;
6bce9d2c 441 err = msg_loop(rx_fd, iov_count, iov_buf,
e6373ce7 442 cnt, &s, false, opt);
d7d6437a
JF
443 if (err)
444 fprintf(stderr,
445 "msg_loop_rx: iov_count %i iov_buf %i cnt %i err %i\n",
446 iov_count, iov_buf, cnt, err);
d7d6437a
JF
447 shutdown(p2, SHUT_RDWR);
448 shutdown(p1, SHUT_RDWR);
66fdd1a3
JF
449 if (s.end.tv_sec - s.start.tv_sec) {
450 sent_Bps = sentBps(s);
451 recvd_Bps = recvdBps(s);
452 }
453 fprintf(stdout,
454 "rx_sendmsg: TX: %zuB %fB/s %fGB/s RX: %zuB %fB/s %fGB/s\n",
455 s.bytes_sent, sent_Bps, sent_Bps/giga,
456 s.bytes_recvd, recvd_Bps, recvd_Bps/giga);
d7d6437a
JF
457 exit(1);
458 } else if (rxpid == -1) {
459 perror("msg_loop_rx: ");
460 return errno;
eaf8c6ee
JF
461 }
462
d7d6437a
JF
463 txpid = fork();
464 if (txpid == 0) {
6bce9d2c 465 if (opt->sendpage)
e6373ce7 466 err = msg_loop_sendpage(c1, iov_buf, cnt, &s, opt);
e67463cb 467 else
6bce9d2c 468 err = msg_loop(c1, iov_count, iov_buf,
e6373ce7 469 cnt, &s, true, opt);
e67463cb 470
d7d6437a
JF
471 if (err)
472 fprintf(stderr,
473 "msg_loop_tx: iov_count %i iov_buf %i cnt %i err %i\n",
474 iov_count, iov_buf, cnt, err);
d7d6437a 475 shutdown(c1, SHUT_RDWR);
66fdd1a3
JF
476 if (s.end.tv_sec - s.start.tv_sec) {
477 sent_Bps = sentBps(s);
478 recvd_Bps = recvdBps(s);
479 }
480 fprintf(stdout,
481 "tx_sendmsg: TX: %zuB %fB/s %f GB/s RX: %zuB %fB/s %fGB/s\n",
482 s.bytes_sent, sent_Bps, sent_Bps/giga,
483 s.bytes_recvd, recvd_Bps, recvd_Bps/giga);
d7d6437a
JF
484 exit(1);
485 } else if (txpid == -1) {
486 perror("msg_loop_tx: ");
487 return errno;
488 }
eaf8c6ee 489
d7d6437a
JF
490 assert(waitpid(rxpid, &status, 0) == rxpid);
491 assert(waitpid(txpid, &status, 0) == txpid);
eaf8c6ee
JF
492 return err;
493}
494
6bce9d2c 495static int forever_ping_pong(int rate, struct sockmap_options *opt)
6627426f
JF
496{
497 struct timeval timeout;
498 char buf[1024] = {0};
499 int sc;
500
501 timeout.tv_sec = 10;
502 timeout.tv_usec = 0;
69e8cc13
JF
503
504 /* Ping/Pong data from client to server */
505 sc = send(c1, buf, sizeof(buf), 0);
506 if (sc < 0) {
507 perror("send failed()\n");
6627426f 508 return sc;
69e8cc13
JF
509 }
510
511 do {
6627426f
JF
512 int s, rc, i, max_fd = p2;
513 fd_set w;
69e8cc13
JF
514
515 /* FD sets */
516 FD_ZERO(&w);
517 FD_SET(c1, &w);
518 FD_SET(c2, &w);
519 FD_SET(p1, &w);
520 FD_SET(p2, &w);
521
522 s = select(max_fd + 1, &w, NULL, NULL, &timeout);
523 if (s == -1) {
524 perror("select()");
525 break;
526 } else if (!s) {
527 fprintf(stderr, "unexpected timeout\n");
528 break;
529 }
530
531 for (i = 0; i <= max_fd && s > 0; ++i) {
532 if (!FD_ISSET(i, &w))
533 continue;
534
535 s--;
536
537 rc = recv(i, buf, sizeof(buf), 0);
538 if (rc < 0) {
539 if (errno != EWOULDBLOCK) {
540 perror("recv failed()\n");
6627426f 541 return rc;
69e8cc13
JF
542 }
543 }
544
545 if (rc == 0) {
546 close(i);
547 break;
548 }
549
550 sc = send(i, buf, rc, 0);
551 if (sc < 0) {
552 perror("send failed()\n");
6627426f 553 return sc;
69e8cc13
JF
554 }
555 }
6627426f
JF
556
557 if (rate)
558 sleep(rate);
559
6bce9d2c 560 if (opt->verbose) {
69e8cc13
JF
561 printf(".");
562 fflush(stdout);
563
564 }
565 } while (running);
566
6627426f 567 return 0;
69e8cc13
JF
568}
569
eaf8c6ee
JF
570enum {
571 PING_PONG,
572 SENDMSG,
ce5373be 573 BASE,
e67463cb
JF
574 BASE_SENDPAGE,
575 SENDPAGE,
eaf8c6ee
JF
576};
577
15f66a91 578static int run_options(struct sockmap_options options, int cg_fd, int test)
69e8cc13 579{
15f66a91
JF
580 char *bpf_file = BPF_FILENAME;
581 int err, tx_prog_fd;
69e8cc13 582 char filename[256];
69e8cc13 583
15f66a91 584 if (load_bpf_file(bpf_file)) {
69e8cc13
JF
585 fprintf(stderr, "load_bpf_file: (%s) %s\n",
586 filename, strerror(errno));
587 return 1;
588 }
589
4c4c3c27 590 /* If base test skip BPF setup */
e67463cb 591 if (test == BASE || test == BASE_SENDPAGE)
4c4c3c27
JF
592 goto run;
593
69e8cc13 594 /* Attach programs to sockmap */
464bc0fd
JF
595 err = bpf_prog_attach(prog_fd[0], map_fd[0],
596 BPF_SK_SKB_STREAM_PARSER, 0);
597 if (err) {
598 fprintf(stderr, "ERROR: bpf_prog_attach (sockmap): %d (%s)\n",
599 err, strerror(errno));
600 return err;
601 }
602
603 err = bpf_prog_attach(prog_fd[1], map_fd[0],
604 BPF_SK_SKB_STREAM_VERDICT, 0);
69e8cc13
JF
605 if (err) {
606 fprintf(stderr, "ERROR: bpf_prog_attach (sockmap): %d (%s)\n",
607 err, strerror(errno));
608 return err;
609 }
610
611 /* Attach to cgroups */
612 err = bpf_prog_attach(prog_fd[2], cg_fd, BPF_CGROUP_SOCK_OPS, 0);
613 if (err) {
614 fprintf(stderr, "ERROR: bpf_prog_attach (groups): %d (%s)\n",
615 err, strerror(errno));
616 return err;
617 }
618
ce5373be 619run:
6627426f 620 err = sockmap_init_sockets();
69e8cc13
JF
621 if (err) {
622 fprintf(stderr, "ERROR: test socket failed: %d\n", err);
6627426f 623 goto out;
69e8cc13 624 }
6627426f 625
4c4c3c27
JF
626 /* Attach txmsg program to sockmap */
627 if (txmsg_pass)
628 tx_prog_fd = prog_fd[3];
629 else if (txmsg_noisy)
630 tx_prog_fd = prog_fd[4];
631 else if (txmsg_redir)
632 tx_prog_fd = prog_fd[5];
633 else if (txmsg_redir_noisy)
634 tx_prog_fd = prog_fd[6];
e6373ce7
JF
635 else if (txmsg_drop)
636 tx_prog_fd = prog_fd[9];
637 /* apply and cork must be last */
1c16c312
JF
638 else if (txmsg_apply)
639 tx_prog_fd = prog_fd[7];
468b3fde
JF
640 else if (txmsg_cork)
641 tx_prog_fd = prog_fd[8];
4c4c3c27
JF
642 else
643 tx_prog_fd = 0;
644
645 if (tx_prog_fd) {
646 int redir_fd, i = 0;
647
648 err = bpf_prog_attach(tx_prog_fd,
649 map_fd[1], BPF_SK_MSG_VERDICT, 0);
650 if (err) {
651 fprintf(stderr,
652 "ERROR: bpf_prog_attach (txmsg): %d (%s)\n",
653 err, strerror(errno));
654 return err;
655 }
656
657 err = bpf_map_update_elem(map_fd[1], &i, &c1, BPF_ANY);
658 if (err) {
659 fprintf(stderr,
660 "ERROR: bpf_map_update_elem (txmsg): %d (%s\n",
661 err, strerror(errno));
662 return err;
663 }
e6373ce7 664
e67463cb 665 if (txmsg_redir || txmsg_redir_noisy)
4c4c3c27
JF
666 redir_fd = c2;
667 else
668 redir_fd = c1;
669
670 err = bpf_map_update_elem(map_fd[2], &i, &redir_fd, BPF_ANY);
671 if (err) {
672 fprintf(stderr,
673 "ERROR: bpf_map_update_elem (txmsg): %d (%s\n",
674 err, strerror(errno));
675 return err;
676 }
1c16c312
JF
677
678 if (txmsg_apply) {
679 err = bpf_map_update_elem(map_fd[3],
680 &i, &txmsg_apply, BPF_ANY);
681 if (err) {
682 fprintf(stderr,
683 "ERROR: bpf_map_update_elem (apply_bytes): %d (%s\n",
684 err, strerror(errno));
685 return err;
686 }
687 }
468b3fde
JF
688
689 if (txmsg_cork) {
690 err = bpf_map_update_elem(map_fd[4],
691 &i, &txmsg_cork, BPF_ANY);
692 if (err) {
693 fprintf(stderr,
694 "ERROR: bpf_map_update_elem (cork_bytes): %d (%s\n",
695 err, strerror(errno));
696 return err;
697 }
698 }
699
0dcbbf67
JF
700 if (txmsg_start) {
701 err = bpf_map_update_elem(map_fd[5],
702 &i, &txmsg_start, BPF_ANY);
703 if (err) {
704 fprintf(stderr,
705 "ERROR: bpf_map_update_elem (txmsg_start): %d (%s)\n",
706 err, strerror(errno));
707 return err;
708 }
709 }
710
711 if (txmsg_end) {
712 i = 1;
713 err = bpf_map_update_elem(map_fd[5],
714 &i, &txmsg_end, BPF_ANY);
715 if (err) {
716 fprintf(stderr,
717 "ERROR: bpf_map_update_elem (txmsg_end): %d (%s)\n",
718 err, strerror(errno));
719 return err;
720 }
721 }
2596f64c
JF
722
723 if (txmsg_ingress) {
724 int in = BPF_F_INGRESS;
725
726 i = 0;
727 err = bpf_map_update_elem(map_fd[6], &i, &in, BPF_ANY);
728 if (err) {
729 fprintf(stderr,
730 "ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n",
731 err, strerror(errno));
732 }
733 i = 1;
734 err = bpf_map_update_elem(map_fd[1], &i, &p1, BPF_ANY);
735 if (err) {
736 fprintf(stderr,
737 "ERROR: bpf_map_update_elem (p1 txmsg): %d (%s)\n",
738 err, strerror(errno));
739 }
740 err = bpf_map_update_elem(map_fd[2], &i, &p1, BPF_ANY);
741 if (err) {
742 fprintf(stderr,
743 "ERROR: bpf_map_update_elem (p1 redir): %d (%s)\n",
744 err, strerror(errno));
745 }
746
747 i = 2;
748 err = bpf_map_update_elem(map_fd[2], &i, &p2, BPF_ANY);
749 if (err) {
750 fprintf(stderr,
751 "ERROR: bpf_map_update_elem (p2 txmsg): %d (%s)\n",
752 err, strerror(errno));
753 }
754 }
2e3f6c5f
JF
755
756 if (txmsg_skb) {
757 int skb_fd = (test == SENDMSG || test == SENDPAGE) ? p2 : p1;
758 int ingress = BPF_F_INGRESS;
759
760 i = 0;
761 err = bpf_map_update_elem(map_fd[7], &i, &ingress, BPF_ANY);
762 if (err) {
763 fprintf(stderr,
764 "ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n",
765 err, strerror(errno));
766 }
767
768 i = 3;
769 err = bpf_map_update_elem(map_fd[0], &i, &skb_fd, BPF_ANY);
770 if (err) {
771 fprintf(stderr,
772 "ERROR: bpf_map_update_elem (c1 sockmap): %d (%s)\n",
773 err, strerror(errno));
774 }
775 }
4c4c3c27 776 }
e6373ce7
JF
777
778 if (txmsg_drop)
779 options.drop_expected = true;
780
eaf8c6ee 781 if (test == PING_PONG)
15f66a91 782 err = forever_ping_pong(options.rate, &options);
6bce9d2c
JF
783 else if (test == SENDMSG) {
784 options.base = false;
785 options.sendpage = false;
15f66a91 786 err = sendmsg_test(&options);
6bce9d2c
JF
787 } else if (test == SENDPAGE) {
788 options.base = false;
789 options.sendpage = true;
15f66a91 790 err = sendmsg_test(&options);
6bce9d2c
JF
791 } else if (test == BASE) {
792 options.base = true;
793 options.sendpage = false;
15f66a91 794 err = sendmsg_test(&options);
6bce9d2c
JF
795 } else if (test == BASE_SENDPAGE) {
796 options.base = true;
797 options.sendpage = true;
15f66a91 798 err = sendmsg_test(&options);
6bce9d2c 799 } else
eaf8c6ee 800 fprintf(stderr, "unknown test\n");
6627426f 801out:
444890c3 802 bpf_prog_detach2(prog_fd[2], cg_fd, BPF_CGROUP_SOCK_OPS);
6627426f
JF
803 close(s1);
804 close(s2);
805 close(p1);
806 close(p2);
807 close(c1);
808 close(c2);
809 close(cg_fd);
810 return err;
69e8cc13
JF
811}
812
15f66a91
JF
813int main(int argc, char **argv)
814{
815 struct rlimit r = {10 * 1024 * 1024, RLIM_INFINITY};
816 int iov_count = 1, length = 1024, rate = 1;
817 struct sockmap_options options = {0};
818 int opt, longindex, cg_fd = 0;
819 int test = PING_PONG;
820
821 while ((opt = getopt_long(argc, argv, ":dhvc:r:i:l:t:",
822 long_options, &longindex)) != -1) {
823 switch (opt) {
824 case 's':
825 txmsg_start = atoi(optarg);
826 break;
827 case 'e':
828 txmsg_end = atoi(optarg);
829 break;
830 case 'a':
831 txmsg_apply = atoi(optarg);
832 break;
833 case 'k':
834 txmsg_cork = atoi(optarg);
835 break;
836 case 'c':
837 cg_fd = open(optarg, O_DIRECTORY, O_RDONLY);
838 if (cg_fd < 0) {
839 fprintf(stderr,
840 "ERROR: (%i) open cg path failed: %s\n",
841 cg_fd, optarg);
842 return cg_fd;
843 }
844 break;
845 case 'r':
846 rate = atoi(optarg);
847 break;
848 case 'v':
849 options.verbose = 1;
850 break;
851 case 'i':
852 iov_count = atoi(optarg);
853 break;
854 case 'l':
855 length = atoi(optarg);
856 break;
857 case 'd':
858 options.data_test = true;
859 break;
860 case 't':
861 if (strcmp(optarg, "ping") == 0) {
862 test = PING_PONG;
863 } else if (strcmp(optarg, "sendmsg") == 0) {
864 test = SENDMSG;
865 } else if (strcmp(optarg, "base") == 0) {
866 test = BASE;
867 } else if (strcmp(optarg, "base_sendpage") == 0) {
868 test = BASE_SENDPAGE;
869 } else if (strcmp(optarg, "sendpage") == 0) {
870 test = SENDPAGE;
871 } else {
872 usage(argv);
873 return -1;
874 }
875 break;
876 case 0:
877 break;
878 case 'h':
879 default:
880 usage(argv);
881 return -1;
882 }
883 }
884
885 if (!cg_fd) {
886 fprintf(stderr, "%s requires cgroup option: --cgroup <path>\n",
887 argv[0]);
888 return -1;
889 }
890
891 if (setrlimit(RLIMIT_MEMLOCK, &r)) {
892 perror("setrlimit(RLIMIT_MEMLOCK)");
893 return 1;
894 }
895
896 running = 1;
897
898 /* catch SIGINT */
899 signal(SIGINT, running_handler);
900
901 options.iov_count = iov_count;
902 options.iov_length = length;
903 options.rate = rate;
904
905 return run_options(options, cg_fd, test);
906}
907
69e8cc13
JF
908void running_handler(int a)
909{
910 running = 0;
911}