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