Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (c) 2020 Jesper Dangaard Brouer */
0003 
0004 #include <linux/bpf.h>
0005 #include <bpf/bpf_helpers.h>
0006 #include <linux/if_ether.h>
0007 
0008 #include <stddef.h>
0009 #include <stdint.h>
0010 
0011 char _license[] SEC("license") = "GPL";
0012 
0013 /* Userspace will update with MTU it can see on device */
0014 volatile const int GLOBAL_USER_MTU;
0015 volatile const __u32 GLOBAL_USER_IFINDEX;
0016 
0017 /* BPF-prog will update these with MTU values it can see */
0018 __u32 global_bpf_mtu_xdp = 0;
0019 __u32 global_bpf_mtu_tc  = 0;
0020 
0021 SEC("xdp")
0022 int xdp_use_helper_basic(struct xdp_md *ctx)
0023 {
0024     __u32 mtu_len = 0;
0025 
0026     if (bpf_check_mtu(ctx, 0, &mtu_len, 0, 0))
0027         return XDP_ABORTED;
0028 
0029     return XDP_PASS;
0030 }
0031 
0032 SEC("xdp")
0033 int xdp_use_helper(struct xdp_md *ctx)
0034 {
0035     int retval = XDP_PASS; /* Expected retval on successful test */
0036     __u32 mtu_len = 0;
0037     __u32 ifindex = 0;
0038     int delta = 0;
0039 
0040     /* When ifindex is zero, save net_device lookup and use ctx netdev */
0041     if (GLOBAL_USER_IFINDEX > 0)
0042         ifindex = GLOBAL_USER_IFINDEX;
0043 
0044     if (bpf_check_mtu(ctx, ifindex, &mtu_len, delta, 0)) {
0045         /* mtu_len is also valid when check fail */
0046         retval = XDP_ABORTED;
0047         goto out;
0048     }
0049 
0050     if (mtu_len != GLOBAL_USER_MTU)
0051         retval = XDP_DROP;
0052 
0053 out:
0054     global_bpf_mtu_xdp = mtu_len;
0055     return retval;
0056 }
0057 
0058 SEC("xdp")
0059 int xdp_exceed_mtu(struct xdp_md *ctx)
0060 {
0061     void *data_end = (void *)(long)ctx->data_end;
0062     void *data = (void *)(long)ctx->data;
0063     __u32 ifindex = GLOBAL_USER_IFINDEX;
0064     __u32 data_len = data_end - data;
0065     int retval = XDP_ABORTED; /* Fail */
0066     __u32 mtu_len = 0;
0067     int delta;
0068     int err;
0069 
0070     /* Exceed MTU with 1 via delta adjust */
0071     delta = GLOBAL_USER_MTU - (data_len - ETH_HLEN) + 1;
0072 
0073     err = bpf_check_mtu(ctx, ifindex, &mtu_len, delta, 0);
0074     if (err) {
0075         retval = XDP_PASS; /* Success in exceeding MTU check */
0076         if (err != BPF_MTU_CHK_RET_FRAG_NEEDED)
0077             retval = XDP_DROP;
0078     }
0079 
0080     global_bpf_mtu_xdp = mtu_len;
0081     return retval;
0082 }
0083 
0084 SEC("xdp")
0085 int xdp_minus_delta(struct xdp_md *ctx)
0086 {
0087     int retval = XDP_PASS; /* Expected retval on successful test */
0088     void *data_end = (void *)(long)ctx->data_end;
0089     void *data = (void *)(long)ctx->data;
0090     __u32 ifindex = GLOBAL_USER_IFINDEX;
0091     __u32 data_len = data_end - data;
0092     __u32 mtu_len = 0;
0093     int delta;
0094 
0095     /* Borderline test case: Minus delta exceeding packet length allowed */
0096     delta = -((data_len - ETH_HLEN) + 1);
0097 
0098     /* Minus length (adjusted via delta) still pass MTU check, other helpers
0099      * are responsible for catching this, when doing actual size adjust
0100      */
0101     if (bpf_check_mtu(ctx, ifindex, &mtu_len, delta, 0))
0102         retval = XDP_ABORTED;
0103 
0104     global_bpf_mtu_xdp = mtu_len;
0105     return retval;
0106 }
0107 
0108 SEC("xdp")
0109 int xdp_input_len(struct xdp_md *ctx)
0110 {
0111     int retval = XDP_PASS; /* Expected retval on successful test */
0112     void *data_end = (void *)(long)ctx->data_end;
0113     void *data = (void *)(long)ctx->data;
0114     __u32 ifindex = GLOBAL_USER_IFINDEX;
0115     __u32 data_len = data_end - data;
0116 
0117     /* API allow user give length to check as input via mtu_len param,
0118      * resulting MTU value is still output in mtu_len param after call.
0119      *
0120      * Input len is L3, like MTU and iph->tot_len.
0121      * Remember XDP data_len is L2.
0122      */
0123     __u32 mtu_len = data_len - ETH_HLEN;
0124 
0125     if (bpf_check_mtu(ctx, ifindex, &mtu_len, 0, 0))
0126         retval = XDP_ABORTED;
0127 
0128     global_bpf_mtu_xdp = mtu_len;
0129     return retval;
0130 }
0131 
0132 SEC("xdp")
0133 int xdp_input_len_exceed(struct xdp_md *ctx)
0134 {
0135     int retval = XDP_ABORTED; /* Fail */
0136     __u32 ifindex = GLOBAL_USER_IFINDEX;
0137     int err;
0138 
0139     /* API allow user give length to check as input via mtu_len param,
0140      * resulting MTU value is still output in mtu_len param after call.
0141      *
0142      * Input length value is L3 size like MTU.
0143      */
0144     __u32 mtu_len = GLOBAL_USER_MTU;
0145 
0146     mtu_len += 1; /* Exceed with 1 */
0147 
0148     err = bpf_check_mtu(ctx, ifindex, &mtu_len, 0, 0);
0149     if (err == BPF_MTU_CHK_RET_FRAG_NEEDED)
0150         retval = XDP_PASS ; /* Success in exceeding MTU check */
0151 
0152     global_bpf_mtu_xdp = mtu_len;
0153     return retval;
0154 }
0155 
0156 SEC("tc")
0157 int tc_use_helper(struct __sk_buff *ctx)
0158 {
0159     int retval = BPF_OK; /* Expected retval on successful test */
0160     __u32 mtu_len = 0;
0161     int delta = 0;
0162 
0163     if (bpf_check_mtu(ctx, 0, &mtu_len, delta, 0)) {
0164         retval = BPF_DROP;
0165         goto out;
0166     }
0167 
0168     if (mtu_len != GLOBAL_USER_MTU)
0169         retval = BPF_REDIRECT;
0170 out:
0171     global_bpf_mtu_tc = mtu_len;
0172     return retval;
0173 }
0174 
0175 SEC("tc")
0176 int tc_exceed_mtu(struct __sk_buff *ctx)
0177 {
0178     __u32 ifindex = GLOBAL_USER_IFINDEX;
0179     int retval = BPF_DROP; /* Fail */
0180     __u32 skb_len = ctx->len;
0181     __u32 mtu_len = 0;
0182     int delta;
0183     int err;
0184 
0185     /* Exceed MTU with 1 via delta adjust */
0186     delta = GLOBAL_USER_MTU - (skb_len - ETH_HLEN) + 1;
0187 
0188     err = bpf_check_mtu(ctx, ifindex, &mtu_len, delta, 0);
0189     if (err) {
0190         retval = BPF_OK; /* Success in exceeding MTU check */
0191         if (err != BPF_MTU_CHK_RET_FRAG_NEEDED)
0192             retval = BPF_DROP;
0193     }
0194 
0195     global_bpf_mtu_tc = mtu_len;
0196     return retval;
0197 }
0198 
0199 SEC("tc")
0200 int tc_exceed_mtu_da(struct __sk_buff *ctx)
0201 {
0202     /* SKB Direct-Access variant */
0203     void *data_end = (void *)(long)ctx->data_end;
0204     void *data = (void *)(long)ctx->data;
0205     __u32 ifindex = GLOBAL_USER_IFINDEX;
0206     __u32 data_len = data_end - data;
0207     int retval = BPF_DROP; /* Fail */
0208     __u32 mtu_len = 0;
0209     int delta;
0210     int err;
0211 
0212     /* Exceed MTU with 1 via delta adjust */
0213     delta = GLOBAL_USER_MTU - (data_len - ETH_HLEN) + 1;
0214 
0215     err = bpf_check_mtu(ctx, ifindex, &mtu_len, delta, 0);
0216     if (err) {
0217         retval = BPF_OK; /* Success in exceeding MTU check */
0218         if (err != BPF_MTU_CHK_RET_FRAG_NEEDED)
0219             retval = BPF_DROP;
0220     }
0221 
0222     global_bpf_mtu_tc = mtu_len;
0223     return retval;
0224 }
0225 
0226 SEC("tc")
0227 int tc_minus_delta(struct __sk_buff *ctx)
0228 {
0229     int retval = BPF_OK; /* Expected retval on successful test */
0230     __u32 ifindex = GLOBAL_USER_IFINDEX;
0231     __u32 skb_len = ctx->len;
0232     __u32 mtu_len = 0;
0233     int delta;
0234 
0235     /* Borderline test case: Minus delta exceeding packet length allowed */
0236     delta = -((skb_len - ETH_HLEN) + 1);
0237 
0238     /* Minus length (adjusted via delta) still pass MTU check, other helpers
0239      * are responsible for catching this, when doing actual size adjust
0240      */
0241     if (bpf_check_mtu(ctx, ifindex, &mtu_len, delta, 0))
0242         retval = BPF_DROP;
0243 
0244     global_bpf_mtu_xdp = mtu_len;
0245     return retval;
0246 }
0247 
0248 SEC("tc")
0249 int tc_input_len(struct __sk_buff *ctx)
0250 {
0251     int retval = BPF_OK; /* Expected retval on successful test */
0252     __u32 ifindex = GLOBAL_USER_IFINDEX;
0253 
0254     /* API allow user give length to check as input via mtu_len param,
0255      * resulting MTU value is still output in mtu_len param after call.
0256      *
0257      * Input length value is L3 size.
0258      */
0259     __u32 mtu_len = GLOBAL_USER_MTU;
0260 
0261     if (bpf_check_mtu(ctx, ifindex, &mtu_len, 0, 0))
0262         retval = BPF_DROP;
0263 
0264     global_bpf_mtu_xdp = mtu_len;
0265     return retval;
0266 }
0267 
0268 SEC("tc")
0269 int tc_input_len_exceed(struct __sk_buff *ctx)
0270 {
0271     int retval = BPF_DROP; /* Fail */
0272     __u32 ifindex = GLOBAL_USER_IFINDEX;
0273     int err;
0274 
0275     /* API allow user give length to check as input via mtu_len param,
0276      * resulting MTU value is still output in mtu_len param after call.
0277      *
0278      * Input length value is L3 size like MTU.
0279      */
0280     __u32 mtu_len = GLOBAL_USER_MTU;
0281 
0282     mtu_len += 1; /* Exceed with 1 */
0283 
0284     err = bpf_check_mtu(ctx, ifindex, &mtu_len, 0, 0);
0285     if (err == BPF_MTU_CHK_RET_FRAG_NEEDED)
0286         retval = BPF_OK; /* Success in exceeding MTU check */
0287 
0288     global_bpf_mtu_xdp = mtu_len;
0289     return retval;
0290 }