1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 #include <netinet/in.h>
4 #include <linux/netfilter.h>
5
6 #include "test_progs.h"
7 #include "test_netfilter_link_attach.skel.h"
8
9 struct nf_link_test {
10 __u32 pf;
11 __u32 hooknum;
12 __s32 priority;
13 __u32 flags;
14
15 bool expect_success;
16 const char * const name;
17 };
18
19 static const struct nf_link_test nf_hook_link_tests[] = {
20 { .name = "allzero", },
21 { .pf = NFPROTO_NUMPROTO, .name = "invalid-pf", },
22 { .pf = NFPROTO_IPV4, .hooknum = 42, .name = "invalid-hooknum", },
23 { .pf = NFPROTO_IPV4, .priority = INT_MIN, .name = "invalid-priority-min", },
24 { .pf = NFPROTO_IPV4, .priority = INT_MAX, .name = "invalid-priority-max", },
25 { .pf = NFPROTO_IPV4, .flags = UINT_MAX, .name = "invalid-flags", },
26
27 { .pf = NFPROTO_INET, .priority = 1, .name = "invalid-inet-not-supported", },
28
29 {
30 .pf = NFPROTO_IPV4,
31 .hooknum = NF_INET_POST_ROUTING,
32 .priority = -10000,
33 .flags = 0,
34 .expect_success = true,
35 .name = "attach ipv4",
36 },
37 {
38 .pf = NFPROTO_IPV6,
39 .hooknum = NF_INET_FORWARD,
40 .priority = 10001,
41 .flags = BPF_F_NETFILTER_IP_DEFRAG,
42 .expect_success = true,
43 .name = "attach ipv6",
44 },
45 };
46
verify_netfilter_link_info(struct bpf_link * link,const struct nf_link_test nf_expected)47 static void verify_netfilter_link_info(struct bpf_link *link, const struct nf_link_test nf_expected)
48 {
49 struct bpf_link_info info;
50 __u32 len = sizeof(info);
51 int err, fd;
52
53 memset(&info, 0, len);
54
55 fd = bpf_link__fd(link);
56 err = bpf_link_get_info_by_fd(fd, &info, &len);
57 ASSERT_OK(err, "get_link_info");
58
59 ASSERT_EQ(info.type, BPF_LINK_TYPE_NETFILTER, "info link type");
60 ASSERT_EQ(info.netfilter.pf, nf_expected.pf, "info nf protocol family");
61 ASSERT_EQ(info.netfilter.hooknum, nf_expected.hooknum, "info nf hooknum");
62 ASSERT_EQ(info.netfilter.priority, nf_expected.priority, "info nf priority");
63 ASSERT_EQ(info.netfilter.flags, nf_expected.flags, "info nf flags");
64 }
65
test_netfilter_link_attach(void)66 void test_netfilter_link_attach(void)
67 {
68 struct test_netfilter_link_attach *skel;
69 struct bpf_program *prog;
70 LIBBPF_OPTS(bpf_netfilter_opts, opts);
71 int i;
72
73 skel = test_netfilter_link_attach__open_and_load();
74 if (!ASSERT_OK_PTR(skel, "test_netfilter_link_attach__open_and_load"))
75 goto out;
76
77 prog = skel->progs.nf_link_attach_test;
78 if (!ASSERT_OK_PTR(prog, "attach program"))
79 goto out;
80
81 for (i = 0; i < ARRAY_SIZE(nf_hook_link_tests); i++) {
82 struct bpf_link *link;
83
84 if (!test__start_subtest(nf_hook_link_tests[i].name))
85 continue;
86
87 #define X(opts, m, i) opts.m = nf_hook_link_tests[(i)].m
88 X(opts, pf, i);
89 X(opts, hooknum, i);
90 X(opts, priority, i);
91 X(opts, flags, i);
92 #undef X
93 link = bpf_program__attach_netfilter(prog, &opts);
94 if (nf_hook_link_tests[i].expect_success) {
95 struct bpf_link *link2;
96
97 if (!ASSERT_OK_PTR(link, "program attach successful"))
98 continue;
99
100 verify_netfilter_link_info(link, nf_hook_link_tests[i]);
101
102 link2 = bpf_program__attach_netfilter(prog, &opts);
103 ASSERT_ERR_PTR(link2, "attach program with same pf/hook/priority");
104
105 if (!ASSERT_OK(bpf_link__destroy(link), "link destroy"))
106 break;
107
108 link2 = bpf_program__attach_netfilter(prog, &opts);
109 if (!ASSERT_OK_PTR(link2, "program reattach successful"))
110 continue;
111
112 verify_netfilter_link_info(link2, nf_hook_link_tests[i]);
113
114 if (!ASSERT_OK(bpf_link__destroy(link2), "link destroy"))
115 break;
116 } else {
117 ASSERT_ERR_PTR(link, "program load failure");
118 }
119 }
120
121 out:
122 test_netfilter_link_attach__destroy(skel);
123 }
124
125