Merge tag 'armsoc-fixes-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[platform/kernel/linux-rpi.git] / samples / bpf / xdpsock_ctrl_proc.c
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
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
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
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
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 }