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