xref: /openbmc/linux/tools/testing/selftests/bpf/test_sockmap.c (revision ea47eed33a3fe3d919e6e3cf4e4eb5507b817188)
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 <sys/ioctl.h>
14 #include <stdbool.h>
15 #include <signal.h>
16 #include <fcntl.h>
17 #include <sys/wait.h>
18 #include <time.h>
19 #include <sched.h>
20 
21 #include <sys/time.h>
22 #include <sys/resource.h>
23 #include <sys/types.h>
24 #include <sys/sendfile.h>
25 
26 #include <linux/netlink.h>
27 #include <linux/socket.h>
28 #include <linux/sock_diag.h>
29 #include <linux/bpf.h>
30 #include <linux/if_link.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 /* randomly selected ports for testing on lo */
47 #define S1_PORT 10000
48 #define S2_PORT 10001
49 
50 #define BPF_SOCKMAP_FILENAME "test_sockmap_kern.o"
51 #define BPF_SOCKHASH_FILENAME "test_sockhash_kern.o"
52 #define CG_PATH "/sockmap"
53 
54 /* global sockets */
55 int s1, s2, c1, c2, p1, p2;
56 int test_cnt;
57 int passed;
58 int failed;
59 int map_fd[8];
60 struct bpf_map *maps[8];
61 int prog_fd[11];
62 
63 int txmsg_pass;
64 int txmsg_noisy;
65 int txmsg_redir;
66 int txmsg_redir_noisy;
67 int txmsg_drop;
68 int txmsg_apply;
69 int txmsg_cork;
70 int txmsg_start;
71 int txmsg_end;
72 int txmsg_ingress;
73 int txmsg_skb;
74 
75 static const struct option long_options[] = {
76 	{"help",	no_argument,		NULL, 'h' },
77 	{"cgroup",	required_argument,	NULL, 'c' },
78 	{"rate",	required_argument,	NULL, 'r' },
79 	{"verbose",	no_argument,		NULL, 'v' },
80 	{"iov_count",	required_argument,	NULL, 'i' },
81 	{"length",	required_argument,	NULL, 'l' },
82 	{"test",	required_argument,	NULL, 't' },
83 	{"data_test",   no_argument,		NULL, 'd' },
84 	{"txmsg",		no_argument,	&txmsg_pass,  1  },
85 	{"txmsg_noisy",		no_argument,	&txmsg_noisy, 1  },
86 	{"txmsg_redir",		no_argument,	&txmsg_redir, 1  },
87 	{"txmsg_redir_noisy",	no_argument,	&txmsg_redir_noisy, 1},
88 	{"txmsg_drop",		no_argument,	&txmsg_drop, 1 },
89 	{"txmsg_apply",	required_argument,	NULL, 'a'},
90 	{"txmsg_cork",	required_argument,	NULL, 'k'},
91 	{"txmsg_start", required_argument,	NULL, 's'},
92 	{"txmsg_end",	required_argument,	NULL, 'e'},
93 	{"txmsg_ingress", no_argument,		&txmsg_ingress, 1 },
94 	{"txmsg_skb", no_argument,		&txmsg_skb, 1 },
95 	{0, 0, NULL, 0 }
96 };
97 
98 static void usage(char *argv[])
99 {
100 	int i;
101 
102 	printf(" Usage: %s --cgroup <cgroup_path>\n", argv[0]);
103 	printf(" options:\n");
104 	for (i = 0; long_options[i].name != 0; i++) {
105 		printf(" --%-12s", long_options[i].name);
106 		if (long_options[i].flag != NULL)
107 			printf(" flag (internal value:%d)\n",
108 				*long_options[i].flag);
109 		else
110 			printf(" -%c\n", long_options[i].val);
111 	}
112 	printf("\n");
113 }
114 
115 static int sockmap_init_sockets(int verbose)
116 {
117 	int i, err, one = 1;
118 	struct sockaddr_in addr;
119 	int *fds[4] = {&s1, &s2, &c1, &c2};
120 
121 	s1 = s2 = p1 = p2 = c1 = c2 = 0;
122 
123 	/* Init sockets */
124 	for (i = 0; i < 4; i++) {
125 		*fds[i] = socket(AF_INET, SOCK_STREAM, 0);
126 		if (*fds[i] < 0) {
127 			perror("socket s1 failed()");
128 			return errno;
129 		}
130 	}
131 
132 	/* Allow reuse */
133 	for (i = 0; i < 2; i++) {
134 		err = setsockopt(*fds[i], SOL_SOCKET, SO_REUSEADDR,
135 				 (char *)&one, sizeof(one));
136 		if (err) {
137 			perror("setsockopt failed()");
138 			return errno;
139 		}
140 	}
141 
142 	/* Non-blocking sockets */
143 	for (i = 0; i < 2; i++) {
144 		err = ioctl(*fds[i], FIONBIO, (char *)&one);
145 		if (err < 0) {
146 			perror("ioctl s1 failed()");
147 			return errno;
148 		}
149 	}
150 
151 	/* Bind server sockets */
152 	memset(&addr, 0, sizeof(struct sockaddr_in));
153 	addr.sin_family = AF_INET;
154 	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
155 
156 	addr.sin_port = htons(S1_PORT);
157 	err = bind(s1, (struct sockaddr *)&addr, sizeof(addr));
158 	if (err < 0) {
159 		perror("bind s1 failed()\n");
160 		return errno;
161 	}
162 
163 	addr.sin_port = htons(S2_PORT);
164 	err = bind(s2, (struct sockaddr *)&addr, sizeof(addr));
165 	if (err < 0) {
166 		perror("bind s2 failed()\n");
167 		return errno;
168 	}
169 
170 	/* Listen server sockets */
171 	addr.sin_port = htons(S1_PORT);
172 	err = listen(s1, 32);
173 	if (err < 0) {
174 		perror("listen s1 failed()\n");
175 		return errno;
176 	}
177 
178 	addr.sin_port = htons(S2_PORT);
179 	err = listen(s2, 32);
180 	if (err < 0) {
181 		perror("listen s1 failed()\n");
182 		return errno;
183 	}
184 
185 	/* Initiate Connect */
186 	addr.sin_port = htons(S1_PORT);
187 	err = connect(c1, (struct sockaddr *)&addr, sizeof(addr));
188 	if (err < 0 && errno != EINPROGRESS) {
189 		perror("connect c1 failed()\n");
190 		return errno;
191 	}
192 
193 	addr.sin_port = htons(S2_PORT);
194 	err = connect(c2, (struct sockaddr *)&addr, sizeof(addr));
195 	if (err < 0 && errno != EINPROGRESS) {
196 		perror("connect c2 failed()\n");
197 		return errno;
198 	} else if (err < 0) {
199 		err = 0;
200 	}
201 
202 	/* Accept Connecrtions */
203 	p1 = accept(s1, NULL, NULL);
204 	if (p1 < 0) {
205 		perror("accept s1 failed()\n");
206 		return errno;
207 	}
208 
209 	p2 = accept(s2, NULL, NULL);
210 	if (p2 < 0) {
211 		perror("accept s1 failed()\n");
212 		return errno;
213 	}
214 
215 	if (verbose) {
216 		printf("connected sockets: c1 <-> p1, c2 <-> p2\n");
217 		printf("cgroups binding: c1(%i) <-> s1(%i) - - - c2(%i) <-> s2(%i)\n",
218 			c1, s1, c2, s2);
219 	}
220 	return 0;
221 }
222 
223 struct msg_stats {
224 	size_t bytes_sent;
225 	size_t bytes_recvd;
226 	struct timespec start;
227 	struct timespec end;
228 };
229 
230 struct sockmap_options {
231 	int verbose;
232 	bool base;
233 	bool sendpage;
234 	bool data_test;
235 	bool drop_expected;
236 	int iov_count;
237 	int iov_length;
238 	int rate;
239 };
240 
241 static int msg_loop_sendpage(int fd, int iov_length, int cnt,
242 			     struct msg_stats *s,
243 			     struct sockmap_options *opt)
244 {
245 	bool drop = opt->drop_expected;
246 	unsigned char k = 0;
247 	FILE *file;
248 	int i, fp;
249 
250 	file = fopen(".sendpage_tst.tmp", "w+");
251 	for (i = 0; i < iov_length * cnt; i++, k++)
252 		fwrite(&k, sizeof(char), 1, file);
253 	fflush(file);
254 	fseek(file, 0, SEEK_SET);
255 	fclose(file);
256 
257 	fp = open(".sendpage_tst.tmp", O_RDONLY);
258 	clock_gettime(CLOCK_MONOTONIC, &s->start);
259 	for (i = 0; i < cnt; i++) {
260 		int sent = sendfile(fd, fp, NULL, iov_length);
261 
262 		if (!drop && sent < 0) {
263 			perror("send loop error:");
264 			close(fp);
265 			return sent;
266 		} else if (drop && sent >= 0) {
267 			printf("sendpage loop error expected: %i\n", sent);
268 			close(fp);
269 			return -EIO;
270 		}
271 
272 		if (sent > 0)
273 			s->bytes_sent += sent;
274 	}
275 	clock_gettime(CLOCK_MONOTONIC, &s->end);
276 	close(fp);
277 	return 0;
278 }
279 
280 static int msg_loop(int fd, int iov_count, int iov_length, int cnt,
281 		    struct msg_stats *s, bool tx,
282 		    struct sockmap_options *opt)
283 {
284 	struct msghdr msg = {0};
285 	int err, i, flags = MSG_NOSIGNAL;
286 	struct iovec *iov;
287 	unsigned char k;
288 	bool data_test = opt->data_test;
289 	bool drop = opt->drop_expected;
290 
291 	iov = calloc(iov_count, sizeof(struct iovec));
292 	if (!iov)
293 		return errno;
294 
295 	k = 0;
296 	for (i = 0; i < iov_count; i++) {
297 		unsigned char *d = calloc(iov_length, sizeof(char));
298 
299 		if (!d) {
300 			fprintf(stderr, "iov_count %i/%i OOM\n", i, iov_count);
301 			goto out_errno;
302 		}
303 		iov[i].iov_base = d;
304 		iov[i].iov_len = iov_length;
305 
306 		if (data_test && tx) {
307 			int j;
308 
309 			for (j = 0; j < iov_length; j++)
310 				d[j] = k++;
311 		}
312 	}
313 
314 	msg.msg_iov = iov;
315 	msg.msg_iovlen = iov_count;
316 	k = 0;
317 
318 	if (tx) {
319 		clock_gettime(CLOCK_MONOTONIC, &s->start);
320 		for (i = 0; i < cnt; i++) {
321 			int sent = sendmsg(fd, &msg, flags);
322 
323 			if (!drop && sent < 0) {
324 				perror("send loop error:");
325 				goto out_errno;
326 			} else if (drop && sent >= 0) {
327 				printf("send loop error expected: %i\n", sent);
328 				errno = -EIO;
329 				goto out_errno;
330 			}
331 			if (sent > 0)
332 				s->bytes_sent += sent;
333 		}
334 		clock_gettime(CLOCK_MONOTONIC, &s->end);
335 	} else {
336 		int slct, recv, max_fd = fd;
337 		int fd_flags = O_NONBLOCK;
338 		struct timeval timeout;
339 		float total_bytes;
340 		int bytes_cnt = 0;
341 		int chunk_sz;
342 		fd_set w;
343 
344 		if (opt->sendpage)
345 			chunk_sz = iov_length * cnt;
346 		else
347 			chunk_sz = iov_length * iov_count;
348 
349 		fcntl(fd, fd_flags);
350 		total_bytes = (float)iov_count * (float)iov_length * (float)cnt;
351 		err = clock_gettime(CLOCK_MONOTONIC, &s->start);
352 		if (err < 0)
353 			perror("recv start time: ");
354 		while (s->bytes_recvd < total_bytes) {
355 			if (txmsg_cork) {
356 				timeout.tv_sec = 0;
357 				timeout.tv_usec = 1000;
358 			} else {
359 				timeout.tv_sec = 1;
360 				timeout.tv_usec = 0;
361 			}
362 
363 			/* FD sets */
364 			FD_ZERO(&w);
365 			FD_SET(fd, &w);
366 
367 			slct = select(max_fd + 1, &w, NULL, NULL, &timeout);
368 			if (slct == -1) {
369 				perror("select()");
370 				clock_gettime(CLOCK_MONOTONIC, &s->end);
371 				goto out_errno;
372 			} else if (!slct) {
373 				if (opt->verbose)
374 					fprintf(stderr, "unexpected timeout\n");
375 				errno = -EIO;
376 				clock_gettime(CLOCK_MONOTONIC, &s->end);
377 				goto out_errno;
378 			}
379 
380 			recv = recvmsg(fd, &msg, flags);
381 			if (recv < 0) {
382 				if (errno != EWOULDBLOCK) {
383 					clock_gettime(CLOCK_MONOTONIC, &s->end);
384 					perror("recv failed()\n");
385 					goto out_errno;
386 				}
387 			}
388 
389 			s->bytes_recvd += recv;
390 
391 			if (data_test) {
392 				int j;
393 
394 				for (i = 0; i < msg.msg_iovlen; i++) {
395 					unsigned char *d = iov[i].iov_base;
396 
397 					for (j = 0;
398 					     j < iov[i].iov_len && recv; j++) {
399 						if (d[j] != k++) {
400 							errno = -EIO;
401 							fprintf(stderr,
402 								"detected data corruption @iov[%i]:%i %02x != %02x, %02x ?= %02x\n",
403 								i, j, d[j], k - 1, d[j+1], k);
404 							goto out_errno;
405 						}
406 						bytes_cnt++;
407 						if (bytes_cnt == chunk_sz) {
408 							k = 0;
409 							bytes_cnt = 0;
410 						}
411 						recv--;
412 					}
413 				}
414 			}
415 		}
416 		clock_gettime(CLOCK_MONOTONIC, &s->end);
417 	}
418 
419 	for (i = 0; i < iov_count; i++)
420 		free(iov[i].iov_base);
421 	free(iov);
422 	return 0;
423 out_errno:
424 	for (i = 0; i < iov_count; i++)
425 		free(iov[i].iov_base);
426 	free(iov);
427 	return errno;
428 }
429 
430 static float giga = 1000000000;
431 
432 static inline float sentBps(struct msg_stats s)
433 {
434 	return s.bytes_sent / (s.end.tv_sec - s.start.tv_sec);
435 }
436 
437 static inline float recvdBps(struct msg_stats s)
438 {
439 	return s.bytes_recvd / (s.end.tv_sec - s.start.tv_sec);
440 }
441 
442 static int sendmsg_test(struct sockmap_options *opt)
443 {
444 	float sent_Bps = 0, recvd_Bps = 0;
445 	int rx_fd, txpid, rxpid, err = 0;
446 	struct msg_stats s = {0};
447 	int iov_count = opt->iov_count;
448 	int iov_buf = opt->iov_length;
449 	int rx_status, tx_status;
450 	int cnt = opt->rate;
451 
452 	errno = 0;
453 
454 	if (opt->base)
455 		rx_fd = p1;
456 	else
457 		rx_fd = p2;
458 
459 	rxpid = fork();
460 	if (rxpid == 0) {
461 		if (opt->drop_expected)
462 			exit(0);
463 
464 		if (opt->sendpage)
465 			iov_count = 1;
466 		err = msg_loop(rx_fd, iov_count, iov_buf,
467 			       cnt, &s, false, opt);
468 		if (err && opt->verbose)
469 			fprintf(stderr,
470 				"msg_loop_rx: iov_count %i iov_buf %i cnt %i err %i\n",
471 				iov_count, iov_buf, cnt, err);
472 		shutdown(p2, SHUT_RDWR);
473 		shutdown(p1, SHUT_RDWR);
474 		if (s.end.tv_sec - s.start.tv_sec) {
475 			sent_Bps = sentBps(s);
476 			recvd_Bps = recvdBps(s);
477 		}
478 		if (opt->verbose)
479 			fprintf(stdout,
480 				"rx_sendmsg: TX: %zuB %fB/s %fGB/s RX: %zuB %fB/s %fGB/s\n",
481 				s.bytes_sent, sent_Bps, sent_Bps/giga,
482 				s.bytes_recvd, recvd_Bps, recvd_Bps/giga);
483 		if (err && txmsg_cork)
484 			err = 0;
485 		exit(err ? 1 : 0);
486 	} else if (rxpid == -1) {
487 		perror("msg_loop_rx: ");
488 		return errno;
489 	}
490 
491 	txpid = fork();
492 	if (txpid == 0) {
493 		if (opt->sendpage)
494 			err = msg_loop_sendpage(c1, iov_buf, cnt, &s, opt);
495 		else
496 			err = msg_loop(c1, iov_count, iov_buf,
497 				       cnt, &s, true, opt);
498 
499 		if (err)
500 			fprintf(stderr,
501 				"msg_loop_tx: iov_count %i iov_buf %i cnt %i err %i\n",
502 				iov_count, iov_buf, cnt, err);
503 		shutdown(c1, SHUT_RDWR);
504 		if (s.end.tv_sec - s.start.tv_sec) {
505 			sent_Bps = sentBps(s);
506 			recvd_Bps = recvdBps(s);
507 		}
508 		if (opt->verbose)
509 			fprintf(stdout,
510 				"tx_sendmsg: TX: %zuB %fB/s %f GB/s RX: %zuB %fB/s %fGB/s\n",
511 				s.bytes_sent, sent_Bps, sent_Bps/giga,
512 				s.bytes_recvd, recvd_Bps, recvd_Bps/giga);
513 		exit(err ? 1 : 0);
514 	} else if (txpid == -1) {
515 		perror("msg_loop_tx: ");
516 		return errno;
517 	}
518 
519 	assert(waitpid(rxpid, &rx_status, 0) == rxpid);
520 	assert(waitpid(txpid, &tx_status, 0) == txpid);
521 	if (WIFEXITED(rx_status)) {
522 		err = WEXITSTATUS(rx_status);
523 		if (err) {
524 			fprintf(stderr, "rx thread exited with err %d. ", err);
525 			goto out;
526 		}
527 	}
528 	if (WIFEXITED(tx_status)) {
529 		err = WEXITSTATUS(tx_status);
530 		if (err)
531 			fprintf(stderr, "tx thread exited with err %d. ", err);
532 	}
533 out:
534 	return err;
535 }
536 
537 static int forever_ping_pong(int rate, struct sockmap_options *opt)
538 {
539 	struct timeval timeout;
540 	char buf[1024] = {0};
541 	int sc;
542 
543 	timeout.tv_sec = 10;
544 	timeout.tv_usec = 0;
545 
546 	/* Ping/Pong data from client to server */
547 	sc = send(c1, buf, sizeof(buf), 0);
548 	if (sc < 0) {
549 		perror("send failed()\n");
550 		return sc;
551 	}
552 
553 	do {
554 		int s, rc, i, max_fd = p2;
555 		fd_set w;
556 
557 		/* FD sets */
558 		FD_ZERO(&w);
559 		FD_SET(c1, &w);
560 		FD_SET(c2, &w);
561 		FD_SET(p1, &w);
562 		FD_SET(p2, &w);
563 
564 		s = select(max_fd + 1, &w, NULL, NULL, &timeout);
565 		if (s == -1) {
566 			perror("select()");
567 			break;
568 		} else if (!s) {
569 			fprintf(stderr, "unexpected timeout\n");
570 			break;
571 		}
572 
573 		for (i = 0; i <= max_fd && s > 0; ++i) {
574 			if (!FD_ISSET(i, &w))
575 				continue;
576 
577 			s--;
578 
579 			rc = recv(i, buf, sizeof(buf), 0);
580 			if (rc < 0) {
581 				if (errno != EWOULDBLOCK) {
582 					perror("recv failed()\n");
583 					return rc;
584 				}
585 			}
586 
587 			if (rc == 0) {
588 				close(i);
589 				break;
590 			}
591 
592 			sc = send(i, buf, rc, 0);
593 			if (sc < 0) {
594 				perror("send failed()\n");
595 				return sc;
596 			}
597 		}
598 
599 		if (rate)
600 			sleep(rate);
601 
602 		if (opt->verbose) {
603 			printf(".");
604 			fflush(stdout);
605 
606 		}
607 	} while (running);
608 
609 	return 0;
610 }
611 
612 enum {
613 	PING_PONG,
614 	SENDMSG,
615 	BASE,
616 	BASE_SENDPAGE,
617 	SENDPAGE,
618 };
619 
620 static int run_options(struct sockmap_options *options, int cg_fd,  int test)
621 {
622 	int i, key, next_key, err, tx_prog_fd = -1, zero = 0;
623 
624 	/* If base test skip BPF setup */
625 	if (test == BASE || test == BASE_SENDPAGE)
626 		goto run;
627 
628 	/* Attach programs to sockmap */
629 	err = bpf_prog_attach(prog_fd[0], map_fd[0],
630 				BPF_SK_SKB_STREAM_PARSER, 0);
631 	if (err) {
632 		fprintf(stderr,
633 			"ERROR: bpf_prog_attach (sockmap %i->%i): %d (%s)\n",
634 			prog_fd[0], map_fd[0], err, strerror(errno));
635 		return err;
636 	}
637 
638 	err = bpf_prog_attach(prog_fd[1], map_fd[0],
639 				BPF_SK_SKB_STREAM_VERDICT, 0);
640 	if (err) {
641 		fprintf(stderr, "ERROR: bpf_prog_attach (sockmap): %d (%s)\n",
642 			err, strerror(errno));
643 		return err;
644 	}
645 
646 	/* Attach to cgroups */
647 	err = bpf_prog_attach(prog_fd[2], cg_fd, BPF_CGROUP_SOCK_OPS, 0);
648 	if (err) {
649 		fprintf(stderr, "ERROR: bpf_prog_attach (groups): %d (%s)\n",
650 			err, strerror(errno));
651 		return err;
652 	}
653 
654 run:
655 	err = sockmap_init_sockets(options->verbose);
656 	if (err) {
657 		fprintf(stderr, "ERROR: test socket failed: %d\n", err);
658 		goto out;
659 	}
660 
661 	/* Attach txmsg program to sockmap */
662 	if (txmsg_pass)
663 		tx_prog_fd = prog_fd[3];
664 	else if (txmsg_noisy)
665 		tx_prog_fd = prog_fd[4];
666 	else if (txmsg_redir)
667 		tx_prog_fd = prog_fd[5];
668 	else if (txmsg_redir_noisy)
669 		tx_prog_fd = prog_fd[6];
670 	else if (txmsg_drop)
671 		tx_prog_fd = prog_fd[9];
672 	/* apply and cork must be last */
673 	else if (txmsg_apply)
674 		tx_prog_fd = prog_fd[7];
675 	else if (txmsg_cork)
676 		tx_prog_fd = prog_fd[8];
677 	else
678 		tx_prog_fd = 0;
679 
680 	if (tx_prog_fd) {
681 		int redir_fd, i = 0;
682 
683 		err = bpf_prog_attach(tx_prog_fd,
684 				      map_fd[1], BPF_SK_MSG_VERDICT, 0);
685 		if (err) {
686 			fprintf(stderr,
687 				"ERROR: bpf_prog_attach (txmsg): %d (%s)\n",
688 				err, strerror(errno));
689 			goto out;
690 		}
691 
692 		err = bpf_map_update_elem(map_fd[1], &i, &c1, BPF_ANY);
693 		if (err) {
694 			fprintf(stderr,
695 				"ERROR: bpf_map_update_elem (txmsg):  %d (%s\n",
696 				err, strerror(errno));
697 			goto out;
698 		}
699 
700 		if (txmsg_redir || txmsg_redir_noisy)
701 			redir_fd = c2;
702 		else
703 			redir_fd = c1;
704 
705 		err = bpf_map_update_elem(map_fd[2], &i, &redir_fd, BPF_ANY);
706 		if (err) {
707 			fprintf(stderr,
708 				"ERROR: bpf_map_update_elem (txmsg):  %d (%s\n",
709 				err, strerror(errno));
710 			goto out;
711 		}
712 
713 		if (txmsg_apply) {
714 			err = bpf_map_update_elem(map_fd[3],
715 						  &i, &txmsg_apply, BPF_ANY);
716 			if (err) {
717 				fprintf(stderr,
718 					"ERROR: bpf_map_update_elem (apply_bytes):  %d (%s\n",
719 					err, strerror(errno));
720 				goto out;
721 			}
722 		}
723 
724 		if (txmsg_cork) {
725 			err = bpf_map_update_elem(map_fd[4],
726 						  &i, &txmsg_cork, BPF_ANY);
727 			if (err) {
728 				fprintf(stderr,
729 					"ERROR: bpf_map_update_elem (cork_bytes):  %d (%s\n",
730 					err, strerror(errno));
731 				goto out;
732 			}
733 		}
734 
735 		if (txmsg_start) {
736 			err = bpf_map_update_elem(map_fd[5],
737 						  &i, &txmsg_start, BPF_ANY);
738 			if (err) {
739 				fprintf(stderr,
740 					"ERROR: bpf_map_update_elem (txmsg_start):  %d (%s)\n",
741 					err, strerror(errno));
742 				goto out;
743 			}
744 		}
745 
746 		if (txmsg_end) {
747 			i = 1;
748 			err = bpf_map_update_elem(map_fd[5],
749 						  &i, &txmsg_end, BPF_ANY);
750 			if (err) {
751 				fprintf(stderr,
752 					"ERROR: bpf_map_update_elem (txmsg_end):  %d (%s)\n",
753 					err, strerror(errno));
754 				goto out;
755 			}
756 		}
757 
758 		if (txmsg_ingress) {
759 			int in = BPF_F_INGRESS;
760 
761 			i = 0;
762 			err = bpf_map_update_elem(map_fd[6], &i, &in, BPF_ANY);
763 			if (err) {
764 				fprintf(stderr,
765 					"ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n",
766 					err, strerror(errno));
767 			}
768 			i = 1;
769 			err = bpf_map_update_elem(map_fd[1], &i, &p1, BPF_ANY);
770 			if (err) {
771 				fprintf(stderr,
772 					"ERROR: bpf_map_update_elem (p1 txmsg): %d (%s)\n",
773 					err, strerror(errno));
774 			}
775 			err = bpf_map_update_elem(map_fd[2], &i, &p1, BPF_ANY);
776 			if (err) {
777 				fprintf(stderr,
778 					"ERROR: bpf_map_update_elem (p1 redir): %d (%s)\n",
779 					err, strerror(errno));
780 			}
781 
782 			i = 2;
783 			err = bpf_map_update_elem(map_fd[2], &i, &p2, BPF_ANY);
784 			if (err) {
785 				fprintf(stderr,
786 					"ERROR: bpf_map_update_elem (p2 txmsg): %d (%s)\n",
787 					err, strerror(errno));
788 			}
789 		}
790 
791 		if (txmsg_skb) {
792 			int skb_fd = (test == SENDMSG || test == SENDPAGE) ?
793 					p2 : p1;
794 			int ingress = BPF_F_INGRESS;
795 
796 			i = 0;
797 			err = bpf_map_update_elem(map_fd[7],
798 						  &i, &ingress, BPF_ANY);
799 			if (err) {
800 				fprintf(stderr,
801 					"ERROR: bpf_map_update_elem (txmsg_ingress): %d (%s)\n",
802 					err, strerror(errno));
803 			}
804 
805 			i = 3;
806 			err = bpf_map_update_elem(map_fd[0],
807 						  &i, &skb_fd, BPF_ANY);
808 			if (err) {
809 				fprintf(stderr,
810 					"ERROR: bpf_map_update_elem (c1 sockmap): %d (%s)\n",
811 					err, strerror(errno));
812 			}
813 		}
814 	}
815 
816 	if (txmsg_drop)
817 		options->drop_expected = true;
818 
819 	if (test == PING_PONG)
820 		err = forever_ping_pong(options->rate, options);
821 	else if (test == SENDMSG) {
822 		options->base = false;
823 		options->sendpage = false;
824 		err = sendmsg_test(options);
825 	} else if (test == SENDPAGE) {
826 		options->base = false;
827 		options->sendpage = true;
828 		err = sendmsg_test(options);
829 	} else if (test == BASE) {
830 		options->base = true;
831 		options->sendpage = false;
832 		err = sendmsg_test(options);
833 	} else if (test == BASE_SENDPAGE) {
834 		options->base = true;
835 		options->sendpage = true;
836 		err = sendmsg_test(options);
837 	} else
838 		fprintf(stderr, "unknown test\n");
839 out:
840 	/* Detatch and zero all the maps */
841 	bpf_prog_detach2(prog_fd[2], cg_fd, BPF_CGROUP_SOCK_OPS);
842 	bpf_prog_detach2(prog_fd[0], map_fd[0], BPF_SK_SKB_STREAM_PARSER);
843 	bpf_prog_detach2(prog_fd[1], map_fd[0], BPF_SK_SKB_STREAM_VERDICT);
844 	if (tx_prog_fd >= 0)
845 		bpf_prog_detach2(tx_prog_fd, map_fd[1], BPF_SK_MSG_VERDICT);
846 
847 	for (i = 0; i < 8; i++) {
848 		key = next_key = 0;
849 		bpf_map_update_elem(map_fd[i], &key, &zero, BPF_ANY);
850 		while (bpf_map_get_next_key(map_fd[i], &key, &next_key) == 0) {
851 			bpf_map_update_elem(map_fd[i], &key, &zero, BPF_ANY);
852 			key = next_key;
853 		}
854 	}
855 
856 	close(s1);
857 	close(s2);
858 	close(p1);
859 	close(p2);
860 	close(c1);
861 	close(c2);
862 	return err;
863 }
864 
865 static char *test_to_str(int test)
866 {
867 	switch (test) {
868 	case SENDMSG:
869 		return "sendmsg";
870 	case SENDPAGE:
871 		return "sendpage";
872 	}
873 	return "unknown";
874 }
875 
876 #define OPTSTRING 60
877 static void test_options(char *options)
878 {
879 	char tstr[OPTSTRING];
880 
881 	memset(options, 0, OPTSTRING);
882 
883 	if (txmsg_pass)
884 		strncat(options, "pass,", OPTSTRING);
885 	if (txmsg_noisy)
886 		strncat(options, "pass_noisy,", OPTSTRING);
887 	if (txmsg_redir)
888 		strncat(options, "redir,", OPTSTRING);
889 	if (txmsg_redir_noisy)
890 		strncat(options, "redir_noisy,", OPTSTRING);
891 	if (txmsg_drop)
892 		strncat(options, "drop,", OPTSTRING);
893 	if (txmsg_apply) {
894 		snprintf(tstr, OPTSTRING, "apply %d,", txmsg_apply);
895 		strncat(options, tstr, OPTSTRING);
896 	}
897 	if (txmsg_cork) {
898 		snprintf(tstr, OPTSTRING, "cork %d,", txmsg_cork);
899 		strncat(options, tstr, OPTSTRING);
900 	}
901 	if (txmsg_start) {
902 		snprintf(tstr, OPTSTRING, "start %d,", txmsg_start);
903 		strncat(options, tstr, OPTSTRING);
904 	}
905 	if (txmsg_end) {
906 		snprintf(tstr, OPTSTRING, "end %d,", txmsg_end);
907 		strncat(options, tstr, OPTSTRING);
908 	}
909 	if (txmsg_ingress)
910 		strncat(options, "ingress,", OPTSTRING);
911 	if (txmsg_skb)
912 		strncat(options, "skb,", OPTSTRING);
913 }
914 
915 static int __test_exec(int cgrp, int test, struct sockmap_options *opt)
916 {
917 	char *options = calloc(OPTSTRING, sizeof(char));
918 	int err;
919 
920 	if (test == SENDPAGE)
921 		opt->sendpage = true;
922 	else
923 		opt->sendpage = false;
924 
925 	if (txmsg_drop)
926 		opt->drop_expected = true;
927 	else
928 		opt->drop_expected = false;
929 
930 	test_options(options);
931 
932 	fprintf(stdout,
933 		"[TEST %i]: (%i, %i, %i, %s, %s): ",
934 		test_cnt, opt->rate, opt->iov_count, opt->iov_length,
935 		test_to_str(test), options);
936 	fflush(stdout);
937 	err = run_options(opt, cgrp, test);
938 	fprintf(stdout, "%s\n", !err ? "PASS" : "FAILED");
939 	test_cnt++;
940 	!err ? passed++ : failed++;
941 	free(options);
942 	return err;
943 }
944 
945 static int test_exec(int cgrp, struct sockmap_options *opt)
946 {
947 	int err = __test_exec(cgrp, SENDMSG, opt);
948 
949 	if (err)
950 		goto out;
951 
952 	err = __test_exec(cgrp, SENDPAGE, opt);
953 out:
954 	return err;
955 }
956 
957 static int test_loop(int cgrp)
958 {
959 	struct sockmap_options opt;
960 
961 	int err, i, l, r;
962 
963 	opt.verbose = 0;
964 	opt.base = false;
965 	opt.sendpage = false;
966 	opt.data_test = false;
967 	opt.drop_expected = false;
968 	opt.iov_count = 0;
969 	opt.iov_length = 0;
970 	opt.rate = 0;
971 
972 	r = 1;
973 	for (i = 1; i < 100; i += 33) {
974 		for (l = 1; l < 100; l += 33) {
975 			opt.rate = r;
976 			opt.iov_count = i;
977 			opt.iov_length = l;
978 			err = test_exec(cgrp, &opt);
979 			if (err)
980 				goto out;
981 		}
982 	}
983 	sched_yield();
984 out:
985 	return err;
986 }
987 
988 static int test_txmsg(int cgrp)
989 {
990 	int err;
991 
992 	txmsg_pass = txmsg_noisy = txmsg_redir_noisy = txmsg_drop = 0;
993 	txmsg_apply = txmsg_cork = 0;
994 	txmsg_ingress = txmsg_skb = 0;
995 
996 	txmsg_pass = 1;
997 	err = test_loop(cgrp);
998 	txmsg_pass = 0;
999 	if (err)
1000 		goto out;
1001 
1002 	txmsg_redir = 1;
1003 	err = test_loop(cgrp);
1004 	txmsg_redir = 0;
1005 	if (err)
1006 		goto out;
1007 
1008 	txmsg_drop = 1;
1009 	err = test_loop(cgrp);
1010 	txmsg_drop = 0;
1011 	if (err)
1012 		goto out;
1013 
1014 	txmsg_redir = 1;
1015 	txmsg_ingress = 1;
1016 	err = test_loop(cgrp);
1017 	txmsg_redir = 0;
1018 	txmsg_ingress = 0;
1019 	if (err)
1020 		goto out;
1021 out:
1022 	txmsg_pass = 0;
1023 	txmsg_redir = 0;
1024 	txmsg_drop = 0;
1025 	return err;
1026 }
1027 
1028 static int test_send(struct sockmap_options *opt, int cgrp)
1029 {
1030 	int err;
1031 
1032 	opt->iov_length = 1;
1033 	opt->iov_count = 1;
1034 	opt->rate = 1;
1035 	err = test_exec(cgrp, opt);
1036 	if (err)
1037 		goto out;
1038 
1039 	opt->iov_length = 1;
1040 	opt->iov_count = 1024;
1041 	opt->rate = 1;
1042 	err = test_exec(cgrp, opt);
1043 	if (err)
1044 		goto out;
1045 
1046 	opt->iov_length = 1024;
1047 	opt->iov_count = 1;
1048 	opt->rate = 1;
1049 	err = test_exec(cgrp, opt);
1050 	if (err)
1051 		goto out;
1052 
1053 	opt->iov_length = 1;
1054 	opt->iov_count = 1;
1055 	opt->rate = 512;
1056 	err = test_exec(cgrp, opt);
1057 	if (err)
1058 		goto out;
1059 
1060 	opt->iov_length = 256;
1061 	opt->iov_count = 1024;
1062 	opt->rate = 2;
1063 	err = test_exec(cgrp, opt);
1064 	if (err)
1065 		goto out;
1066 
1067 	opt->rate = 100;
1068 	opt->iov_count = 1;
1069 	opt->iov_length = 5;
1070 	err = test_exec(cgrp, opt);
1071 	if (err)
1072 		goto out;
1073 out:
1074 	sched_yield();
1075 	return err;
1076 }
1077 
1078 static int test_mixed(int cgrp)
1079 {
1080 	struct sockmap_options opt = {0};
1081 	int err;
1082 
1083 	txmsg_pass = txmsg_noisy = txmsg_redir_noisy = txmsg_drop = 0;
1084 	txmsg_apply = txmsg_cork = 0;
1085 	txmsg_start = txmsg_end = 0;
1086 	/* Test small and large iov_count values with pass/redir/apply/cork */
1087 	txmsg_pass = 1;
1088 	txmsg_redir = 0;
1089 	txmsg_apply = 1;
1090 	txmsg_cork = 0;
1091 	err = test_send(&opt, cgrp);
1092 	if (err)
1093 		goto out;
1094 
1095 	txmsg_pass = 1;
1096 	txmsg_redir = 0;
1097 	txmsg_apply = 0;
1098 	txmsg_cork = 1;
1099 	err = test_send(&opt, cgrp);
1100 	if (err)
1101 		goto out;
1102 
1103 	txmsg_pass = 1;
1104 	txmsg_redir = 0;
1105 	txmsg_apply = 1;
1106 	txmsg_cork = 1;
1107 	err = test_send(&opt, cgrp);
1108 	if (err)
1109 		goto out;
1110 
1111 	txmsg_pass = 1;
1112 	txmsg_redir = 0;
1113 	txmsg_apply = 1024;
1114 	txmsg_cork = 0;
1115 	err = test_send(&opt, cgrp);
1116 	if (err)
1117 		goto out;
1118 
1119 	txmsg_pass = 1;
1120 	txmsg_redir = 0;
1121 	txmsg_apply = 0;
1122 	txmsg_cork = 1024;
1123 	err = test_send(&opt, cgrp);
1124 	if (err)
1125 		goto out;
1126 
1127 	txmsg_pass = 1;
1128 	txmsg_redir = 0;
1129 	txmsg_apply = 1024;
1130 	txmsg_cork = 1024;
1131 	err = test_send(&opt, cgrp);
1132 	if (err)
1133 		goto out;
1134 
1135 	txmsg_pass = 1;
1136 	txmsg_redir = 0;
1137 	txmsg_cork = 4096;
1138 	txmsg_apply = 4096;
1139 	err = test_send(&opt, cgrp);
1140 	if (err)
1141 		goto out;
1142 
1143 	txmsg_pass = 0;
1144 	txmsg_redir = 1;
1145 	txmsg_apply = 1;
1146 	txmsg_cork = 0;
1147 	err = test_send(&opt, cgrp);
1148 	if (err)
1149 		goto out;
1150 
1151 	txmsg_pass = 0;
1152 	txmsg_redir = 1;
1153 	txmsg_apply = 0;
1154 	txmsg_cork = 1;
1155 	err = test_send(&opt, cgrp);
1156 	if (err)
1157 		goto out;
1158 
1159 	txmsg_pass = 0;
1160 	txmsg_redir = 1;
1161 	txmsg_apply = 1024;
1162 	txmsg_cork = 0;
1163 	err = test_send(&opt, cgrp);
1164 	if (err)
1165 		goto out;
1166 
1167 	txmsg_pass = 0;
1168 	txmsg_redir = 1;
1169 	txmsg_apply = 0;
1170 	txmsg_cork = 1024;
1171 	err = test_send(&opt, cgrp);
1172 	if (err)
1173 		goto out;
1174 
1175 	txmsg_pass = 0;
1176 	txmsg_redir = 1;
1177 	txmsg_apply = 1024;
1178 	txmsg_cork = 1024;
1179 	err = test_send(&opt, cgrp);
1180 	if (err)
1181 		goto out;
1182 
1183 	txmsg_pass = 0;
1184 	txmsg_redir = 1;
1185 	txmsg_cork = 4096;
1186 	txmsg_apply = 4096;
1187 	err = test_send(&opt, cgrp);
1188 	if (err)
1189 		goto out;
1190 out:
1191 	return err;
1192 }
1193 
1194 static int test_start_end(int cgrp)
1195 {
1196 	struct sockmap_options opt = {0};
1197 	int err, i;
1198 
1199 	/* Test basic start/end with lots of iov_count and iov_lengths */
1200 	txmsg_start = 1;
1201 	txmsg_end = 2;
1202 	err = test_txmsg(cgrp);
1203 	if (err)
1204 		goto out;
1205 
1206 	/* Test start/end with cork */
1207 	opt.rate = 16;
1208 	opt.iov_count = 1;
1209 	opt.iov_length = 100;
1210 	txmsg_cork = 1600;
1211 
1212 	for (i = 99; i <= 1600; i += 500) {
1213 		txmsg_start = 0;
1214 		txmsg_end = i;
1215 		err = test_exec(cgrp, &opt);
1216 		if (err)
1217 			goto out;
1218 	}
1219 
1220 	/* Test start/end with cork but pull data in middle */
1221 	for (i = 199; i <= 1600; i += 500) {
1222 		txmsg_start = 100;
1223 		txmsg_end = i;
1224 		err = test_exec(cgrp, &opt);
1225 		if (err)
1226 			goto out;
1227 	}
1228 
1229 	/* Test start/end with cork pulling last sg entry */
1230 	txmsg_start = 1500;
1231 	txmsg_end = 1600;
1232 	err = test_exec(cgrp, &opt);
1233 	if (err)
1234 		goto out;
1235 
1236 	/* Test start/end pull of single byte in last page */
1237 	txmsg_start = 1111;
1238 	txmsg_end = 1112;
1239 	err = test_exec(cgrp, &opt);
1240 	if (err)
1241 		goto out;
1242 
1243 	/* Test start/end with end < start */
1244 	txmsg_start = 1111;
1245 	txmsg_end = 0;
1246 	err = test_exec(cgrp, &opt);
1247 	if (err)
1248 		goto out;
1249 
1250 	/* Test start/end with end > data */
1251 	txmsg_start = 0;
1252 	txmsg_end = 1601;
1253 	err = test_exec(cgrp, &opt);
1254 	if (err)
1255 		goto out;
1256 
1257 	/* Test start/end with start > data */
1258 	txmsg_start = 1601;
1259 	txmsg_end = 1600;
1260 	err = test_exec(cgrp, &opt);
1261 
1262 out:
1263 	txmsg_start = 0;
1264 	txmsg_end = 0;
1265 	sched_yield();
1266 	return err;
1267 }
1268 
1269 char *map_names[] = {
1270 	"sock_map",
1271 	"sock_map_txmsg",
1272 	"sock_map_redir",
1273 	"sock_apply_bytes",
1274 	"sock_cork_bytes",
1275 	"sock_pull_bytes",
1276 	"sock_redir_flags",
1277 	"sock_skb_opts",
1278 };
1279 
1280 int prog_attach_type[] = {
1281 	BPF_SK_SKB_STREAM_PARSER,
1282 	BPF_SK_SKB_STREAM_VERDICT,
1283 	BPF_CGROUP_SOCK_OPS,
1284 	BPF_SK_MSG_VERDICT,
1285 	BPF_SK_MSG_VERDICT,
1286 	BPF_SK_MSG_VERDICT,
1287 	BPF_SK_MSG_VERDICT,
1288 	BPF_SK_MSG_VERDICT,
1289 	BPF_SK_MSG_VERDICT,
1290 	BPF_SK_MSG_VERDICT,
1291 };
1292 
1293 int prog_type[] = {
1294 	BPF_PROG_TYPE_SK_SKB,
1295 	BPF_PROG_TYPE_SK_SKB,
1296 	BPF_PROG_TYPE_SOCK_OPS,
1297 	BPF_PROG_TYPE_SK_MSG,
1298 	BPF_PROG_TYPE_SK_MSG,
1299 	BPF_PROG_TYPE_SK_MSG,
1300 	BPF_PROG_TYPE_SK_MSG,
1301 	BPF_PROG_TYPE_SK_MSG,
1302 	BPF_PROG_TYPE_SK_MSG,
1303 	BPF_PROG_TYPE_SK_MSG,
1304 };
1305 
1306 static int populate_progs(char *bpf_file)
1307 {
1308 	struct bpf_program *prog;
1309 	struct bpf_object *obj;
1310 	int i = 0;
1311 	long err;
1312 
1313 	obj = bpf_object__open(bpf_file);
1314 	err = libbpf_get_error(obj);
1315 	if (err) {
1316 		char err_buf[256];
1317 
1318 		libbpf_strerror(err, err_buf, sizeof(err_buf));
1319 		printf("Unable to load eBPF objects in file '%s' : %s\n",
1320 		       bpf_file, err_buf);
1321 		return -1;
1322 	}
1323 
1324 	bpf_object__for_each_program(prog, obj) {
1325 		bpf_program__set_type(prog, prog_type[i]);
1326 		bpf_program__set_expected_attach_type(prog,
1327 						      prog_attach_type[i]);
1328 		i++;
1329 	}
1330 
1331 	i = bpf_object__load(obj);
1332 	i = 0;
1333 	bpf_object__for_each_program(prog, obj) {
1334 		prog_fd[i] = bpf_program__fd(prog);
1335 		i++;
1336 	}
1337 
1338 	for (i = 0; i < sizeof(map_fd)/sizeof(int); i++) {
1339 		maps[i] = bpf_object__find_map_by_name(obj, map_names[i]);
1340 		map_fd[i] = bpf_map__fd(maps[i]);
1341 		if (map_fd[i] < 0) {
1342 			fprintf(stderr, "load_bpf_file: (%i) %s\n",
1343 				map_fd[i], strerror(errno));
1344 			return -1;
1345 		}
1346 	}
1347 
1348 	return 0;
1349 }
1350 
1351 static int __test_suite(char *bpf_file)
1352 {
1353 	int cg_fd, err;
1354 
1355 	err = populate_progs(bpf_file);
1356 	if (err < 0) {
1357 		fprintf(stderr, "ERROR: (%i) load bpf failed\n", err);
1358 		return err;
1359 	}
1360 
1361 	if (setup_cgroup_environment()) {
1362 		fprintf(stderr, "ERROR: cgroup env failed\n");
1363 		return -EINVAL;
1364 	}
1365 
1366 	cg_fd = create_and_get_cgroup(CG_PATH);
1367 	if (cg_fd < 0) {
1368 		fprintf(stderr,
1369 			"ERROR: (%i) open cg path failed: %s\n",
1370 			cg_fd, optarg);
1371 		return cg_fd;
1372 	}
1373 
1374 	if (join_cgroup(CG_PATH)) {
1375 		fprintf(stderr, "ERROR: failed to join cgroup\n");
1376 		return -EINVAL;
1377 	}
1378 
1379 	/* Tests basic commands and APIs with range of iov values */
1380 	txmsg_start = txmsg_end = 0;
1381 	err = test_txmsg(cg_fd);
1382 	if (err)
1383 		goto out;
1384 
1385 	/* Tests interesting combinations of APIs used together */
1386 	err = test_mixed(cg_fd);
1387 	if (err)
1388 		goto out;
1389 
1390 	/* Tests pull_data API using start/end API */
1391 	err = test_start_end(cg_fd);
1392 	if (err)
1393 		goto out;
1394 
1395 out:
1396 	printf("Summary: %i PASSED %i FAILED\n", passed, failed);
1397 	cleanup_cgroup_environment();
1398 	close(cg_fd);
1399 	return err;
1400 }
1401 
1402 static int test_suite(void)
1403 {
1404 	int err;
1405 
1406 	err = __test_suite(BPF_SOCKMAP_FILENAME);
1407 	if (err)
1408 		goto out;
1409 	err = __test_suite(BPF_SOCKHASH_FILENAME);
1410 out:
1411 	return err;
1412 }
1413 
1414 int main(int argc, char **argv)
1415 {
1416 	struct rlimit r = {10 * 1024 * 1024, RLIM_INFINITY};
1417 	int iov_count = 1, length = 1024, rate = 1;
1418 	struct sockmap_options options = {0};
1419 	int opt, longindex, err, cg_fd = 0;
1420 	char *bpf_file = BPF_SOCKMAP_FILENAME;
1421 	int test = PING_PONG;
1422 
1423 	if (setrlimit(RLIMIT_MEMLOCK, &r)) {
1424 		perror("setrlimit(RLIMIT_MEMLOCK)");
1425 		return 1;
1426 	}
1427 
1428 	if (argc < 2)
1429 		return test_suite();
1430 
1431 	while ((opt = getopt_long(argc, argv, ":dhvc:r:i:l:t:",
1432 				  long_options, &longindex)) != -1) {
1433 		switch (opt) {
1434 		case 's':
1435 			txmsg_start = atoi(optarg);
1436 			break;
1437 		case 'e':
1438 			txmsg_end = atoi(optarg);
1439 			break;
1440 		case 'a':
1441 			txmsg_apply = atoi(optarg);
1442 			break;
1443 		case 'k':
1444 			txmsg_cork = atoi(optarg);
1445 			break;
1446 		case 'c':
1447 			cg_fd = open(optarg, O_DIRECTORY, O_RDONLY);
1448 			if (cg_fd < 0) {
1449 				fprintf(stderr,
1450 					"ERROR: (%i) open cg path failed: %s\n",
1451 					cg_fd, optarg);
1452 				return cg_fd;
1453 			}
1454 			break;
1455 		case 'r':
1456 			rate = atoi(optarg);
1457 			break;
1458 		case 'v':
1459 			options.verbose = 1;
1460 			break;
1461 		case 'i':
1462 			iov_count = atoi(optarg);
1463 			break;
1464 		case 'l':
1465 			length = atoi(optarg);
1466 			break;
1467 		case 'd':
1468 			options.data_test = true;
1469 			break;
1470 		case 't':
1471 			if (strcmp(optarg, "ping") == 0) {
1472 				test = PING_PONG;
1473 			} else if (strcmp(optarg, "sendmsg") == 0) {
1474 				test = SENDMSG;
1475 			} else if (strcmp(optarg, "base") == 0) {
1476 				test = BASE;
1477 			} else if (strcmp(optarg, "base_sendpage") == 0) {
1478 				test = BASE_SENDPAGE;
1479 			} else if (strcmp(optarg, "sendpage") == 0) {
1480 				test = SENDPAGE;
1481 			} else {
1482 				usage(argv);
1483 				return -1;
1484 			}
1485 			break;
1486 		case 0:
1487 			break;
1488 		case 'h':
1489 		default:
1490 			usage(argv);
1491 			return -1;
1492 		}
1493 	}
1494 
1495 	if (!cg_fd) {
1496 		fprintf(stderr, "%s requires cgroup option: --cgroup <path>\n",
1497 			argv[0]);
1498 		return -1;
1499 	}
1500 
1501 	err = populate_progs(bpf_file);
1502 	if (err) {
1503 		fprintf(stderr, "populate program: (%s) %s\n",
1504 			bpf_file, strerror(errno));
1505 		return 1;
1506 	}
1507 	running = 1;
1508 
1509 	/* catch SIGINT */
1510 	signal(SIGINT, running_handler);
1511 
1512 	options.iov_count = iov_count;
1513 	options.iov_length = length;
1514 	options.rate = rate;
1515 
1516 	err = run_options(&options, cg_fd, test);
1517 	close(cg_fd);
1518 	return err;
1519 }
1520 
1521 void running_handler(int a)
1522 {
1523 	running = 0;
1524 }
1525