1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2017 - 2018 Intel Corporation. */
3 
4 #include <errno.h>
5 #include <getopt.h>
6 #include <libgen.h>
7 #include <net/if.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <sys/socket.h>
11 #include <sys/un.h>
12 #include <unistd.h>
13 
14 #include <bpf/bpf.h>
15 #include <bpf/xsk.h>
16 #include "xdpsock.h"
17 
18 static const char *opt_if = "";
19 
20 static struct option long_options[] = {
21 	{"interface", required_argument, 0, 'i'},
22 	{0, 0, 0, 0}
23 };
24 
usage(const char * prog)25 static void usage(const char *prog)
26 {
27 	const char *str =
28 		"  Usage: %s [OPTIONS]\n"
29 		"  Options:\n"
30 		"  -i, --interface=n	Run on interface n\n"
31 		"\n";
32 	fprintf(stderr, "%s\n", str);
33 
34 	exit(0);
35 }
36 
parse_command_line(int argc,char ** argv)37 static void parse_command_line(int argc, char **argv)
38 {
39 	int option_index, c;
40 
41 	opterr = 0;
42 
43 	for (;;) {
44 		c = getopt_long(argc, argv, "i:",
45 				long_options, &option_index);
46 		if (c == -1)
47 			break;
48 
49 		switch (c) {
50 		case 'i':
51 			opt_if = optarg;
52 			break;
53 		default:
54 			usage(basename(argv[0]));
55 		}
56 	}
57 }
58 
send_xsks_map_fd(int sock,int fd)59 static int send_xsks_map_fd(int sock, int fd)
60 {
61 	char cmsgbuf[CMSG_SPACE(sizeof(int))];
62 	struct msghdr msg;
63 	struct iovec iov;
64 	int value = 0;
65 
66 	if (fd == -1) {
67 		fprintf(stderr, "Incorrect fd = %d\n", fd);
68 		return -1;
69 	}
70 	iov.iov_base = &value;
71 	iov.iov_len = sizeof(int);
72 
73 	msg.msg_name = NULL;
74 	msg.msg_namelen = 0;
75 	msg.msg_iov = &iov;
76 	msg.msg_iovlen = 1;
77 	msg.msg_flags = 0;
78 	msg.msg_control = cmsgbuf;
79 	msg.msg_controllen = CMSG_LEN(sizeof(int));
80 
81 	struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
82 
83 	cmsg->cmsg_level = SOL_SOCKET;
84 	cmsg->cmsg_type = SCM_RIGHTS;
85 	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
86 
87 	*(int *)CMSG_DATA(cmsg) = fd;
88 	int ret = sendmsg(sock, &msg, 0);
89 
90 	if (ret == -1) {
91 		fprintf(stderr, "Sendmsg failed with %s", strerror(errno));
92 		return -errno;
93 	}
94 
95 	return ret;
96 }
97 
98 int
main(int argc,char ** argv)99 main(int argc, char **argv)
100 {
101 	struct sockaddr_un server;
102 	int listening = 1;
103 	int rval, msgsock;
104 	int ifindex = 0;
105 	int flag = 1;
106 	int cmd = 0;
107 	int sock;
108 	int err;
109 	int xsks_map_fd;
110 
111 	parse_command_line(argc, argv);
112 
113 	ifindex = if_nametoindex(opt_if);
114 	if (ifindex == 0) {
115 		fprintf(stderr, "Unable to get ifindex for Interface %s. Reason:%s",
116 			opt_if, strerror(errno));
117 		return -errno;
118 	}
119 
120 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
121 	if (sock < 0) {
122 		fprintf(stderr, "Opening socket stream failed: %s", strerror(errno));
123 		return -errno;
124 	}
125 
126 	server.sun_family = AF_UNIX;
127 	strcpy(server.sun_path, SOCKET_NAME);
128 
129 	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int));
130 
131 	if (bind(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_un))) {
132 		fprintf(stderr, "Binding to socket stream failed: %s", strerror(errno));
133 		return -errno;
134 	}
135 
136 	listen(sock, MAX_NUM_OF_CLIENTS);
137 
138 	err = xsk_setup_xdp_prog(ifindex, &xsks_map_fd);
139 	if (err) {
140 		fprintf(stderr, "Setup of xdp program failed\n");
141 		goto close_sock;
142 	}
143 
144 	while (listening) {
145 		msgsock = accept(sock, 0, 0);
146 		if (msgsock == -1) {
147 			fprintf(stderr, "Error accepting connection: %s", strerror(errno));
148 			err = -errno;
149 			goto close_sock;
150 		}
151 		err = send_xsks_map_fd(msgsock, xsks_map_fd);
152 		if (err <= 0) {
153 			fprintf(stderr, "Error %d sending xsks_map_fd\n", err);
154 			goto cleanup;
155 		}
156 		do {
157 			rval = read(msgsock, &cmd, sizeof(int));
158 			if (rval < 0) {
159 				fprintf(stderr, "Error reading stream message");
160 			} else {
161 				if (cmd != CLOSE_CONN)
162 					fprintf(stderr, "Recv unknown cmd = %d\n", cmd);
163 				listening = 0;
164 				break;
165 			}
166 		} while (rval > 0);
167 	}
168 	close(msgsock);
169 	close(sock);
170 	unlink(SOCKET_NAME);
171 
172 	/* Unset fd for given ifindex */
173 	err = bpf_set_link_xdp_fd(ifindex, -1, 0);
174 	if (err) {
175 		fprintf(stderr, "Error when unsetting bpf prog_fd for ifindex(%d)\n", ifindex);
176 		return err;
177 	}
178 
179 	return 0;
180 
181 cleanup:
182 	close(msgsock);
183 close_sock:
184 	close(sock);
185 	unlink(SOCKET_NAME);
186 	return err;
187 }
188