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