]> Git Repo - linux.git/blob - tools/testing/selftests/bpf/prog_tests/sk_assign.c
selftests/bpf: Store BPF object files with .bpf.o extension
[linux.git] / tools / testing / selftests / bpf / prog_tests / sk_assign.c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2018 Facebook
3 // Copyright (c) 2019 Cloudflare
4 // Copyright (c) 2020 Isovalent, Inc.
5 /*
6  * Test that the socket assign program is able to redirect traffic towards a
7  * socket, regardless of whether the port or address destination of the traffic
8  * matches the port.
9  */
10
11 #define _GNU_SOURCE
12 #include <fcntl.h>
13 #include <signal.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16
17 #include "test_progs.h"
18
19 #define BIND_PORT 1234
20 #define CONNECT_PORT 4321
21 #define TEST_DADDR (0xC0A80203)
22 #define NS_SELF "/proc/self/ns/net"
23 #define SERVER_MAP_PATH "/sys/fs/bpf/tc/globals/server_map"
24
25 static const struct timeval timeo_sec = { .tv_sec = 3 };
26 static const size_t timeo_optlen = sizeof(timeo_sec);
27 static int stop, duration;
28
29 static bool
30 configure_stack(void)
31 {
32         char tc_cmd[BUFSIZ];
33
34         /* Move to a new networking namespace */
35         if (CHECK_FAIL(unshare(CLONE_NEWNET)))
36                 return false;
37
38         /* Configure necessary links, routes */
39         if (CHECK_FAIL(system("ip link set dev lo up")))
40                 return false;
41         if (CHECK_FAIL(system("ip route add local default dev lo")))
42                 return false;
43         if (CHECK_FAIL(system("ip -6 route add local default dev lo")))
44                 return false;
45
46         /* Load qdisc, BPF program */
47         if (CHECK_FAIL(system("tc qdisc add dev lo clsact")))
48                 return false;
49         sprintf(tc_cmd, "%s %s %s %s", "tc filter add dev lo ingress bpf",
50                        "direct-action object-file ./test_sk_assign.bpf.o",
51                        "section tc",
52                        (env.verbosity < VERBOSE_VERY) ? " 2>/dev/null" : "verbose");
53         if (CHECK(system(tc_cmd), "BPF load failed;",
54                   "run with -vv for more info\n"))
55                 return false;
56
57         return true;
58 }
59
60 static int
61 start_server(const struct sockaddr *addr, socklen_t len, int type)
62 {
63         int fd;
64
65         fd = socket(addr->sa_family, type, 0);
66         if (CHECK_FAIL(fd == -1))
67                 goto out;
68         if (CHECK_FAIL(setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeo_sec,
69                                   timeo_optlen)))
70                 goto close_out;
71         if (CHECK_FAIL(bind(fd, addr, len) == -1))
72                 goto close_out;
73         if (type == SOCK_STREAM && CHECK_FAIL(listen(fd, 128) == -1))
74                 goto close_out;
75
76         goto out;
77 close_out:
78         close(fd);
79         fd = -1;
80 out:
81         return fd;
82 }
83
84 static int
85 connect_to_server(const struct sockaddr *addr, socklen_t len, int type)
86 {
87         int fd = -1;
88
89         fd = socket(addr->sa_family, type, 0);
90         if (CHECK_FAIL(fd == -1))
91                 goto out;
92         if (CHECK_FAIL(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo_sec,
93                                   timeo_optlen)))
94                 goto close_out;
95         if (CHECK_FAIL(connect(fd, addr, len)))
96                 goto close_out;
97
98         goto out;
99 close_out:
100         close(fd);
101         fd = -1;
102 out:
103         return fd;
104 }
105
106 static in_port_t
107 get_port(int fd)
108 {
109         struct sockaddr_storage ss;
110         socklen_t slen = sizeof(ss);
111         in_port_t port = 0;
112
113         if (CHECK_FAIL(getsockname(fd, (struct sockaddr *)&ss, &slen)))
114                 return port;
115
116         switch (ss.ss_family) {
117         case AF_INET:
118                 port = ((struct sockaddr_in *)&ss)->sin_port;
119                 break;
120         case AF_INET6:
121                 port = ((struct sockaddr_in6 *)&ss)->sin6_port;
122                 break;
123         default:
124                 CHECK(1, "Invalid address family", "%d\n", ss.ss_family);
125         }
126         return port;
127 }
128
129 static ssize_t
130 rcv_msg(int srv_client, int type)
131 {
132         struct sockaddr_storage ss;
133         char buf[BUFSIZ];
134         socklen_t slen;
135
136         if (type == SOCK_STREAM)
137                 return read(srv_client, &buf, sizeof(buf));
138         else
139                 return recvfrom(srv_client, &buf, sizeof(buf), 0,
140                                 (struct sockaddr *)&ss, &slen);
141 }
142
143 static int
144 run_test(int server_fd, const struct sockaddr *addr, socklen_t len, int type)
145 {
146         int client = -1, srv_client = -1;
147         char buf[] = "testing";
148         in_port_t port;
149         int ret = 1;
150
151         client = connect_to_server(addr, len, type);
152         if (client == -1) {
153                 perror("Cannot connect to server");
154                 goto out;
155         }
156
157         if (type == SOCK_STREAM) {
158                 srv_client = accept(server_fd, NULL, NULL);
159                 if (CHECK_FAIL(srv_client == -1)) {
160                         perror("Can't accept connection");
161                         goto out;
162                 }
163         } else {
164                 srv_client = server_fd;
165         }
166         if (CHECK_FAIL(write(client, buf, sizeof(buf)) != sizeof(buf))) {
167                 perror("Can't write on client");
168                 goto out;
169         }
170         if (CHECK_FAIL(rcv_msg(srv_client, type) != sizeof(buf))) {
171                 perror("Can't read on server");
172                 goto out;
173         }
174
175         port = get_port(srv_client);
176         if (CHECK_FAIL(!port))
177                 goto out;
178         /* SOCK_STREAM is connected via accept(), so the server's local address
179          * will be the CONNECT_PORT rather than the BIND port that corresponds
180          * to the listen socket. SOCK_DGRAM on the other hand is connectionless
181          * so we can't really do the same check there; the server doesn't ever
182          * create a socket with CONNECT_PORT.
183          */
184         if (type == SOCK_STREAM &&
185             CHECK(port != htons(CONNECT_PORT), "Expected", "port %u but got %u",
186                   CONNECT_PORT, ntohs(port)))
187                 goto out;
188         else if (type == SOCK_DGRAM &&
189                  CHECK(port != htons(BIND_PORT), "Expected",
190                        "port %u but got %u", BIND_PORT, ntohs(port)))
191                 goto out;
192
193         ret = 0;
194 out:
195         close(client);
196         if (srv_client != server_fd)
197                 close(srv_client);
198         if (ret)
199                 WRITE_ONCE(stop, 1);
200         return ret;
201 }
202
203 static void
204 prepare_addr(struct sockaddr *addr, int family, __u16 port, bool rewrite_addr)
205 {
206         struct sockaddr_in *addr4;
207         struct sockaddr_in6 *addr6;
208
209         switch (family) {
210         case AF_INET:
211                 addr4 = (struct sockaddr_in *)addr;
212                 memset(addr4, 0, sizeof(*addr4));
213                 addr4->sin_family = family;
214                 addr4->sin_port = htons(port);
215                 if (rewrite_addr)
216                         addr4->sin_addr.s_addr = htonl(TEST_DADDR);
217                 else
218                         addr4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
219                 break;
220         case AF_INET6:
221                 addr6 = (struct sockaddr_in6 *)addr;
222                 memset(addr6, 0, sizeof(*addr6));
223                 addr6->sin6_family = family;
224                 addr6->sin6_port = htons(port);
225                 addr6->sin6_addr = in6addr_loopback;
226                 if (rewrite_addr)
227                         addr6->sin6_addr.s6_addr32[3] = htonl(TEST_DADDR);
228                 break;
229         default:
230                 fprintf(stderr, "Invalid family %d", family);
231         }
232 }
233
234 struct test_sk_cfg {
235         const char *name;
236         int family;
237         struct sockaddr *addr;
238         socklen_t len;
239         int type;
240         bool rewrite_addr;
241 };
242
243 #define TEST(NAME, FAMILY, TYPE, REWRITE)                               \
244 {                                                                       \
245         .name = NAME,                                                   \
246         .family = FAMILY,                                               \
247         .addr = (FAMILY == AF_INET) ? (struct sockaddr *)&addr4         \
248                                     : (struct sockaddr *)&addr6,        \
249         .len = (FAMILY == AF_INET) ? sizeof(addr4) : sizeof(addr6),     \
250         .type = TYPE,                                                   \
251         .rewrite_addr = REWRITE,                                        \
252 }
253
254 void test_sk_assign(void)
255 {
256         struct sockaddr_in addr4;
257         struct sockaddr_in6 addr6;
258         struct test_sk_cfg tests[] = {
259                 TEST("ipv4 tcp port redir", AF_INET, SOCK_STREAM, false),
260                 TEST("ipv4 tcp addr redir", AF_INET, SOCK_STREAM, true),
261                 TEST("ipv6 tcp port redir", AF_INET6, SOCK_STREAM, false),
262                 TEST("ipv6 tcp addr redir", AF_INET6, SOCK_STREAM, true),
263                 TEST("ipv4 udp port redir", AF_INET, SOCK_DGRAM, false),
264                 TEST("ipv4 udp addr redir", AF_INET, SOCK_DGRAM, true),
265                 TEST("ipv6 udp port redir", AF_INET6, SOCK_DGRAM, false),
266                 TEST("ipv6 udp addr redir", AF_INET6, SOCK_DGRAM, true),
267         };
268         __s64 server = -1;
269         int server_map;
270         int self_net;
271         int i;
272
273         self_net = open(NS_SELF, O_RDONLY);
274         if (CHECK_FAIL(self_net < 0)) {
275                 perror("Unable to open "NS_SELF);
276                 return;
277         }
278
279         if (!configure_stack()) {
280                 perror("configure_stack");
281                 goto cleanup;
282         }
283
284         server_map = bpf_obj_get(SERVER_MAP_PATH);
285         if (CHECK_FAIL(server_map < 0)) {
286                 perror("Unable to open " SERVER_MAP_PATH);
287                 goto cleanup;
288         }
289
290         for (i = 0; i < ARRAY_SIZE(tests) && !READ_ONCE(stop); i++) {
291                 struct test_sk_cfg *test = &tests[i];
292                 const struct sockaddr *addr;
293                 const int zero = 0;
294                 int err;
295
296                 if (!test__start_subtest(test->name))
297                         continue;
298                 prepare_addr(test->addr, test->family, BIND_PORT, false);
299                 addr = (const struct sockaddr *)test->addr;
300                 server = start_server(addr, test->len, test->type);
301                 if (server == -1)
302                         goto close;
303
304                 err = bpf_map_update_elem(server_map, &zero, &server, BPF_ANY);
305                 if (CHECK_FAIL(err)) {
306                         perror("Unable to update server_map");
307                         goto close;
308                 }
309
310                 /* connect to unbound ports */
311                 prepare_addr(test->addr, test->family, CONNECT_PORT,
312                              test->rewrite_addr);
313                 if (run_test(server, addr, test->len, test->type))
314                         goto close;
315
316                 close(server);
317                 server = -1;
318         }
319
320 close:
321         close(server);
322         close(server_map);
323 cleanup:
324         if (CHECK_FAIL(unlink(SERVER_MAP_PATH)))
325                 perror("Unable to unlink " SERVER_MAP_PATH);
326         if (CHECK_FAIL(setns(self_net, CLONE_NEWNET)))
327                 perror("Failed to setns("NS_SELF")");
328         close(self_net);
329 }
This page took 0.04993 seconds and 4 git commands to generate.