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