bpf/flow_dissector: support ipv6 flow_label and BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL
authorStanislav Fomichev <sdf@google.com>
Thu, 25 Jul 2019 22:52:30 +0000 (15:52 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 26 Jul 2019 01:00:41 +0000 (18:00 -0700)
Add support for exporting ipv6 flow label via bpf_flow_keys.
Export flow label from bpf_flow.c and also return early when
BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL is passed.

Acked-by: Petar Penkov <ppenkov@google.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Acked-by: Song Liu <songliubraving@fb.com>
Cc: Song Liu <songliubraving@fb.com>
Cc: Willem de Bruijn <willemb@google.com>
Cc: Petar Penkov <ppenkov@google.com>
Signed-off-by: Stanislav Fomichev <sdf@google.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
include/uapi/linux/bpf.h
net/core/flow_dissector.c
tools/include/uapi/linux/bpf.h
tools/testing/selftests/bpf/prog_tests/flow_dissector.c
tools/testing/selftests/bpf/progs/bpf_flow.c

index 88b9d743036f11f491f5238702f071ca4bf56a28..e985f07a98ed3346a3d9c4ec4b350d6cf09d9cda 100644 (file)
@@ -3533,6 +3533,7 @@ struct bpf_flow_keys {
                };
        };
        __u32   flags;
+       __be32  flow_label;
 };
 
 struct bpf_func_info {
index 50ed1a688709f5df9a42bb301d433532a8d6874a..9741b593ea5325aaa18a928ca91fb2b2d59dda15 100644 (file)
@@ -737,6 +737,7 @@ static void __skb_flow_bpf_to_target(const struct bpf_flow_keys *flow_keys,
        struct flow_dissector_key_basic *key_basic;
        struct flow_dissector_key_addrs *key_addrs;
        struct flow_dissector_key_ports *key_ports;
+       struct flow_dissector_key_tags *key_tags;
 
        key_control = skb_flow_dissector_target(flow_dissector,
                                                FLOW_DISSECTOR_KEY_CONTROL,
@@ -781,6 +782,14 @@ static void __skb_flow_bpf_to_target(const struct bpf_flow_keys *flow_keys,
                key_ports->src = flow_keys->sport;
                key_ports->dst = flow_keys->dport;
        }
+
+       if (dissector_uses_key(flow_dissector,
+                              FLOW_DISSECTOR_KEY_FLOW_LABEL)) {
+               key_tags = skb_flow_dissector_target(flow_dissector,
+                                                    FLOW_DISSECTOR_KEY_FLOW_LABEL,
+                                                    target_container);
+               key_tags->flow_label = ntohl(flow_keys->flow_label);
+       }
 }
 
 bool bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx,
index 2e4b0848d79527cdd57599f85b512d30593dd9ab..3d7fc67ec1b81b353cf82261e1d8174eb47dcfbb 100644 (file)
@@ -3530,6 +3530,7 @@ struct bpf_flow_keys {
                };
        };
        __u32   flags;
+       __be32  flow_label;
 };
 
 struct bpf_func_info {
index 8e8c18aced9b563d53192b4400ca1d06c57740e1..ef83f145a6f1b6c020dfd9ddd7679a826bf3ab6b 100644 (file)
@@ -20,6 +20,7 @@
              "is_encap=%u/%u "                                         \
              "ip_proto=0x%x/0x%x "                                     \
              "n_proto=0x%x/0x%x "                                      \
+             "flow_label=0x%x/0x%x "                                   \
              "sport=%u/%u "                                            \
              "dport=%u/%u\n",                                          \
              got.nhoff, expected.nhoff,                                \
@@ -30,6 +31,7 @@
              got.is_encap, expected.is_encap,                          \
              got.ip_proto, expected.ip_proto,                          \
              got.n_proto, expected.n_proto,                            \
+             got.flow_label, expected.flow_label,                      \
              got.sport, expected.sport,                                \
              got.dport, expected.dport)
 
@@ -257,6 +259,50 @@ struct test tests[] = {
                        .is_first_frag = true,
                },
        },
+       {
+               .name = "ipv6-flow-label",
+               .pkt.ipv6 = {
+                       .eth.h_proto = __bpf_constant_htons(ETH_P_IPV6),
+                       .iph.nexthdr = IPPROTO_TCP,
+                       .iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
+                       .iph.flow_lbl = { 0xb, 0xee, 0xef },
+                       .tcp.doff = 5,
+                       .tcp.source = 80,
+                       .tcp.dest = 8080,
+               },
+               .keys = {
+                       .nhoff = ETH_HLEN,
+                       .thoff = ETH_HLEN + sizeof(struct ipv6hdr),
+                       .addr_proto = ETH_P_IPV6,
+                       .ip_proto = IPPROTO_TCP,
+                       .n_proto = __bpf_constant_htons(ETH_P_IPV6),
+                       .sport = 80,
+                       .dport = 8080,
+                       .flow_label = __bpf_constant_htonl(0xbeeef),
+               },
+       },
+       {
+               .name = "ipv6-no-flow-label",
+               .pkt.ipv6 = {
+                       .eth.h_proto = __bpf_constant_htons(ETH_P_IPV6),
+                       .iph.nexthdr = IPPROTO_TCP,
+                       .iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
+                       .iph.flow_lbl = { 0xb, 0xee, 0xef },
+                       .tcp.doff = 5,
+                       .tcp.source = 80,
+                       .tcp.dest = 8080,
+               },
+               .keys = {
+                       .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL,
+                       .nhoff = ETH_HLEN,
+                       .thoff = ETH_HLEN + sizeof(struct ipv6hdr),
+                       .addr_proto = ETH_P_IPV6,
+                       .ip_proto = IPPROTO_TCP,
+                       .n_proto = __bpf_constant_htons(ETH_P_IPV6),
+                       .flow_label = __bpf_constant_htonl(0xbeeef),
+               },
+               .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL,
+       },
 };
 
 static int create_tap(const char *ifname)
index f931cd3db9d4981a6ff0e6d894a1d3cadd9d4034..7fbfa22f33dfdfe6f45e36e72fe41bf0c9ed7854 100644 (file)
@@ -83,6 +83,12 @@ static __always_inline int export_flow_keys(struct bpf_flow_keys *keys,
        return ret;
 }
 
+#define IPV6_FLOWLABEL_MASK            __bpf_constant_htonl(0x000FFFFF)
+static inline __be32 ip6_flowlabel(const struct ipv6hdr *hdr)
+{
+       return *(__be32 *)hdr & IPV6_FLOWLABEL_MASK;
+}
+
 static __always_inline void *bpf_flow_dissect_get_header(struct __sk_buff *skb,
                                                         __u16 hdr_size,
                                                         void *buffer)
@@ -308,6 +314,10 @@ PROG(IPV6)(struct __sk_buff *skb)
 
        keys->thoff += sizeof(struct ipv6hdr);
        keys->ip_proto = ip6h->nexthdr;
+       keys->flow_label = ip6_flowlabel(ip6h);
+
+       if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL)
+               return export_flow_keys(keys, BPF_OK);
 
        return parse_ipv6_proto(skb, ip6h->nexthdr);
 }