1 // SPDX-License-Identifier: GPL-2.0
2 #include <vmlinux.h>
3 #include <bpf/bpf_helpers.h>
4 
5 #define EAFNOSUPPORT 97
6 #define EPROTO 71
7 #define ENONET 64
8 #define EINVAL 22
9 #define ENOENT 2
10 
11 int test_einval_bpf_tuple = 0;
12 int test_einval_reserved = 0;
13 int test_einval_netns_id = 0;
14 int test_einval_len_opts = 0;
15 int test_eproto_l4proto = 0;
16 int test_enonet_netns_id = 0;
17 int test_enoent_lookup = 0;
18 int test_eafnosupport = 0;
19 
20 struct nf_conn;
21 
22 struct bpf_ct_opts___local {
23 	s32 netns_id;
24 	s32 error;
25 	u8 l4proto;
26 	u8 reserved[3];
27 } __attribute__((preserve_access_index));
28 
29 struct nf_conn *bpf_xdp_ct_lookup(struct xdp_md *, struct bpf_sock_tuple *, u32,
30 				  struct bpf_ct_opts___local *, u32) __ksym;
31 struct nf_conn *bpf_skb_ct_lookup(struct __sk_buff *, struct bpf_sock_tuple *, u32,
32 				  struct bpf_ct_opts___local *, u32) __ksym;
33 void bpf_ct_release(struct nf_conn *) __ksym;
34 
35 static __always_inline void
36 nf_ct_test(struct nf_conn *(*func)(void *, struct bpf_sock_tuple *, u32,
37 				   struct bpf_ct_opts___local *, u32),
38 	   void *ctx)
39 {
40 	struct bpf_ct_opts___local opts_def = { .l4proto = IPPROTO_TCP, .netns_id = -1 };
41 	struct bpf_sock_tuple bpf_tuple;
42 	struct nf_conn *ct;
43 
44 	__builtin_memset(&bpf_tuple, 0, sizeof(bpf_tuple.ipv4));
45 
46 	ct = func(ctx, NULL, 0, &opts_def, sizeof(opts_def));
47 	if (ct)
48 		bpf_ct_release(ct);
49 	else
50 		test_einval_bpf_tuple = opts_def.error;
51 
52 	opts_def.reserved[0] = 1;
53 	ct = func(ctx, &bpf_tuple, sizeof(bpf_tuple.ipv4), &opts_def, sizeof(opts_def));
54 	opts_def.reserved[0] = 0;
55 	opts_def.l4proto = IPPROTO_TCP;
56 	if (ct)
57 		bpf_ct_release(ct);
58 	else
59 		test_einval_reserved = opts_def.error;
60 
61 	opts_def.netns_id = -2;
62 	ct = func(ctx, &bpf_tuple, sizeof(bpf_tuple.ipv4), &opts_def, sizeof(opts_def));
63 	opts_def.netns_id = -1;
64 	if (ct)
65 		bpf_ct_release(ct);
66 	else
67 		test_einval_netns_id = opts_def.error;
68 
69 	ct = func(ctx, &bpf_tuple, sizeof(bpf_tuple.ipv4), &opts_def, sizeof(opts_def) - 1);
70 	if (ct)
71 		bpf_ct_release(ct);
72 	else
73 		test_einval_len_opts = opts_def.error;
74 
75 	opts_def.l4proto = IPPROTO_ICMP;
76 	ct = func(ctx, &bpf_tuple, sizeof(bpf_tuple.ipv4), &opts_def, sizeof(opts_def));
77 	opts_def.l4proto = IPPROTO_TCP;
78 	if (ct)
79 		bpf_ct_release(ct);
80 	else
81 		test_eproto_l4proto = opts_def.error;
82 
83 	opts_def.netns_id = 0xf00f;
84 	ct = func(ctx, &bpf_tuple, sizeof(bpf_tuple.ipv4), &opts_def, sizeof(opts_def));
85 	opts_def.netns_id = -1;
86 	if (ct)
87 		bpf_ct_release(ct);
88 	else
89 		test_enonet_netns_id = opts_def.error;
90 
91 	ct = func(ctx, &bpf_tuple, sizeof(bpf_tuple.ipv4), &opts_def, sizeof(opts_def));
92 	if (ct)
93 		bpf_ct_release(ct);
94 	else
95 		test_enoent_lookup = opts_def.error;
96 
97 	ct = func(ctx, &bpf_tuple, sizeof(bpf_tuple.ipv4) - 1, &opts_def, sizeof(opts_def));
98 	if (ct)
99 		bpf_ct_release(ct);
100 	else
101 		test_eafnosupport = opts_def.error;
102 }
103 
104 SEC("xdp")
105 int nf_xdp_ct_test(struct xdp_md *ctx)
106 {
107 	nf_ct_test((void *)bpf_xdp_ct_lookup, ctx);
108 	return 0;
109 }
110 
111 SEC("tc")
112 int nf_skb_ct_test(struct __sk_buff *ctx)
113 {
114 	nf_ct_test((void *)bpf_skb_ct_lookup, ctx);
115 	return 0;
116 }
117 
118 char _license[] SEC("license") = "GPL";
119