bpf: support flow label for bpf_skb_{set, get}_tunnel_key
authorDaniel Borkmann <daniel@iogearbox.net>
Wed, 9 Mar 2016 02:00:05 +0000 (03:00 +0100)
committerDavid S. Miller <davem@davemloft.net>
Fri, 11 Mar 2016 20:14:27 +0000 (15:14 -0500)
This patch extends bpf_tunnel_key with a tunnel_label member, that maps
to ip_tunnel_key's label so underlying backends like vxlan and geneve
can propagate the label to udp_tunnel6_xmit_skb(), where it's being set
in the IPv6 header. It allows for having 20 more bits to encode/decode
flow related meta information programmatically. Tested with vxlan and
geneve.

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 0e30b19012a5688cab5fd1b81381c144940b5690..924f537183fd2f368f4b557df7158537f8416a3b 100644 (file)
@@ -375,6 +375,7 @@ struct bpf_tunnel_key {
        };
        __u8 tunnel_tos;
        __u8 tunnel_ttl;
+       __u32 tunnel_label;
 };
 
 #endif /* _UAPI__LINUX_BPF_H__ */
index a66dc03c261f4f4d3248b6a2b508fad05c989bfa..6fc3893a6170517d3e41f3b4243bf76af5f55bcf 100644 (file)
@@ -1770,12 +1770,15 @@ static u64 bpf_skb_get_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
                return -EPROTO;
        if (unlikely(size != sizeof(struct bpf_tunnel_key))) {
                switch (size) {
+               case offsetof(struct bpf_tunnel_key, tunnel_label):
+                       goto set_compat;
                case offsetof(struct bpf_tunnel_key, remote_ipv6[1]):
                        /* Fixup deprecated structure layouts here, so we have
                         * a common path later on.
                         */
                        if (ip_tunnel_info_af(info) != AF_INET)
                                return -EINVAL;
+set_compat:
                        to = (struct bpf_tunnel_key *)compat;
                        break;
                default:
@@ -1787,11 +1790,13 @@ static u64 bpf_skb_get_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
        to->tunnel_tos = info->key.tos;
        to->tunnel_ttl = info->key.ttl;
 
-       if (flags & BPF_F_TUNINFO_IPV6)
+       if (flags & BPF_F_TUNINFO_IPV6) {
                memcpy(to->remote_ipv6, &info->key.u.ipv6.src,
                       sizeof(to->remote_ipv6));
-       else
+               to->tunnel_label = be32_to_cpu(info->key.label);
+       } else {
                to->remote_ipv4 = be32_to_cpu(info->key.u.ipv4.src);
+       }
 
        if (unlikely(size != sizeof(struct bpf_tunnel_key)))
                memcpy((void *)(long) r2, to, size);
@@ -1850,6 +1855,7 @@ static u64 bpf_skb_set_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
                return -EINVAL;
        if (unlikely(size != sizeof(struct bpf_tunnel_key))) {
                switch (size) {
+               case offsetof(struct bpf_tunnel_key, tunnel_label):
                case offsetof(struct bpf_tunnel_key, remote_ipv6[1]):
                        /* Fixup deprecated structure layouts here, so we have
                         * a common path later on.
@@ -1862,6 +1868,8 @@ static u64 bpf_skb_set_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
                        return -EINVAL;
                }
        }
+       if (unlikely(!(flags & BPF_F_TUNINFO_IPV6) && from->tunnel_label))
+               return -EINVAL;
 
        skb_dst_drop(skb);
        dst_hold((struct dst_entry *) md);
@@ -1882,6 +1890,8 @@ static u64 bpf_skb_set_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
                info->mode |= IP_TUNNEL_INFO_IPV6;
                memcpy(&info->key.u.ipv6.dst, from->remote_ipv6,
                       sizeof(from->remote_ipv6));
+               info->key.label = cpu_to_be32(from->tunnel_label) &
+                                 IPV6_FLOWLABEL_MASK;
        } else {
                info->key.u.ipv4.dst = cpu_to_be32(from->remote_ipv4);
                if (flags & BPF_F_ZERO_CSUM_TX)