bpf: allow option for setting bpf_l4_csum_replace from scratch
authorDaniel Borkmann <daniel@iogearbox.net>
Tue, 24 Jan 2017 00:06:28 +0000 (01:06 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 24 Jan 2017 19:46:06 +0000 (14:46 -0500)
When programs need to calculate the csum from scratch for small UDP
packets and use bpf_l4_csum_replace() to feed the result from helpers
like bpf_csum_diff(), then we need a flag besides BPF_F_MARK_MANGLED_0
that would ignore the case of current csum being 0, and which would
still allow for the helper to set the csum and transform when needed
to CSUM_MANGLED_0.

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/uapi/linux/bpf.h
net/core/filter.c

index bd30684..e07fd5a 100644 (file)
@@ -522,6 +522,7 @@ enum bpf_func_id {
 /* BPF_FUNC_l4_csum_replace flags. */
 #define BPF_F_PSEUDO_HDR               (1ULL << 4)
 #define BPF_F_MARK_MANGLED_0           (1ULL << 5)
+#define BPF_F_MARK_ENFORCE             (1ULL << 6)
 
 /* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */
 #define BPF_F_INGRESS                  (1ULL << 0)
index e2263da..1e00737 100644 (file)
@@ -1522,10 +1522,11 @@ BPF_CALL_5(bpf_l4_csum_replace, struct sk_buff *, skb, u32, offset,
 {
        bool is_pseudo = flags & BPF_F_PSEUDO_HDR;
        bool is_mmzero = flags & BPF_F_MARK_MANGLED_0;
+       bool do_mforce = flags & BPF_F_MARK_ENFORCE;
        __sum16 *ptr;
 
-       if (unlikely(flags & ~(BPF_F_MARK_MANGLED_0 | BPF_F_PSEUDO_HDR |
-                              BPF_F_HDR_FIELD_MASK)))
+       if (unlikely(flags & ~(BPF_F_MARK_MANGLED_0 | BPF_F_MARK_ENFORCE |
+                              BPF_F_PSEUDO_HDR | BPF_F_HDR_FIELD_MASK)))
                return -EINVAL;
        if (unlikely(offset > 0xffff || offset & 1))
                return -EFAULT;
@@ -1533,7 +1534,7 @@ BPF_CALL_5(bpf_l4_csum_replace, struct sk_buff *, skb, u32, offset,
                return -EFAULT;
 
        ptr = (__sum16 *)(skb->data + offset);
-       if (is_mmzero && !*ptr)
+       if (is_mmzero && !do_mforce && !*ptr)
                return 0;
 
        switch (flags & BPF_F_HDR_FIELD_MASK) {