Commit e5e35e75 authored by Jesper Dangaard Brouer's avatar Jesper Dangaard Brouer Committed by Daniel Borkmann

bpf: BPF-helper for MTU checking add length input

The FIB lookup example[1] show how the IP-header field tot_len
(iph->tot_len) is used as input to perform the MTU check.

This patch extend the BPF-helper bpf_check_mtu() with the same ability
to provide the length as user parameter input, via mtu_len parameter.

This still needs to be done before the bpf_check_mtu() helper API
becomes frozen.

  [1] samples/bpf/xdp_fwd_kern.c

Fixes: 34b2021c ("bpf: Add BPF-helper for MTU checking")
Signed-off-by: default avatarJesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarJohn Fastabend <john.fastabend@gmail.com>
Link: https://lore.kernel.org/bpf/161521555850.3515614.6533850861569774444.stgit@firesoul
parent e7fb6465
...@@ -3850,7 +3850,7 @@ union bpf_attr { ...@@ -3850,7 +3850,7 @@ union bpf_attr {
* *
* long bpf_check_mtu(void *ctx, u32 ifindex, u32 *mtu_len, s32 len_diff, u64 flags) * long bpf_check_mtu(void *ctx, u32 ifindex, u32 *mtu_len, s32 len_diff, u64 flags)
* Description * Description
* Check ctx packet size against exceeding MTU of net device (based * Check packet size against exceeding MTU of net device (based
* on *ifindex*). This helper will likely be used in combination * on *ifindex*). This helper will likely be used in combination
* with helpers that adjust/change the packet size. * with helpers that adjust/change the packet size.
* *
...@@ -3867,6 +3867,14 @@ union bpf_attr { ...@@ -3867,6 +3867,14 @@ union bpf_attr {
* against the current net device. This is practical if this isn't * against the current net device. This is practical if this isn't
* used prior to redirect. * used prior to redirect.
* *
* On input *mtu_len* must be a valid pointer, else verifier will
* reject BPF program. If the value *mtu_len* is initialized to
* zero then the ctx packet size is use. When value *mtu_len* is
* provided as input this specify the L3 length that the MTU check
* is done against. Remember XDP and TC length operate at L2, but
* this value is L3 as this correlate to MTU and IP-header tot_len
* values which are L3 (similar behavior as bpf_fib_lookup).
*
* The Linux kernel route table can configure MTUs on a more * The Linux kernel route table can configure MTUs on a more
* specific per route level, which is not provided by this helper. * specific per route level, which is not provided by this helper.
* For route level MTU checks use the **bpf_fib_lookup**\ () * For route level MTU checks use the **bpf_fib_lookup**\ ()
...@@ -3891,11 +3899,9 @@ union bpf_attr { ...@@ -3891,11 +3899,9 @@ union bpf_attr {
* *
* On return *mtu_len* pointer contains the MTU value of the net * On return *mtu_len* pointer contains the MTU value of the net
* device. Remember the net device configured MTU is the L3 size, * device. Remember the net device configured MTU is the L3 size,
* which is returned here and XDP and TX length operate at L2. * which is returned here and XDP and TC length operate at L2.
* Helper take this into account for you, but remember when using * Helper take this into account for you, but remember when using
* MTU value in your BPF-code. On input *mtu_len* must be a valid * MTU value in your BPF-code.
* pointer and be initialized (to zero), else verifier will reject
* BPF program.
* *
* Return * Return
* * 0 on success, and populate MTU value in *mtu_len* pointer. * * 0 on success, and populate MTU value in *mtu_len* pointer.
......
...@@ -5658,7 +5658,7 @@ BPF_CALL_5(bpf_skb_check_mtu, struct sk_buff *, skb, ...@@ -5658,7 +5658,7 @@ BPF_CALL_5(bpf_skb_check_mtu, struct sk_buff *, skb,
if (unlikely(flags & ~(BPF_MTU_CHK_SEGS))) if (unlikely(flags & ~(BPF_MTU_CHK_SEGS)))
return -EINVAL; return -EINVAL;
if (unlikely(flags & BPF_MTU_CHK_SEGS && len_diff)) if (unlikely(flags & BPF_MTU_CHK_SEGS && (len_diff || *mtu_len)))
return -EINVAL; return -EINVAL;
dev = __dev_via_ifindex(dev, ifindex); dev = __dev_via_ifindex(dev, ifindex);
...@@ -5668,7 +5668,11 @@ BPF_CALL_5(bpf_skb_check_mtu, struct sk_buff *, skb, ...@@ -5668,7 +5668,11 @@ BPF_CALL_5(bpf_skb_check_mtu, struct sk_buff *, skb,
mtu = READ_ONCE(dev->mtu); mtu = READ_ONCE(dev->mtu);
dev_len = mtu + dev->hard_header_len; dev_len = mtu + dev->hard_header_len;
skb_len = skb->len + len_diff; /* minus result pass check */
/* If set use *mtu_len as input, L3 as iph->tot_len (like fib_lookup) */
skb_len = *mtu_len ? *mtu_len + dev->hard_header_len : skb->len;
skb_len += len_diff; /* minus result pass check */
if (skb_len <= dev_len) { if (skb_len <= dev_len) {
ret = BPF_MTU_CHK_RET_SUCCESS; ret = BPF_MTU_CHK_RET_SUCCESS;
goto out; goto out;
...@@ -5713,6 +5717,10 @@ BPF_CALL_5(bpf_xdp_check_mtu, struct xdp_buff *, xdp, ...@@ -5713,6 +5717,10 @@ BPF_CALL_5(bpf_xdp_check_mtu, struct xdp_buff *, xdp,
/* Add L2-header as dev MTU is L3 size */ /* Add L2-header as dev MTU is L3 size */
dev_len = mtu + dev->hard_header_len; dev_len = mtu + dev->hard_header_len;
/* Use *mtu_len as input, L3 as iph->tot_len (like fib_lookup) */
if (*mtu_len)
xdp_len = *mtu_len + dev->hard_header_len;
xdp_len += len_diff; /* minus result pass check */ xdp_len += len_diff; /* minus result pass check */
if (xdp_len > dev_len) if (xdp_len > dev_len)
ret = BPF_MTU_CHK_RET_FRAG_NEEDED; ret = BPF_MTU_CHK_RET_FRAG_NEEDED;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment