diff options
author | Stanislav Fomichev <sdf@google.com> | 2019-07-25 18:52:30 -0400 |
---|---|---|
committer | Alexei Starovoitov <ast@kernel.org> | 2019-07-25 21:00:41 -0400 |
commit | 71c99e32b926159ea628352751f66383d7d04d17 (patch) | |
tree | 6a2b488c1d184b9ce514deb7187ab9b0130a270c | |
parent | ae173a915785e55574c1fc54edf58b9b87b28c22 (diff) |
bpf/flow_dissector: support ipv6 flow_label and BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL
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>
-rw-r--r-- | include/uapi/linux/bpf.h | 1 | ||||
-rw-r--r-- | net/core/flow_dissector.c | 9 | ||||
-rw-r--r-- | tools/include/uapi/linux/bpf.h | 1 | ||||
-rw-r--r-- | tools/testing/selftests/bpf/prog_tests/flow_dissector.c | 46 | ||||
-rw-r--r-- | tools/testing/selftests/bpf/progs/bpf_flow.c | 10 |
5 files changed, 67 insertions, 0 deletions
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 88b9d743036f..e985f07a98ed 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h | |||
@@ -3533,6 +3533,7 @@ struct bpf_flow_keys { | |||
3533 | }; | 3533 | }; |
3534 | }; | 3534 | }; |
3535 | __u32 flags; | 3535 | __u32 flags; |
3536 | __be32 flow_label; | ||
3536 | }; | 3537 | }; |
3537 | 3538 | ||
3538 | struct bpf_func_info { | 3539 | struct bpf_func_info { |
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 50ed1a688709..9741b593ea53 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c | |||
@@ -737,6 +737,7 @@ static void __skb_flow_bpf_to_target(const struct bpf_flow_keys *flow_keys, | |||
737 | struct flow_dissector_key_basic *key_basic; | 737 | struct flow_dissector_key_basic *key_basic; |
738 | struct flow_dissector_key_addrs *key_addrs; | 738 | struct flow_dissector_key_addrs *key_addrs; |
739 | struct flow_dissector_key_ports *key_ports; | 739 | struct flow_dissector_key_ports *key_ports; |
740 | struct flow_dissector_key_tags *key_tags; | ||
740 | 741 | ||
741 | key_control = skb_flow_dissector_target(flow_dissector, | 742 | key_control = skb_flow_dissector_target(flow_dissector, |
742 | FLOW_DISSECTOR_KEY_CONTROL, | 743 | FLOW_DISSECTOR_KEY_CONTROL, |
@@ -781,6 +782,14 @@ static void __skb_flow_bpf_to_target(const struct bpf_flow_keys *flow_keys, | |||
781 | key_ports->src = flow_keys->sport; | 782 | key_ports->src = flow_keys->sport; |
782 | key_ports->dst = flow_keys->dport; | 783 | key_ports->dst = flow_keys->dport; |
783 | } | 784 | } |
785 | |||
786 | if (dissector_uses_key(flow_dissector, | ||
787 | FLOW_DISSECTOR_KEY_FLOW_LABEL)) { | ||
788 | key_tags = skb_flow_dissector_target(flow_dissector, | ||
789 | FLOW_DISSECTOR_KEY_FLOW_LABEL, | ||
790 | target_container); | ||
791 | key_tags->flow_label = ntohl(flow_keys->flow_label); | ||
792 | } | ||
784 | } | 793 | } |
785 | 794 | ||
786 | bool bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx, | 795 | bool bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx, |
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 2e4b0848d795..3d7fc67ec1b8 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h | |||
@@ -3530,6 +3530,7 @@ struct bpf_flow_keys { | |||
3530 | }; | 3530 | }; |
3531 | }; | 3531 | }; |
3532 | __u32 flags; | 3532 | __u32 flags; |
3533 | __be32 flow_label; | ||
3533 | }; | 3534 | }; |
3534 | 3535 | ||
3535 | struct bpf_func_info { | 3536 | struct bpf_func_info { |
diff --git a/tools/testing/selftests/bpf/prog_tests/flow_dissector.c b/tools/testing/selftests/bpf/prog_tests/flow_dissector.c index 8e8c18aced9b..ef83f145a6f1 100644 --- a/tools/testing/selftests/bpf/prog_tests/flow_dissector.c +++ b/tools/testing/selftests/bpf/prog_tests/flow_dissector.c | |||
@@ -20,6 +20,7 @@ | |||
20 | "is_encap=%u/%u " \ | 20 | "is_encap=%u/%u " \ |
21 | "ip_proto=0x%x/0x%x " \ | 21 | "ip_proto=0x%x/0x%x " \ |
22 | "n_proto=0x%x/0x%x " \ | 22 | "n_proto=0x%x/0x%x " \ |
23 | "flow_label=0x%x/0x%x " \ | ||
23 | "sport=%u/%u " \ | 24 | "sport=%u/%u " \ |
24 | "dport=%u/%u\n", \ | 25 | "dport=%u/%u\n", \ |
25 | got.nhoff, expected.nhoff, \ | 26 | got.nhoff, expected.nhoff, \ |
@@ -30,6 +31,7 @@ | |||
30 | got.is_encap, expected.is_encap, \ | 31 | got.is_encap, expected.is_encap, \ |
31 | got.ip_proto, expected.ip_proto, \ | 32 | got.ip_proto, expected.ip_proto, \ |
32 | got.n_proto, expected.n_proto, \ | 33 | got.n_proto, expected.n_proto, \ |
34 | got.flow_label, expected.flow_label, \ | ||
33 | got.sport, expected.sport, \ | 35 | got.sport, expected.sport, \ |
34 | got.dport, expected.dport) | 36 | got.dport, expected.dport) |
35 | 37 | ||
@@ -257,6 +259,50 @@ struct test tests[] = { | |||
257 | .is_first_frag = true, | 259 | .is_first_frag = true, |
258 | }, | 260 | }, |
259 | }, | 261 | }, |
262 | { | ||
263 | .name = "ipv6-flow-label", | ||
264 | .pkt.ipv6 = { | ||
265 | .eth.h_proto = __bpf_constant_htons(ETH_P_IPV6), | ||
266 | .iph.nexthdr = IPPROTO_TCP, | ||
267 | .iph.payload_len = __bpf_constant_htons(MAGIC_BYTES), | ||
268 | .iph.flow_lbl = { 0xb, 0xee, 0xef }, | ||
269 | .tcp.doff = 5, | ||
270 | .tcp.source = 80, | ||
271 | .tcp.dest = 8080, | ||
272 | }, | ||
273 | .keys = { | ||
274 | .nhoff = ETH_HLEN, | ||
275 | .thoff = ETH_HLEN + sizeof(struct ipv6hdr), | ||
276 | .addr_proto = ETH_P_IPV6, | ||
277 | .ip_proto = IPPROTO_TCP, | ||
278 | .n_proto = __bpf_constant_htons(ETH_P_IPV6), | ||
279 | .sport = 80, | ||
280 | .dport = 8080, | ||
281 | .flow_label = __bpf_constant_htonl(0xbeeef), | ||
282 | }, | ||
283 | }, | ||
284 | { | ||
285 | .name = "ipv6-no-flow-label", | ||
286 | .pkt.ipv6 = { | ||
287 | .eth.h_proto = __bpf_constant_htons(ETH_P_IPV6), | ||
288 | .iph.nexthdr = IPPROTO_TCP, | ||
289 | .iph.payload_len = __bpf_constant_htons(MAGIC_BYTES), | ||
290 | .iph.flow_lbl = { 0xb, 0xee, 0xef }, | ||
291 | .tcp.doff = 5, | ||
292 | .tcp.source = 80, | ||
293 | .tcp.dest = 8080, | ||
294 | }, | ||
295 | .keys = { | ||
296 | .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL, | ||
297 | .nhoff = ETH_HLEN, | ||
298 | .thoff = ETH_HLEN + sizeof(struct ipv6hdr), | ||
299 | .addr_proto = ETH_P_IPV6, | ||
300 | .ip_proto = IPPROTO_TCP, | ||
301 | .n_proto = __bpf_constant_htons(ETH_P_IPV6), | ||
302 | .flow_label = __bpf_constant_htonl(0xbeeef), | ||
303 | }, | ||
304 | .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL, | ||
305 | }, | ||
260 | }; | 306 | }; |
261 | 307 | ||
262 | static int create_tap(const char *ifname) | 308 | static int create_tap(const char *ifname) |
diff --git a/tools/testing/selftests/bpf/progs/bpf_flow.c b/tools/testing/selftests/bpf/progs/bpf_flow.c index f931cd3db9d4..7fbfa22f33df 100644 --- a/tools/testing/selftests/bpf/progs/bpf_flow.c +++ b/tools/testing/selftests/bpf/progs/bpf_flow.c | |||
@@ -83,6 +83,12 @@ static __always_inline int export_flow_keys(struct bpf_flow_keys *keys, | |||
83 | return ret; | 83 | return ret; |
84 | } | 84 | } |
85 | 85 | ||
86 | #define IPV6_FLOWLABEL_MASK __bpf_constant_htonl(0x000FFFFF) | ||
87 | static inline __be32 ip6_flowlabel(const struct ipv6hdr *hdr) | ||
88 | { | ||
89 | return *(__be32 *)hdr & IPV6_FLOWLABEL_MASK; | ||
90 | } | ||
91 | |||
86 | static __always_inline void *bpf_flow_dissect_get_header(struct __sk_buff *skb, | 92 | static __always_inline void *bpf_flow_dissect_get_header(struct __sk_buff *skb, |
87 | __u16 hdr_size, | 93 | __u16 hdr_size, |
88 | void *buffer) | 94 | void *buffer) |
@@ -308,6 +314,10 @@ PROG(IPV6)(struct __sk_buff *skb) | |||
308 | 314 | ||
309 | keys->thoff += sizeof(struct ipv6hdr); | 315 | keys->thoff += sizeof(struct ipv6hdr); |
310 | keys->ip_proto = ip6h->nexthdr; | 316 | keys->ip_proto = ip6h->nexthdr; |
317 | keys->flow_label = ip6_flowlabel(ip6h); | ||
318 | |||
319 | if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL) | ||
320 | return export_flow_keys(keys, BPF_OK); | ||
311 | 321 | ||
312 | return parse_ipv6_proto(skb, ip6h->nexthdr); | 322 | return parse_ipv6_proto(skb, ip6h->nexthdr); |
313 | } | 323 | } |