~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/test_select_reuseport.c

Version: ~ [ linux-5.1-rc1 ] ~ [ linux-5.0.3 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.30 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.107 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.164 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.176 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.136 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.63 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /* Copyright (c) 2018 Facebook */
  3 
  4 #include <stdlib.h>
  5 #include <unistd.h>
  6 #include <stdbool.h>
  7 #include <string.h>
  8 #include <errno.h>
  9 #include <assert.h>
 10 #include <fcntl.h>
 11 #include <linux/bpf.h>
 12 #include <linux/err.h>
 13 #include <linux/types.h>
 14 #include <linux/if_ether.h>
 15 #include <sys/types.h>
 16 #include <sys/epoll.h>
 17 #include <sys/socket.h>
 18 #include <netinet/in.h>
 19 #include <bpf/bpf.h>
 20 #include <bpf/libbpf.h>
 21 #include "bpf_rlimit.h"
 22 #include "bpf_util.h"
 23 #include "test_select_reuseport_common.h"
 24 
 25 #define MIN_TCPHDR_LEN 20
 26 #define UDPHDR_LEN 8
 27 
 28 #define TCP_SYNCOOKIE_SYSCTL "/proc/sys/net/ipv4/tcp_syncookies"
 29 #define TCP_FO_SYSCTL "/proc/sys/net/ipv4/tcp_fastopen"
 30 #define REUSEPORT_ARRAY_SIZE 32
 31 
 32 static int result_map, tmp_index_ovr_map, linum_map, data_check_map;
 33 static enum result expected_results[NR_RESULTS];
 34 static int sk_fds[REUSEPORT_ARRAY_SIZE];
 35 static int reuseport_array, outer_map;
 36 static int select_by_skb_data_prog;
 37 static int saved_tcp_syncookie;
 38 static struct bpf_object *obj;
 39 static int saved_tcp_fo;
 40 static __u32 index_zero;
 41 static int epfd;
 42 
 43 static union sa46 {
 44         struct sockaddr_in6 v6;
 45         struct sockaddr_in v4;
 46         sa_family_t family;
 47 } srv_sa;
 48 
 49 #define CHECK(condition, tag, format...) ({                             \
 50         int __ret = !!(condition);                                      \
 51         if (__ret) {                                                    \
 52                 printf("%s(%d):FAIL:%s ", __func__, __LINE__, tag);     \
 53                 printf(format);                                         \
 54                 exit(-1);                                               \
 55         }                                                               \
 56 })
 57 
 58 static void create_maps(void)
 59 {
 60         struct bpf_create_map_attr attr = {};
 61 
 62         /* Creating reuseport_array */
 63         attr.name = "reuseport_array";
 64         attr.map_type = BPF_MAP_TYPE_REUSEPORT_SOCKARRAY;
 65         attr.key_size = sizeof(__u32);
 66         attr.value_size = sizeof(__u32);
 67         attr.max_entries = REUSEPORT_ARRAY_SIZE;
 68 
 69         reuseport_array = bpf_create_map_xattr(&attr);
 70         CHECK(reuseport_array == -1, "creating reuseport_array",
 71               "reuseport_array:%d errno:%d\n", reuseport_array, errno);
 72 
 73         /* Creating outer_map */
 74         attr.name = "outer_map";
 75         attr.map_type = BPF_MAP_TYPE_ARRAY_OF_MAPS;
 76         attr.key_size = sizeof(__u32);
 77         attr.value_size = sizeof(__u32);
 78         attr.max_entries = 1;
 79         attr.inner_map_fd = reuseport_array;
 80         outer_map = bpf_create_map_xattr(&attr);
 81         CHECK(outer_map == -1, "creating outer_map",
 82               "outer_map:%d errno:%d\n", outer_map, errno);
 83 }
 84 
 85 static void prepare_bpf_obj(void)
 86 {
 87         struct bpf_program *prog;
 88         struct bpf_map *map;
 89         int err;
 90         struct bpf_object_open_attr attr = {
 91                 .file = "test_select_reuseport_kern.o",
 92                 .prog_type = BPF_PROG_TYPE_SK_REUSEPORT,
 93         };
 94 
 95         obj = bpf_object__open_xattr(&attr);
 96         CHECK(IS_ERR_OR_NULL(obj), "open test_select_reuseport_kern.o",
 97               "obj:%p PTR_ERR(obj):%ld\n", obj, PTR_ERR(obj));
 98 
 99         prog = bpf_program__next(NULL, obj);
100         CHECK(!prog, "get first bpf_program", "!prog\n");
101         bpf_program__set_type(prog, attr.prog_type);
102 
103         map = bpf_object__find_map_by_name(obj, "outer_map");
104         CHECK(!map, "find outer_map", "!map\n");
105         err = bpf_map__reuse_fd(map, outer_map);
106         CHECK(err, "reuse outer_map", "err:%d\n", err);
107 
108         err = bpf_object__load(obj);
109         CHECK(err, "load bpf_object", "err:%d\n", err);
110 
111         select_by_skb_data_prog = bpf_program__fd(prog);
112         CHECK(select_by_skb_data_prog == -1, "get prog fd",
113               "select_by_skb_data_prog:%d\n", select_by_skb_data_prog);
114 
115         map = bpf_object__find_map_by_name(obj, "result_map");
116         CHECK(!map, "find result_map", "!map\n");
117         result_map = bpf_map__fd(map);
118         CHECK(result_map == -1, "get result_map fd",
119               "result_map:%d\n", result_map);
120 
121         map = bpf_object__find_map_by_name(obj, "tmp_index_ovr_map");
122         CHECK(!map, "find tmp_index_ovr_map", "!map\n");
123         tmp_index_ovr_map = bpf_map__fd(map);
124         CHECK(tmp_index_ovr_map == -1, "get tmp_index_ovr_map fd",
125               "tmp_index_ovr_map:%d\n", tmp_index_ovr_map);
126 
127         map = bpf_object__find_map_by_name(obj, "linum_map");
128         CHECK(!map, "find linum_map", "!map\n");
129         linum_map = bpf_map__fd(map);
130         CHECK(linum_map == -1, "get linum_map fd",
131               "linum_map:%d\n", linum_map);
132 
133         map = bpf_object__find_map_by_name(obj, "data_check_map");
134         CHECK(!map, "find data_check_map", "!map\n");
135         data_check_map = bpf_map__fd(map);
136         CHECK(data_check_map == -1, "get data_check_map fd",
137               "data_check_map:%d\n", data_check_map);
138 }
139 
140 static void sa46_init_loopback(union sa46 *sa, sa_family_t family)
141 {
142         memset(sa, 0, sizeof(*sa));
143         sa->family = family;
144         if (sa->family == AF_INET6)
145                 sa->v6.sin6_addr = in6addr_loopback;
146         else
147                 sa->v4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
148 }
149 
150 static void sa46_init_inany(union sa46 *sa, sa_family_t family)
151 {
152         memset(sa, 0, sizeof(*sa));
153         sa->family = family;
154         if (sa->family == AF_INET6)
155                 sa->v6.sin6_addr = in6addr_any;
156         else
157                 sa->v4.sin_addr.s_addr = INADDR_ANY;
158 }
159 
160 static int read_int_sysctl(const char *sysctl)
161 {
162         char buf[16];
163         int fd, ret;
164 
165         fd = open(sysctl, 0);
166         CHECK(fd == -1, "open(sysctl)", "sysctl:%s fd:%d errno:%d\n",
167               sysctl, fd, errno);
168 
169         ret = read(fd, buf, sizeof(buf));
170         CHECK(ret <= 0, "read(sysctl)", "sysctl:%s ret:%d errno:%d\n",
171               sysctl, ret, errno);
172         close(fd);
173 
174         return atoi(buf);
175 }
176 
177 static void write_int_sysctl(const char *sysctl, int v)
178 {
179         int fd, ret, size;
180         char buf[16];
181 
182         fd = open(sysctl, O_RDWR);
183         CHECK(fd == -1, "open(sysctl)", "sysctl:%s fd:%d errno:%d\n",
184               sysctl, fd, errno);
185 
186         size = snprintf(buf, sizeof(buf), "%d", v);
187         ret = write(fd, buf, size);
188         CHECK(ret != size, "write(sysctl)",
189               "sysctl:%s ret:%d size:%d errno:%d\n", sysctl, ret, size, errno);
190         close(fd);
191 }
192 
193 static void restore_sysctls(void)
194 {
195         write_int_sysctl(TCP_FO_SYSCTL, saved_tcp_fo);
196         write_int_sysctl(TCP_SYNCOOKIE_SYSCTL, saved_tcp_syncookie);
197 }
198 
199 static void enable_fastopen(void)
200 {
201         int fo;
202 
203         fo = read_int_sysctl(TCP_FO_SYSCTL);
204         write_int_sysctl(TCP_FO_SYSCTL, fo | 7);
205 }
206 
207 static void enable_syncookie(void)
208 {
209         write_int_sysctl(TCP_SYNCOOKIE_SYSCTL, 2);
210 }
211 
212 static void disable_syncookie(void)
213 {
214         write_int_sysctl(TCP_SYNCOOKIE_SYSCTL, 0);
215 }
216 
217 static __u32 get_linum(void)
218 {
219         __u32 linum;
220         int err;
221 
222         err = bpf_map_lookup_elem(linum_map, &index_zero, &linum);
223         CHECK(err == -1, "lookup_elem(linum_map)", "err:%d errno:%d\n",
224               err, errno);
225 
226         return linum;
227 }
228 
229 static void check_data(int type, sa_family_t family, const struct cmd *cmd,
230                        int cli_fd)
231 {
232         struct data_check expected = {}, result;
233         union sa46 cli_sa;
234         socklen_t addrlen;
235         int err;
236 
237         addrlen = sizeof(cli_sa);
238         err = getsockname(cli_fd, (struct sockaddr *)&cli_sa,
239                           &addrlen);
240         CHECK(err == -1, "getsockname(cli_fd)", "err:%d errno:%d\n",
241               err, errno);
242 
243         err = bpf_map_lookup_elem(data_check_map, &index_zero, &result);
244         CHECK(err == -1, "lookup_elem(data_check_map)", "err:%d errno:%d\n",
245               err, errno);
246 
247         if (type == SOCK_STREAM) {
248                 expected.len = MIN_TCPHDR_LEN;
249                 expected.ip_protocol = IPPROTO_TCP;
250         } else {
251                 expected.len = UDPHDR_LEN;
252                 expected.ip_protocol = IPPROTO_UDP;
253         }
254 
255         if (family == AF_INET6) {
256                 expected.eth_protocol = htons(ETH_P_IPV6);
257                 expected.bind_inany = !srv_sa.v6.sin6_addr.s6_addr32[3] &&
258                         !srv_sa.v6.sin6_addr.s6_addr32[2] &&
259                         !srv_sa.v6.sin6_addr.s6_addr32[1] &&
260                         !srv_sa.v6.sin6_addr.s6_addr32[0];
261 
262                 memcpy(&expected.skb_addrs[0], cli_sa.v6.sin6_addr.s6_addr32,
263                        sizeof(cli_sa.v6.sin6_addr));
264                 memcpy(&expected.skb_addrs[4], &in6addr_loopback,
265                        sizeof(in6addr_loopback));
266                 expected.skb_ports[0] = cli_sa.v6.sin6_port;
267                 expected.skb_ports[1] = srv_sa.v6.sin6_port;
268         } else {
269                 expected.eth_protocol = htons(ETH_P_IP);
270                 expected.bind_inany = !srv_sa.v4.sin_addr.s_addr;
271 
272                 expected.skb_addrs[0] = cli_sa.v4.sin_addr.s_addr;
273                 expected.skb_addrs[1] = htonl(INADDR_LOOPBACK);
274                 expected.skb_ports[0] = cli_sa.v4.sin_port;
275                 expected.skb_ports[1] = srv_sa.v4.sin_port;
276         }
277 
278         if (memcmp(&result, &expected, offsetof(struct data_check,
279                                                 equal_check_end))) {
280                 printf("unexpected data_check\n");
281                 printf("  result: (0x%x, %u, %u)\n",
282                        result.eth_protocol, result.ip_protocol,
283                        result.bind_inany);
284                 printf("expected: (0x%x, %u, %u)\n",
285                        expected.eth_protocol, expected.ip_protocol,
286                        expected.bind_inany);
287                 CHECK(1, "data_check result != expected",
288                       "bpf_prog_linum:%u\n", get_linum());
289         }
290 
291         CHECK(!result.hash, "data_check result.hash empty",
292               "result.hash:%u", result.hash);
293 
294         expected.len += cmd ? sizeof(*cmd) : 0;
295         if (type == SOCK_STREAM)
296                 CHECK(expected.len > result.len, "expected.len > result.len",
297                       "expected.len:%u result.len:%u bpf_prog_linum:%u\n",
298                       expected.len, result.len, get_linum());
299         else
300                 CHECK(expected.len != result.len, "expected.len != result.len",
301                       "expected.len:%u result.len:%u bpf_prog_linum:%u\n",
302                       expected.len, result.len, get_linum());
303 }
304 
305 static void check_results(void)
306 {
307         __u32 results[NR_RESULTS];
308         __u32 i, broken = 0;
309         int err;
310 
311         for (i = 0; i < NR_RESULTS; i++) {
312                 err = bpf_map_lookup_elem(result_map, &i, &results[i]);
313                 CHECK(err == -1, "lookup_elem(result_map)",
314                       "i:%u err:%d errno:%d\n", i, err, errno);
315         }
316 
317         for (i = 0; i < NR_RESULTS; i++) {
318                 if (results[i] != expected_results[i]) {
319                         broken = i;
320                         break;
321                 }
322         }
323 
324         if (i == NR_RESULTS)
325                 return;
326 
327         printf("unexpected result\n");
328         printf(" result: [");
329         printf("%u", results[0]);
330         for (i = 1; i < NR_RESULTS; i++)
331                 printf(", %u", results[i]);
332         printf("]\n");
333 
334         printf("expected: [");
335         printf("%u", expected_results[0]);
336         for (i = 1; i < NR_RESULTS; i++)
337                 printf(", %u", expected_results[i]);
338         printf("]\n");
339 
340         CHECK(expected_results[broken] != results[broken],
341               "unexpected result",
342               "expected_results[%u] != results[%u] bpf_prog_linum:%u\n",
343               broken, broken, get_linum());
344 }
345 
346 static int send_data(int type, sa_family_t family, void *data, size_t len,
347                      enum result expected)
348 {
349         union sa46 cli_sa;
350         int fd, err;
351 
352         fd = socket(family, type, 0);
353         CHECK(fd == -1, "socket()", "fd:%d errno:%d\n", fd, errno);
354 
355         sa46_init_loopback(&cli_sa, family);
356         err = bind(fd, (struct sockaddr *)&cli_sa, sizeof(cli_sa));
357         CHECK(fd == -1, "bind(cli_sa)", "err:%d errno:%d\n", err, errno);
358 
359         err = sendto(fd, data, len, MSG_FASTOPEN, (struct sockaddr *)&srv_sa,
360                      sizeof(srv_sa));
361         CHECK(err != len && expected >= PASS,
362               "sendto()", "family:%u err:%d errno:%d expected:%d\n",
363               family, err, errno, expected);
364 
365         return fd;
366 }
367 
368 static void do_test(int type, sa_family_t family, struct cmd *cmd,
369                     enum result expected)
370 {
371         int nev, srv_fd, cli_fd;
372         struct epoll_event ev;
373         struct cmd rcv_cmd;
374         ssize_t nread;
375 
376         cli_fd = send_data(type, family, cmd, cmd ? sizeof(*cmd) : 0,
377                            expected);
378         nev = epoll_wait(epfd, &ev, 1, expected >= PASS ? 5 : 0);
379         CHECK((nev <= 0 && expected >= PASS) ||
380               (nev > 0 && expected < PASS),
381               "nev <> expected",
382               "nev:%d expected:%d type:%d family:%d data:(%d, %d)\n",
383               nev, expected, type, family,
384               cmd ? cmd->reuseport_index : -1,
385               cmd ? cmd->pass_on_failure : -1);
386         check_results();
387         check_data(type, family, cmd, cli_fd);
388 
389         if (expected < PASS)
390                 return;
391 
392         CHECK(expected != PASS_ERR_SK_SELECT_REUSEPORT &&
393               cmd->reuseport_index != ev.data.u32,
394               "check cmd->reuseport_index",
395               "cmd:(%u, %u) ev.data.u32:%u\n",
396               cmd->pass_on_failure, cmd->reuseport_index, ev.data.u32);
397 
398         srv_fd = sk_fds[ev.data.u32];
399         if (type == SOCK_STREAM) {
400                 int new_fd = accept(srv_fd, NULL, 0);
401 
402                 CHECK(new_fd == -1, "accept(srv_fd)",
403                       "ev.data.u32:%u new_fd:%d errno:%d\n",
404                       ev.data.u32, new_fd, errno);
405 
406                 nread = recv(new_fd, &rcv_cmd, sizeof(rcv_cmd), MSG_DONTWAIT);
407                 CHECK(nread != sizeof(rcv_cmd),
408                       "recv(new_fd)",
409                       "ev.data.u32:%u nread:%zd sizeof(rcv_cmd):%zu errno:%d\n",
410                       ev.data.u32, nread, sizeof(rcv_cmd), errno);
411 
412                 close(new_fd);
413         } else {
414                 nread = recv(srv_fd, &rcv_cmd, sizeof(rcv_cmd), MSG_DONTWAIT);
415                 CHECK(nread != sizeof(rcv_cmd),
416                       "recv(sk_fds)",
417                       "ev.data.u32:%u nread:%zd sizeof(rcv_cmd):%zu errno:%d\n",
418                       ev.data.u32, nread, sizeof(rcv_cmd), errno);
419         }
420 
421         close(cli_fd);
422 }
423 
424 static void test_err_inner_map(int type, sa_family_t family)
425 {
426         struct cmd cmd = {
427                 .reuseport_index = 0,
428                 .pass_on_failure = 0,
429         };
430 
431         printf("%s: ", __func__);
432         expected_results[DROP_ERR_INNER_MAP]++;
433         do_test(type, family, &cmd, DROP_ERR_INNER_MAP);
434         printf("OK\n");
435 }
436 
437 static void test_err_skb_data(int type, sa_family_t family)
438 {
439         printf("%s: ", __func__);
440         expected_results[DROP_ERR_SKB_DATA]++;
441         do_test(type, family, NULL, DROP_ERR_SKB_DATA);
442         printf("OK\n");
443 }
444 
445 static void test_err_sk_select_port(int type, sa_family_t family)
446 {
447         struct cmd cmd = {
448                 .reuseport_index = REUSEPORT_ARRAY_SIZE,
449                 .pass_on_failure = 0,
450         };
451 
452         printf("%s: ", __func__);
453         expected_results[DROP_ERR_SK_SELECT_REUSEPORT]++;
454         do_test(type, family, &cmd, DROP_ERR_SK_SELECT_REUSEPORT);
455         printf("OK\n");
456 }
457 
458 static void test_pass(int type, sa_family_t family)
459 {
460         struct cmd cmd;
461         int i;
462 
463         printf("%s: ", __func__);
464         cmd.pass_on_failure = 0;
465         for (i = 0; i < REUSEPORT_ARRAY_SIZE; i++) {
466                 expected_results[PASS]++;
467                 cmd.reuseport_index = i;
468                 do_test(type, family, &cmd, PASS);
469         }
470         printf("OK\n");
471 }
472 
473 static void test_syncookie(int type, sa_family_t family)
474 {
475         int err, tmp_index = 1;
476         struct cmd cmd = {
477                 .reuseport_index = 0,
478                 .pass_on_failure = 0,
479         };
480 
481         if (type != SOCK_STREAM)
482                 return;
483 
484         printf("%s: ", __func__);
485         /*
486          * +1 for TCP-SYN and
487          * +1 for the TCP-ACK (ack the syncookie)
488          */
489         expected_results[PASS] += 2;
490         enable_syncookie();
491         /*
492          * Simulate TCP-SYN and TCP-ACK are handled by two different sk:
493          * TCP-SYN: select sk_fds[tmp_index = 1] tmp_index is from the
494          *          tmp_index_ovr_map
495          * TCP-ACK: select sk_fds[reuseport_index = 0] reuseport_index
496          *          is from the cmd.reuseport_index
497          */
498         err = bpf_map_update_elem(tmp_index_ovr_map, &index_zero,
499                                   &tmp_index, BPF_ANY);
500         CHECK(err == -1, "update_elem(tmp_index_ovr_map, 0, 1)",
501               "err:%d errno:%d\n", err, errno);
502         do_test(type, family, &cmd, PASS);
503         err = bpf_map_lookup_elem(tmp_index_ovr_map, &index_zero,
504                                   &tmp_index);
505         CHECK(err == -1 || tmp_index != -1,
506               "lookup_elem(tmp_index_ovr_map)",
507               "err:%d errno:%d tmp_index:%d\n",
508               err, errno, tmp_index);
509         disable_syncookie();
510         printf("OK\n");
511 }
512 
513 static void test_pass_on_err(int type, sa_family_t family)
514 {
515         struct cmd cmd = {
516                 .reuseport_index = REUSEPORT_ARRAY_SIZE,
517                 .pass_on_failure = 1,
518         };
519 
520         printf("%s: ", __func__);
521         expected_results[PASS_ERR_SK_SELECT_REUSEPORT] += 1;
522         do_test(type, family, &cmd, PASS_ERR_SK_SELECT_REUSEPORT);
523         printf("OK\n");
524 }
525 
526 static void prepare_sk_fds(int type, sa_family_t family, bool inany)
527 {
528         const int first = REUSEPORT_ARRAY_SIZE - 1;
529         int i, err, optval = 1;
530         struct epoll_event ev;
531         socklen_t addrlen;
532 
533         if (inany)
534                 sa46_init_inany(&srv_sa, family);
535         else
536                 sa46_init_loopback(&srv_sa, family);
537         addrlen = sizeof(srv_sa);
538 
539         /*
540          * The sk_fds[] is filled from the back such that the order
541          * is exactly opposite to the (struct sock_reuseport *)reuse->socks[].
542          */
543         for (i = first; i >= 0; i--) {
544                 sk_fds[i] = socket(family, type, 0);
545                 CHECK(sk_fds[i] == -1, "socket()", "sk_fds[%d]:%d errno:%d\n",
546                       i, sk_fds[i], errno);
547                 err = setsockopt(sk_fds[i], SOL_SOCKET, SO_REUSEPORT,
548                                  &optval, sizeof(optval));
549                 CHECK(err == -1, "setsockopt(SO_REUSEPORT)",
550                       "sk_fds[%d] err:%d errno:%d\n",
551                       i, err, errno);
552 
553                 if (i == first) {
554                         err = setsockopt(sk_fds[i], SOL_SOCKET,
555                                          SO_ATTACH_REUSEPORT_EBPF,
556                                          &select_by_skb_data_prog,
557                                          sizeof(select_by_skb_data_prog));
558                         CHECK(err == -1, "setsockopt(SO_ATTACH_REUEPORT_EBPF)",
559                               "err:%d errno:%d\n", err, errno);
560                 }
561 
562                 err = bind(sk_fds[i], (struct sockaddr *)&srv_sa, addrlen);
563                 CHECK(err == -1, "bind()", "sk_fds[%d] err:%d errno:%d\n",
564                       i, err, errno);
565 
566                 if (type == SOCK_STREAM) {
567                         err = listen(sk_fds[i], 10);
568                         CHECK(err == -1, "listen()",
569                               "sk_fds[%d] err:%d errno:%d\n",
570                               i, err, errno);
571                 }
572 
573                 err = bpf_map_update_elem(reuseport_array, &i, &sk_fds[i],
574                                           BPF_NOEXIST);
575                 CHECK(err == -1, "update_elem(reuseport_array)",
576                       "sk_fds[%d] err:%d errno:%d\n", i, err, errno);
577 
578                 if (i == first) {
579                         socklen_t addrlen = sizeof(srv_sa);
580 
581                         err = getsockname(sk_fds[i], (struct sockaddr *)&srv_sa,
582                                           &addrlen);
583                         CHECK(err == -1, "getsockname()",
584                               "sk_fds[%d] err:%d errno:%d\n", i, err, errno);
585                 }
586         }
587 
588         epfd = epoll_create(1);
589         CHECK(epfd == -1, "epoll_create(1)",
590               "epfd:%d errno:%d\n", epfd, errno);
591 
592         ev.events = EPOLLIN;
593         for (i = 0; i < REUSEPORT_ARRAY_SIZE; i++) {
594                 ev.data.u32 = i;
595                 err = epoll_ctl(epfd, EPOLL_CTL_ADD, sk_fds[i], &ev);
596                 CHECK(err, "epoll_ctl(EPOLL_CTL_ADD)", "sk_fds[%d]\n", i);
597         }
598 }
599 
600 static void setup_per_test(int type, unsigned short family, bool inany)
601 {
602         int ovr = -1, err;
603 
604         prepare_sk_fds(type, family, inany);
605         err = bpf_map_update_elem(tmp_index_ovr_map, &index_zero, &ovr,
606                                   BPF_ANY);
607         CHECK(err == -1, "update_elem(tmp_index_ovr_map, 0, -1)",
608               "err:%d errno:%d\n", err, errno);
609 }
610 
611 static void cleanup_per_test(void)
612 {
613         int i, err;
614 
615         for (i = 0; i < REUSEPORT_ARRAY_SIZE; i++)
616                 close(sk_fds[i]);
617         close(epfd);
618 
619         err = bpf_map_delete_elem(outer_map, &index_zero);
620         CHECK(err == -1, "delete_elem(outer_map)",
621               "err:%d errno:%d\n", err, errno);
622 }
623 
624 static void cleanup(void)
625 {
626         close(outer_map);
627         close(reuseport_array);
628         bpf_object__close(obj);
629 }
630 
631 static void test_all(void)
632 {
633         /* Extra SOCK_STREAM to test bind_inany==true */
634         const int types[] = { SOCK_STREAM, SOCK_DGRAM, SOCK_STREAM };
635         const char * const type_strings[] = { "TCP", "UDP", "TCP" };
636         const char * const family_strings[] = { "IPv6", "IPv4" };
637         const unsigned short families[] = { AF_INET6, AF_INET };
638         const bool bind_inany[] = { false, false, true };
639         int t, f, err;
640 
641         for (f = 0; f < ARRAY_SIZE(families); f++) {
642                 unsigned short family = families[f];
643 
644                 for (t = 0; t < ARRAY_SIZE(types); t++) {
645                         bool inany = bind_inany[t];
646                         int type = types[t];
647 
648                         printf("######## %s/%s %s ########\n",
649                                family_strings[f], type_strings[t],
650                                 inany ? " INANY  " : "LOOPBACK");
651 
652                         setup_per_test(type, family, inany);
653 
654                         test_err_inner_map(type, family);
655 
656                         /* Install reuseport_array to the outer_map */
657                         err = bpf_map_update_elem(outer_map, &index_zero,
658                                                   &reuseport_array, BPF_ANY);
659                         CHECK(err == -1, "update_elem(outer_map)",
660                               "err:%d errno:%d\n", err, errno);
661 
662                         test_err_skb_data(type, family);
663                         test_err_sk_select_port(type, family);
664                         test_pass(type, family);
665                         test_syncookie(type, family);
666                         test_pass_on_err(type, family);
667 
668                         cleanup_per_test();
669                         printf("\n");
670                 }
671         }
672 }
673 
674 int main(int argc, const char **argv)
675 {
676         create_maps();
677         prepare_bpf_obj();
678         saved_tcp_fo = read_int_sysctl(TCP_FO_SYSCTL);
679         saved_tcp_syncookie = read_int_sysctl(TCP_SYNCOOKIE_SYSCTL);
680         enable_fastopen();
681         disable_syncookie();
682         atexit(restore_sysctls);
683 
684         test_all();
685 
686         cleanup();
687         return 0;
688 }
689 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp