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