]> Git Repo - linux.git/blob - tools/testing/selftests/bpf/progs/test_check_mtu.c
Linux 6.14-rc3
[linux.git] / tools / testing / selftests / bpf / progs / test_check_mtu.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2020 Jesper Dangaard Brouer */
3
4 #include <linux/bpf.h>
5 #include <bpf/bpf_helpers.h>
6 #include <linux/if_ether.h>
7
8 #include <stddef.h>
9 #include <stdint.h>
10
11 char _license[] SEC("license") = "GPL";
12
13 /* Userspace will update with MTU it can see on device */
14 volatile const int GLOBAL_USER_MTU;
15 volatile const __u32 GLOBAL_USER_IFINDEX;
16
17 /* BPF-prog will update these with MTU values it can see */
18 __u32 global_bpf_mtu_xdp = 0;
19 __u32 global_bpf_mtu_tc  = 0;
20
21 SEC("xdp")
22 int xdp_use_helper_basic(struct xdp_md *ctx)
23 {
24         __u32 mtu_len = 0;
25
26         if (bpf_check_mtu(ctx, 0, &mtu_len, 0, 0))
27                 return XDP_ABORTED;
28
29         return XDP_PASS;
30 }
31
32 SEC("xdp")
33 int xdp_use_helper(struct xdp_md *ctx)
34 {
35         int retval = XDP_PASS; /* Expected retval on successful test */
36         __u32 mtu_len = 0;
37         __u32 ifindex = 0;
38         int delta = 0;
39
40         /* When ifindex is zero, save net_device lookup and use ctx netdev */
41         if (GLOBAL_USER_IFINDEX > 0)
42                 ifindex = GLOBAL_USER_IFINDEX;
43
44         if (bpf_check_mtu(ctx, ifindex, &mtu_len, delta, 0)) {
45                 /* mtu_len is also valid when check fail */
46                 retval = XDP_ABORTED;
47                 goto out;
48         }
49
50         if (mtu_len != GLOBAL_USER_MTU)
51                 retval = XDP_DROP;
52
53 out:
54         global_bpf_mtu_xdp = mtu_len;
55         return retval;
56 }
57
58 SEC("xdp")
59 int xdp_exceed_mtu(struct xdp_md *ctx)
60 {
61         void *data_end = (void *)(long)ctx->data_end;
62         void *data = (void *)(long)ctx->data;
63         __u32 ifindex = GLOBAL_USER_IFINDEX;
64         __u32 data_len = data_end - data;
65         int retval = XDP_ABORTED; /* Fail */
66         __u32 mtu_len = 0;
67         int delta;
68         int err;
69
70         /* Exceed MTU with 1 via delta adjust */
71         delta = GLOBAL_USER_MTU - (data_len - ETH_HLEN) + 1;
72
73         err = bpf_check_mtu(ctx, ifindex, &mtu_len, delta, 0);
74         if (err) {
75                 retval = XDP_PASS; /* Success in exceeding MTU check */
76                 if (err != BPF_MTU_CHK_RET_FRAG_NEEDED)
77                         retval = XDP_DROP;
78         }
79
80         global_bpf_mtu_xdp = mtu_len;
81         return retval;
82 }
83
84 SEC("xdp")
85 int xdp_minus_delta(struct xdp_md *ctx)
86 {
87         int retval = XDP_PASS; /* Expected retval on successful test */
88         void *data_end = (void *)(long)ctx->data_end;
89         void *data = (void *)(long)ctx->data;
90         __u32 ifindex = GLOBAL_USER_IFINDEX;
91         __u32 data_len = data_end - data;
92         __u32 mtu_len = 0;
93         int delta;
94
95         /* Borderline test case: Minus delta exceeding packet length allowed */
96         delta = -((data_len - ETH_HLEN) + 1);
97
98         /* Minus length (adjusted via delta) still pass MTU check, other helpers
99          * are responsible for catching this, when doing actual size adjust
100          */
101         if (bpf_check_mtu(ctx, ifindex, &mtu_len, delta, 0))
102                 retval = XDP_ABORTED;
103
104         global_bpf_mtu_xdp = mtu_len;
105         return retval;
106 }
107
108 SEC("xdp")
109 int xdp_input_len(struct xdp_md *ctx)
110 {
111         int retval = XDP_PASS; /* Expected retval on successful test */
112         void *data_end = (void *)(long)ctx->data_end;
113         void *data = (void *)(long)ctx->data;
114         __u32 ifindex = GLOBAL_USER_IFINDEX;
115         __u32 data_len = data_end - data;
116
117         /* API allow user give length to check as input via mtu_len param,
118          * resulting MTU value is still output in mtu_len param after call.
119          *
120          * Input len is L3, like MTU and iph->tot_len.
121          * Remember XDP data_len is L2.
122          */
123         __u32 mtu_len = data_len - ETH_HLEN;
124
125         if (bpf_check_mtu(ctx, ifindex, &mtu_len, 0, 0))
126                 retval = XDP_ABORTED;
127
128         global_bpf_mtu_xdp = mtu_len;
129         return retval;
130 }
131
132 SEC("xdp")
133 int xdp_input_len_exceed(struct xdp_md *ctx)
134 {
135         int retval = XDP_ABORTED; /* Fail */
136         __u32 ifindex = GLOBAL_USER_IFINDEX;
137         int err;
138
139         /* API allow user give length to check as input via mtu_len param,
140          * resulting MTU value is still output in mtu_len param after call.
141          *
142          * Input length value is L3 size like MTU.
143          */
144         __u32 mtu_len = GLOBAL_USER_MTU;
145
146         mtu_len += 1; /* Exceed with 1 */
147
148         err = bpf_check_mtu(ctx, ifindex, &mtu_len, 0, 0);
149         if (err == BPF_MTU_CHK_RET_FRAG_NEEDED)
150                 retval = XDP_PASS ; /* Success in exceeding MTU check */
151
152         global_bpf_mtu_xdp = mtu_len;
153         return retval;
154 }
155
156 SEC("tc")
157 int tc_use_helper(struct __sk_buff *ctx)
158 {
159         int retval = BPF_OK; /* Expected retval on successful test */
160         __u32 mtu_len = 0;
161         int delta = 0;
162
163         if (bpf_check_mtu(ctx, 0, &mtu_len, delta, 0)) {
164                 retval = BPF_DROP;
165                 goto out;
166         }
167
168         if (mtu_len != GLOBAL_USER_MTU)
169                 retval = BPF_REDIRECT;
170 out:
171         global_bpf_mtu_tc = mtu_len;
172         return retval;
173 }
174
175 SEC("tc")
176 int tc_exceed_mtu(struct __sk_buff *ctx)
177 {
178         __u32 ifindex = GLOBAL_USER_IFINDEX;
179         int retval = BPF_DROP; /* Fail */
180         __u32 skb_len = ctx->len;
181         __u32 mtu_len = 0;
182         int delta;
183         int err;
184
185         /* Exceed MTU with 1 via delta adjust */
186         delta = GLOBAL_USER_MTU - (skb_len - ETH_HLEN) + 1;
187
188         err = bpf_check_mtu(ctx, ifindex, &mtu_len, delta, 0);
189         if (err) {
190                 retval = BPF_OK; /* Success in exceeding MTU check */
191                 if (err != BPF_MTU_CHK_RET_FRAG_NEEDED)
192                         retval = BPF_DROP;
193         }
194
195         global_bpf_mtu_tc = mtu_len;
196         return retval;
197 }
198
199 SEC("tc")
200 int tc_exceed_mtu_da(struct __sk_buff *ctx)
201 {
202         /* SKB Direct-Access variant */
203         void *data_end = (void *)(long)ctx->data_end;
204         void *data = (void *)(long)ctx->data;
205         __u32 ifindex = GLOBAL_USER_IFINDEX;
206         __u32 data_len = data_end - data;
207         int retval = BPF_DROP; /* Fail */
208         __u32 mtu_len = 0;
209         int delta;
210         int err;
211
212         /* Exceed MTU with 1 via delta adjust */
213         delta = GLOBAL_USER_MTU - (data_len - ETH_HLEN) + 1;
214
215         err = bpf_check_mtu(ctx, ifindex, &mtu_len, delta, 0);
216         if (err) {
217                 retval = BPF_OK; /* Success in exceeding MTU check */
218                 if (err != BPF_MTU_CHK_RET_FRAG_NEEDED)
219                         retval = BPF_DROP;
220         }
221
222         global_bpf_mtu_tc = mtu_len;
223         return retval;
224 }
225
226 SEC("tc")
227 int tc_minus_delta(struct __sk_buff *ctx)
228 {
229         int retval = BPF_OK; /* Expected retval on successful test */
230         __u32 ifindex = GLOBAL_USER_IFINDEX;
231         __u32 skb_len = ctx->len;
232         __u32 mtu_len = 0;
233         int delta;
234
235         /* Borderline test case: Minus delta exceeding packet length allowed */
236         delta = -((skb_len - ETH_HLEN) + 1);
237
238         /* Minus length (adjusted via delta) still pass MTU check, other helpers
239          * are responsible for catching this, when doing actual size adjust
240          */
241         if (bpf_check_mtu(ctx, ifindex, &mtu_len, delta, 0))
242                 retval = BPF_DROP;
243
244         global_bpf_mtu_xdp = mtu_len;
245         return retval;
246 }
247
248 SEC("tc")
249 int tc_input_len(struct __sk_buff *ctx)
250 {
251         int retval = BPF_OK; /* Expected retval on successful test */
252         __u32 ifindex = GLOBAL_USER_IFINDEX;
253
254         /* API allow user give length to check as input via mtu_len param,
255          * resulting MTU value is still output in mtu_len param after call.
256          *
257          * Input length value is L3 size.
258          */
259         __u32 mtu_len = GLOBAL_USER_MTU;
260
261         if (bpf_check_mtu(ctx, ifindex, &mtu_len, 0, 0))
262                 retval = BPF_DROP;
263
264         global_bpf_mtu_xdp = mtu_len;
265         return retval;
266 }
267
268 SEC("tc")
269 int tc_input_len_exceed(struct __sk_buff *ctx)
270 {
271         int retval = BPF_DROP; /* Fail */
272         __u32 ifindex = GLOBAL_USER_IFINDEX;
273         int err;
274
275         /* API allow user give length to check as input via mtu_len param,
276          * resulting MTU value is still output in mtu_len param after call.
277          *
278          * Input length value is L3 size like MTU.
279          */
280         __u32 mtu_len = GLOBAL_USER_MTU;
281
282         mtu_len += 1; /* Exceed with 1 */
283
284         err = bpf_check_mtu(ctx, ifindex, &mtu_len, 0, 0);
285         if (err == BPF_MTU_CHK_RET_FRAG_NEEDED)
286                 retval = BPF_OK; /* Success in exceeding MTU check */
287
288         global_bpf_mtu_xdp = mtu_len;
289         return retval;
290 }
This page took 0.049539 seconds and 4 git commands to generate.