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

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/prog_tests/tcp_hdr_options.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /* Copyright (c) 2020 Facebook */
  3 
  4 #define _GNU_SOURCE
  5 #include <sched.h>
  6 #include <stdio.h>
  7 #include <stdlib.h>
  8 #include <sys/socket.h>
  9 #include <linux/compiler.h>
 10 
 11 #include "test_progs.h"
 12 #include "cgroup_helpers.h"
 13 #include "network_helpers.h"
 14 #include "test_tcp_hdr_options.h"
 15 #include "test_tcp_hdr_options.skel.h"
 16 #include "test_misc_tcp_hdr_options.skel.h"
 17 
 18 #define LO_ADDR6 "::1"
 19 #define CG_NAME "/tcpbpf-hdr-opt-test"
 20 
 21 static struct bpf_test_option exp_passive_estab_in;
 22 static struct bpf_test_option exp_active_estab_in;
 23 static struct bpf_test_option exp_passive_fin_in;
 24 static struct bpf_test_option exp_active_fin_in;
 25 static struct hdr_stg exp_passive_hdr_stg;
 26 static struct hdr_stg exp_active_hdr_stg = { .active = true, };
 27 
 28 static struct test_misc_tcp_hdr_options *misc_skel;
 29 static struct test_tcp_hdr_options *skel;
 30 static int lport_linum_map_fd;
 31 static int hdr_stg_map_fd;
 32 static __u32 duration;
 33 static int cg_fd;
 34 
 35 struct sk_fds {
 36         int srv_fd;
 37         int passive_fd;
 38         int active_fd;
 39         int passive_lport;
 40         int active_lport;
 41 };
 42 
 43 static int create_netns(void)
 44 {
 45         if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns"))
 46                 return -1;
 47 
 48         if (!ASSERT_OK(system("ip link set dev lo up"), "run ip cmd"))
 49                 return -1;
 50 
 51         return 0;
 52 }
 53 
 54 static void print_hdr_stg(const struct hdr_stg *hdr_stg, const char *prefix)
 55 {
 56         fprintf(stderr, "%s{active:%u, resend_syn:%u, syncookie:%u, fastopen:%u}\n",
 57                 prefix ? : "", hdr_stg->active, hdr_stg->resend_syn,
 58                 hdr_stg->syncookie, hdr_stg->fastopen);
 59 }
 60 
 61 static void print_option(const struct bpf_test_option *opt, const char *prefix)
 62 {
 63         fprintf(stderr, "%s{flags:0x%x, max_delack_ms:%u, rand:0x%x}\n",
 64                 prefix ? : "", opt->flags, opt->max_delack_ms, opt->rand);
 65 }
 66 
 67 static void sk_fds_close(struct sk_fds *sk_fds)
 68 {
 69         close(sk_fds->srv_fd);
 70         close(sk_fds->passive_fd);
 71         close(sk_fds->active_fd);
 72 }
 73 
 74 static int sk_fds_shutdown(struct sk_fds *sk_fds)
 75 {
 76         int ret, abyte;
 77 
 78         shutdown(sk_fds->active_fd, SHUT_WR);
 79         ret = read(sk_fds->passive_fd, &abyte, sizeof(abyte));
 80         if (!ASSERT_EQ(ret, 0, "read-after-shutdown(passive_fd):"))
 81                 return -1;
 82 
 83         shutdown(sk_fds->passive_fd, SHUT_WR);
 84         ret = read(sk_fds->active_fd, &abyte, sizeof(abyte));
 85         if (!ASSERT_EQ(ret, 0, "read-after-shutdown(active_fd):"))
 86                 return -1;
 87 
 88         return 0;
 89 }
 90 
 91 static int sk_fds_connect(struct sk_fds *sk_fds, bool fast_open)
 92 {
 93         const char fast[] = "FAST!!!";
 94         struct sockaddr_in6 addr6;
 95         socklen_t len;
 96 
 97         sk_fds->srv_fd = start_server(AF_INET6, SOCK_STREAM, LO_ADDR6, 0, 0);
 98         if (!ASSERT_NEQ(sk_fds->srv_fd, -1, "start_server"))
 99                 goto error;
100 
101         if (fast_open)
102                 sk_fds->active_fd = fastopen_connect(sk_fds->srv_fd, fast,
103                                                      sizeof(fast), 0);
104         else
105                 sk_fds->active_fd = connect_to_fd(sk_fds->srv_fd, 0);
106 
107         if (!ASSERT_NEQ(sk_fds->active_fd, -1, "")) {
108                 close(sk_fds->srv_fd);
109                 goto error;
110         }
111 
112         len = sizeof(addr6);
113         if (!ASSERT_OK(getsockname(sk_fds->srv_fd, (struct sockaddr *)&addr6,
114                                    &len), "getsockname(srv_fd)"))
115                 goto error_close;
116         sk_fds->passive_lport = ntohs(addr6.sin6_port);
117 
118         len = sizeof(addr6);
119         if (!ASSERT_OK(getsockname(sk_fds->active_fd, (struct sockaddr *)&addr6,
120                                    &len), "getsockname(active_fd)"))
121                 goto error_close;
122         sk_fds->active_lport = ntohs(addr6.sin6_port);
123 
124         sk_fds->passive_fd = accept(sk_fds->srv_fd, NULL, 0);
125         if (!ASSERT_NEQ(sk_fds->passive_fd, -1, "accept(srv_fd)"))
126                 goto error_close;
127 
128         if (fast_open) {
129                 char bytes_in[sizeof(fast)];
130                 int ret;
131 
132                 ret = read(sk_fds->passive_fd, bytes_in, sizeof(bytes_in));
133                 if (!ASSERT_EQ(ret, sizeof(fast), "read fastopen syn data")) {
134                         close(sk_fds->passive_fd);
135                         goto error_close;
136                 }
137         }
138 
139         return 0;
140 
141 error_close:
142         close(sk_fds->active_fd);
143         close(sk_fds->srv_fd);
144 
145 error:
146         memset(sk_fds, -1, sizeof(*sk_fds));
147         return -1;
148 }
149 
150 static int check_hdr_opt(const struct bpf_test_option *exp,
151                          const struct bpf_test_option *act,
152                          const char *hdr_desc)
153 {
154         if (!ASSERT_EQ(memcmp(exp, act, sizeof(*exp)), 0, hdr_desc)) {
155                 print_option(exp, "expected: ");
156                 print_option(act, "  actual: ");
157                 return -1;
158         }
159 
160         return 0;
161 }
162 
163 static int check_hdr_stg(const struct hdr_stg *exp, int fd,
164                          const char *stg_desc)
165 {
166         struct hdr_stg act;
167 
168         if (!ASSERT_OK(bpf_map_lookup_elem(hdr_stg_map_fd, &fd, &act),
169                   "map_lookup(hdr_stg_map_fd)"))
170                 return -1;
171 
172         if (!ASSERT_EQ(memcmp(exp, &act, sizeof(*exp)), 0, stg_desc)) {
173                 print_hdr_stg(exp, "expected: ");
174                 print_hdr_stg(&act, "  actual: ");
175                 return -1;
176         }
177 
178         return 0;
179 }
180 
181 static int check_error_linum(const struct sk_fds *sk_fds)
182 {
183         unsigned int nr_errors = 0;
184         struct linum_err linum_err;
185         int lport;
186 
187         lport = sk_fds->passive_lport;
188         if (!bpf_map_lookup_elem(lport_linum_map_fd, &lport, &linum_err)) {
189                 fprintf(stderr,
190                         "bpf prog error out at lport:passive(%d), linum:%u err:%d\n",
191                         lport, linum_err.linum, linum_err.err);
192                 nr_errors++;
193         }
194 
195         lport = sk_fds->active_lport;
196         if (!bpf_map_lookup_elem(lport_linum_map_fd, &lport, &linum_err)) {
197                 fprintf(stderr,
198                         "bpf prog error out at lport:active(%d), linum:%u err:%d\n",
199                         lport, linum_err.linum, linum_err.err);
200                 nr_errors++;
201         }
202 
203         return nr_errors;
204 }
205 
206 static void check_hdr_and_close_fds(struct sk_fds *sk_fds)
207 {
208         const __u32 expected_inherit_cb_flags =
209                 BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG |
210                 BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG |
211                 BPF_SOCK_OPS_STATE_CB_FLAG;
212 
213         if (sk_fds_shutdown(sk_fds))
214                 goto check_linum;
215 
216         if (!ASSERT_EQ(expected_inherit_cb_flags, skel->bss->inherit_cb_flags,
217                        "inherit_cb_flags"))
218                 goto check_linum;
219 
220         if (check_hdr_stg(&exp_passive_hdr_stg, sk_fds->passive_fd,
221                           "passive_hdr_stg"))
222                 goto check_linum;
223 
224         if (check_hdr_stg(&exp_active_hdr_stg, sk_fds->active_fd,
225                           "active_hdr_stg"))
226                 goto check_linum;
227 
228         if (check_hdr_opt(&exp_passive_estab_in, &skel->bss->passive_estab_in,
229                           "passive_estab_in"))
230                 goto check_linum;
231 
232         if (check_hdr_opt(&exp_active_estab_in, &skel->bss->active_estab_in,
233                           "active_estab_in"))
234                 goto check_linum;
235 
236         if (check_hdr_opt(&exp_passive_fin_in, &skel->bss->passive_fin_in,
237                           "passive_fin_in"))
238                 goto check_linum;
239 
240         check_hdr_opt(&exp_active_fin_in, &skel->bss->active_fin_in,
241                       "active_fin_in");
242 
243 check_linum:
244         ASSERT_FALSE(check_error_linum(sk_fds), "check_error_linum");
245         sk_fds_close(sk_fds);
246 }
247 
248 static void prepare_out(void)
249 {
250         skel->bss->active_syn_out = exp_passive_estab_in;
251         skel->bss->passive_synack_out = exp_active_estab_in;
252 
253         skel->bss->active_fin_out = exp_passive_fin_in;
254         skel->bss->passive_fin_out = exp_active_fin_in;
255 }
256 
257 static void reset_test(void)
258 {
259         size_t optsize = sizeof(struct bpf_test_option);
260         int lport, err;
261 
262         memset(&skel->bss->passive_synack_out, 0, optsize);
263         memset(&skel->bss->passive_fin_out, 0, optsize);
264 
265         memset(&skel->bss->passive_estab_in, 0, optsize);
266         memset(&skel->bss->passive_fin_in, 0, optsize);
267 
268         memset(&skel->bss->active_syn_out, 0, optsize);
269         memset(&skel->bss->active_fin_out, 0, optsize);
270 
271         memset(&skel->bss->active_estab_in, 0, optsize);
272         memset(&skel->bss->active_fin_in, 0, optsize);
273 
274         skel->bss->inherit_cb_flags = 0;
275 
276         skel->data->test_kind = TCPOPT_EXP;
277         skel->data->test_magic = 0xeB9F;
278 
279         memset(&exp_passive_estab_in, 0, optsize);
280         memset(&exp_active_estab_in, 0, optsize);
281         memset(&exp_passive_fin_in, 0, optsize);
282         memset(&exp_active_fin_in, 0, optsize);
283 
284         memset(&exp_passive_hdr_stg, 0, sizeof(exp_passive_hdr_stg));
285         memset(&exp_active_hdr_stg, 0, sizeof(exp_active_hdr_stg));
286         exp_active_hdr_stg.active = true;
287 
288         err = bpf_map_get_next_key(lport_linum_map_fd, NULL, &lport);
289         while (!err) {
290                 bpf_map_delete_elem(lport_linum_map_fd, &lport);
291                 err = bpf_map_get_next_key(lport_linum_map_fd, &lport, &lport);
292         }
293 }
294 
295 static void fastopen_estab(void)
296 {
297         struct bpf_link *link;
298         struct sk_fds sk_fds;
299 
300         hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
301         lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
302 
303         exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
304         exp_passive_estab_in.rand = 0xfa;
305         exp_passive_estab_in.max_delack_ms = 11;
306 
307         exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
308         exp_active_estab_in.rand = 0xce;
309         exp_active_estab_in.max_delack_ms = 22;
310 
311         exp_passive_hdr_stg.fastopen = true;
312 
313         prepare_out();
314 
315         /* Allow fastopen without fastopen cookie */
316         if (write_sysctl("/proc/sys/net/ipv4/tcp_fastopen", "1543"))
317                 return;
318 
319         link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
320         if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))
321                 return;
322 
323         if (sk_fds_connect(&sk_fds, true)) {
324                 bpf_link__destroy(link);
325                 return;
326         }
327 
328         check_hdr_and_close_fds(&sk_fds);
329         bpf_link__destroy(link);
330 }
331 
332 static void syncookie_estab(void)
333 {
334         struct bpf_link *link;
335         struct sk_fds sk_fds;
336 
337         hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
338         lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
339 
340         exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
341         exp_passive_estab_in.rand = 0xfa;
342         exp_passive_estab_in.max_delack_ms = 11;
343 
344         exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS |
345                                         OPTION_F_RESEND;
346         exp_active_estab_in.rand = 0xce;
347         exp_active_estab_in.max_delack_ms = 22;
348 
349         exp_passive_hdr_stg.syncookie = true;
350         exp_active_hdr_stg.resend_syn = true;
351 
352         prepare_out();
353 
354         /* Clear the RESEND to ensure the bpf prog can learn
355          * want_cookie and set the RESEND by itself.
356          */
357         skel->bss->passive_synack_out.flags &= ~OPTION_F_RESEND;
358 
359         /* Enforce syncookie mode */
360         if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "2"))
361                 return;
362 
363         link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
364         if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))
365                 return;
366 
367         if (sk_fds_connect(&sk_fds, false)) {
368                 bpf_link__destroy(link);
369                 return;
370         }
371 
372         check_hdr_and_close_fds(&sk_fds);
373         bpf_link__destroy(link);
374 }
375 
376 static void fin(void)
377 {
378         struct bpf_link *link;
379         struct sk_fds sk_fds;
380 
381         hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
382         lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
383 
384         exp_passive_fin_in.flags = OPTION_F_RAND;
385         exp_passive_fin_in.rand = 0xfa;
386 
387         exp_active_fin_in.flags = OPTION_F_RAND;
388         exp_active_fin_in.rand = 0xce;
389 
390         prepare_out();
391 
392         if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))
393                 return;
394 
395         link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
396         if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))
397                 return;
398 
399         if (sk_fds_connect(&sk_fds, false)) {
400                 bpf_link__destroy(link);
401                 return;
402         }
403 
404         check_hdr_and_close_fds(&sk_fds);
405         bpf_link__destroy(link);
406 }
407 
408 static void __simple_estab(bool exprm)
409 {
410         struct bpf_link *link;
411         struct sk_fds sk_fds;
412 
413         hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);
414         lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);
415 
416         exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
417         exp_passive_estab_in.rand = 0xfa;
418         exp_passive_estab_in.max_delack_ms = 11;
419 
420         exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;
421         exp_active_estab_in.rand = 0xce;
422         exp_active_estab_in.max_delack_ms = 22;
423 
424         prepare_out();
425 
426         if (!exprm) {
427                 skel->data->test_kind = 0xB9;
428                 skel->data->test_magic = 0;
429         }
430 
431         if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))
432                 return;
433 
434         link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);
435         if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))
436                 return;
437 
438         if (sk_fds_connect(&sk_fds, false)) {
439                 bpf_link__destroy(link);
440                 return;
441         }
442 
443         check_hdr_and_close_fds(&sk_fds);
444         bpf_link__destroy(link);
445 }
446 
447 static void no_exprm_estab(void)
448 {
449         __simple_estab(false);
450 }
451 
452 static void simple_estab(void)
453 {
454         __simple_estab(true);
455 }
456 
457 static void misc(void)
458 {
459         const char send_msg[] = "MISC!!!";
460         char recv_msg[sizeof(send_msg)];
461         const unsigned int nr_data = 2;
462         struct bpf_link *link;
463         struct sk_fds sk_fds;
464         int i, ret;
465 
466         lport_linum_map_fd = bpf_map__fd(misc_skel->maps.lport_linum_map);
467 
468         if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))
469                 return;
470 
471         link = bpf_program__attach_cgroup(misc_skel->progs.misc_estab, cg_fd);
472         if (!ASSERT_OK_PTR(link, "attach_cgroup(misc_estab)"))
473                 return;
474 
475         if (sk_fds_connect(&sk_fds, false)) {
476                 bpf_link__destroy(link);
477                 return;
478         }
479 
480         for (i = 0; i < nr_data; i++) {
481                 /* MSG_EOR to ensure skb will not be combined */
482                 ret = send(sk_fds.active_fd, send_msg, sizeof(send_msg),
483                            MSG_EOR);
484                 if (!ASSERT_EQ(ret, sizeof(send_msg), "send(msg)"))
485                         goto check_linum;
486 
487                 ret = read(sk_fds.passive_fd, recv_msg, sizeof(recv_msg));
488                 if (!ASSERT_EQ(ret, sizeof(send_msg), "read(msg)"))
489                         goto check_linum;
490         }
491 
492         if (sk_fds_shutdown(&sk_fds))
493                 goto check_linum;
494 
495         ASSERT_EQ(misc_skel->bss->nr_syn, 1, "unexpected nr_syn");
496 
497         ASSERT_EQ(misc_skel->bss->nr_data, nr_data, "unexpected nr_data");
498 
499         /* The last ACK may have been delayed, so it is either 1 or 2. */
500         CHECK(misc_skel->bss->nr_pure_ack != 1 &&
501               misc_skel->bss->nr_pure_ack != 2,
502               "unexpected nr_pure_ack",
503               "expected (1 or 2) != actual (%u)\n",
504                 misc_skel->bss->nr_pure_ack);
505 
506         ASSERT_EQ(misc_skel->bss->nr_fin, 1, "unexpected nr_fin");
507 
508         ASSERT_EQ(misc_skel->bss->nr_hwtstamp, 0, "nr_hwtstamp");
509 
510 check_linum:
511         ASSERT_FALSE(check_error_linum(&sk_fds), "check_error_linum");
512         sk_fds_close(&sk_fds);
513         bpf_link__destroy(link);
514 }
515 
516 struct test {
517         const char *desc;
518         void (*run)(void);
519 };
520 
521 #define DEF_TEST(name) { #name, name }
522 static struct test tests[] = {
523         DEF_TEST(simple_estab),
524         DEF_TEST(no_exprm_estab),
525         DEF_TEST(syncookie_estab),
526         DEF_TEST(fastopen_estab),
527         DEF_TEST(fin),
528         DEF_TEST(misc),
529 };
530 
531 void test_tcp_hdr_options(void)
532 {
533         int i;
534 
535         skel = test_tcp_hdr_options__open_and_load();
536         if (!ASSERT_OK_PTR(skel, "open and load skel"))
537                 return;
538 
539         misc_skel = test_misc_tcp_hdr_options__open_and_load();
540         if (!ASSERT_OK_PTR(misc_skel, "open and load misc test skel"))
541                 goto skel_destroy;
542 
543         cg_fd = test__join_cgroup(CG_NAME);
544         if (!ASSERT_GE(cg_fd, 0, "join_cgroup"))
545                 goto skel_destroy;
546 
547         for (i = 0; i < ARRAY_SIZE(tests); i++) {
548                 if (!test__start_subtest(tests[i].desc))
549                         continue;
550 
551                 if (create_netns())
552                         break;
553 
554                 tests[i].run();
555 
556                 reset_test();
557         }
558 
559         close(cg_fd);
560 skel_destroy:
561         test_misc_tcp_hdr_options__destroy(misc_skel);
562         test_tcp_hdr_options__destroy(skel);
563 }
564 

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

kernel.org | git.kernel.org | LWN.net | Project Home | 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.

sflogo.php