Message ID | 20190725225231.195090-8-sdf@google.com |
---|---|
State | Accepted |
Delegated to: | BPF Maintainers |
Headers | show |
Series | bpf/flow_dissector: support input flags | expand |
On 7/26/19 12:52 AM, Stanislav Fomichev wrote: > Exit as soon as we found that packet is encapped when > BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP is passed. > Add appropriate selftest cases. > > v2: > * Subtract sizeof(struct iphdr) from .iph_inner.tot_len (Willem de Bruijn) > > 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> > --- > .../selftests/bpf/prog_tests/flow_dissector.c | 64 +++++++++++++++++++ > tools/testing/selftests/bpf/progs/bpf_flow.c | 8 +++ > 2 files changed, 72 insertions(+) > > diff --git a/tools/testing/selftests/bpf/prog_tests/flow_dissector.c b/tools/testing/selftests/bpf/prog_tests/flow_dissector.c > index ef83f145a6f1..700d73d2f22a 100644 > --- a/tools/testing/selftests/bpf/prog_tests/flow_dissector.c > +++ b/tools/testing/selftests/bpf/prog_tests/flow_dissector.c > @@ -41,6 +41,13 @@ struct ipv4_pkt { > struct tcphdr tcp; > } __packed; > > +struct ipip_pkt { > + struct ethhdr eth; > + struct iphdr iph; > + struct iphdr iph_inner; > + struct tcphdr tcp; > +} __packed; > + > struct svlan_ipv4_pkt { > struct ethhdr eth; > __u16 vlan_tci; > @@ -82,6 +89,7 @@ struct test { > union { > struct ipv4_pkt ipv4; > struct svlan_ipv4_pkt svlan_ipv4; > + struct ipip_pkt ipip; > struct ipv6_pkt ipv6; > struct ipv6_frag_pkt ipv6_frag; > struct dvlan_ipv6_pkt dvlan_ipv6; > @@ -303,6 +311,62 @@ struct test tests[] = { > }, > .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL, > }, > + { > + .name = "ipip-encap", > + .pkt.ipip = { > + .eth.h_proto = __bpf_constant_htons(ETH_P_IP), > + .iph.ihl = 5, > + .iph.protocol = IPPROTO_IPIP, > + .iph.tot_len = __bpf_constant_htons(MAGIC_BYTES), > + .iph_inner.ihl = 5, > + .iph_inner.protocol = IPPROTO_TCP, > + .iph_inner.tot_len = > + __bpf_constant_htons(MAGIC_BYTES) - > + sizeof(struct iphdr), > + .tcp.doff = 5, > + .tcp.source = 80, > + .tcp.dest = 8080, > + }, > + .keys = { > + .nhoff = 0, > + .nhoff = ETH_HLEN, clang emits a warning because nhoff is defined twice. > + .thoff = ETH_HLEN + sizeof(struct iphdr) + > + sizeof(struct iphdr), > + .addr_proto = ETH_P_IP, > + .ip_proto = IPPROTO_TCP, > + .n_proto = __bpf_constant_htons(ETH_P_IP), > + .is_encap = true, > + .sport = 80, > + .dport = 8080, > + }, > + }, > + { > + .name = "ipip-no-encap", > + .pkt.ipip = { > + .eth.h_proto = __bpf_constant_htons(ETH_P_IP), > + .iph.ihl = 5, > + .iph.protocol = IPPROTO_IPIP, > + .iph.tot_len = __bpf_constant_htons(MAGIC_BYTES), > + .iph_inner.ihl = 5, > + .iph_inner.protocol = IPPROTO_TCP, > + .iph_inner.tot_len = > + __bpf_constant_htons(MAGIC_BYTES) - > + sizeof(struct iphdr), > + .tcp.doff = 5, > + .tcp.source = 80, > + .tcp.dest = 8080, > + }, > + .keys = { > + .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP, > + .nhoff = ETH_HLEN, > + .thoff = ETH_HLEN + sizeof(struct iphdr), > + .addr_proto = ETH_P_IP, > + .ip_proto = IPPROTO_IPIP, > + .n_proto = __bpf_constant_htons(ETH_P_IP), > + .is_encap = true, > + }, > + .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP, > + }, > }; > > 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 7fbfa22f33df..08bd8b9d58d0 100644 > --- a/tools/testing/selftests/bpf/progs/bpf_flow.c > +++ b/tools/testing/selftests/bpf/progs/bpf_flow.c > @@ -167,9 +167,15 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto) > return export_flow_keys(keys, BPF_OK); > case IPPROTO_IPIP: > keys->is_encap = true; > + if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP) > + return export_flow_keys(keys, BPF_OK); > + > return parse_eth_proto(skb, bpf_htons(ETH_P_IP)); > case IPPROTO_IPV6: > keys->is_encap = true; > + if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP) > + return export_flow_keys(keys, BPF_OK); > + > return parse_eth_proto(skb, bpf_htons(ETH_P_IPV6)); > case IPPROTO_GRE: > gre = bpf_flow_dissect_get_header(skb, sizeof(*gre), &_gre); > @@ -189,6 +195,8 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto) > keys->thoff += 4; /* Step over sequence number */ > > keys->is_encap = true; > + if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP) > + return export_flow_keys(keys, BPF_OK); > > if (gre->proto == bpf_htons(ETH_P_TEB)) { > eth = bpf_flow_dissect_get_header(skb, sizeof(*eth), >
Yeah, I've sent the fix upstream yesterday, will backport. Feel free to ignore the following patches: https://screenshot.googleplex.com/DOQKAzGDksV They are all blocked on this nhoff defined twice :-( I'll backport them On Tue, Aug 27, 2019 at 11:04 AM Eric Dumazet <eric.dumazet@gmail.com> wrote: > > > > On 7/26/19 12:52 AM, Stanislav Fomichev wrote: > > Exit as soon as we found that packet is encapped when > > BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP is passed. > > Add appropriate selftest cases. > > > > v2: > > * Subtract sizeof(struct iphdr) from .iph_inner.tot_len (Willem de Bruijn) > > > > 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> > > --- > > .../selftests/bpf/prog_tests/flow_dissector.c | 64 +++++++++++++++++++ > > tools/testing/selftests/bpf/progs/bpf_flow.c | 8 +++ > > 2 files changed, 72 insertions(+) > > > > diff --git a/tools/testing/selftests/bpf/prog_tests/flow_dissector.c b/tools/testing/selftests/bpf/prog_tests/flow_dissector.c > > index ef83f145a6f1..700d73d2f22a 100644 > > --- a/tools/testing/selftests/bpf/prog_tests/flow_dissector.c > > +++ b/tools/testing/selftests/bpf/prog_tests/flow_dissector.c > > @@ -41,6 +41,13 @@ struct ipv4_pkt { > > struct tcphdr tcp; > > } __packed; > > > > +struct ipip_pkt { > > + struct ethhdr eth; > > + struct iphdr iph; > > + struct iphdr iph_inner; > > + struct tcphdr tcp; > > +} __packed; > > + > > struct svlan_ipv4_pkt { > > struct ethhdr eth; > > __u16 vlan_tci; > > @@ -82,6 +89,7 @@ struct test { > > union { > > struct ipv4_pkt ipv4; > > struct svlan_ipv4_pkt svlan_ipv4; > > + struct ipip_pkt ipip; > > struct ipv6_pkt ipv6; > > struct ipv6_frag_pkt ipv6_frag; > > struct dvlan_ipv6_pkt dvlan_ipv6; > > @@ -303,6 +311,62 @@ struct test tests[] = { > > }, > > .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL, > > }, > > + { > > + .name = "ipip-encap", > > + .pkt.ipip = { > > + .eth.h_proto = __bpf_constant_htons(ETH_P_IP), > > + .iph.ihl = 5, > > + .iph.protocol = IPPROTO_IPIP, > > + .iph.tot_len = __bpf_constant_htons(MAGIC_BYTES), > > + .iph_inner.ihl = 5, > > + .iph_inner.protocol = IPPROTO_TCP, > > + .iph_inner.tot_len = > > + __bpf_constant_htons(MAGIC_BYTES) - > > + sizeof(struct iphdr), > > + .tcp.doff = 5, > > + .tcp.source = 80, > > + .tcp.dest = 8080, > > + }, > > + .keys = { > > + .nhoff = 0, > > + .nhoff = ETH_HLEN, > > clang emits a warning because nhoff is defined twice. > > > + .thoff = ETH_HLEN + sizeof(struct iphdr) + > > + sizeof(struct iphdr), > > + .addr_proto = ETH_P_IP, > > + .ip_proto = IPPROTO_TCP, > > + .n_proto = __bpf_constant_htons(ETH_P_IP), > > + .is_encap = true, > > + .sport = 80, > > + .dport = 8080, > > + }, > > + }, > > + { > > + .name = "ipip-no-encap", > > + .pkt.ipip = { > > + .eth.h_proto = __bpf_constant_htons(ETH_P_IP), > > + .iph.ihl = 5, > > + .iph.protocol = IPPROTO_IPIP, > > + .iph.tot_len = __bpf_constant_htons(MAGIC_BYTES), > > + .iph_inner.ihl = 5, > > + .iph_inner.protocol = IPPROTO_TCP, > > + .iph_inner.tot_len = > > + __bpf_constant_htons(MAGIC_BYTES) - > > + sizeof(struct iphdr), > > + .tcp.doff = 5, > > + .tcp.source = 80, > > + .tcp.dest = 8080, > > + }, > > + .keys = { > > + .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP, > > + .nhoff = ETH_HLEN, > > + .thoff = ETH_HLEN + sizeof(struct iphdr), > > + .addr_proto = ETH_P_IP, > > + .ip_proto = IPPROTO_IPIP, > > + .n_proto = __bpf_constant_htons(ETH_P_IP), > > + .is_encap = true, > > + }, > > + .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP, > > + }, > > }; > > > > 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 7fbfa22f33df..08bd8b9d58d0 100644 > > --- a/tools/testing/selftests/bpf/progs/bpf_flow.c > > +++ b/tools/testing/selftests/bpf/progs/bpf_flow.c > > @@ -167,9 +167,15 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto) > > return export_flow_keys(keys, BPF_OK); > > case IPPROTO_IPIP: > > keys->is_encap = true; > > + if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP) > > + return export_flow_keys(keys, BPF_OK); > > + > > return parse_eth_proto(skb, bpf_htons(ETH_P_IP)); > > case IPPROTO_IPV6: > > keys->is_encap = true; > > + if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP) > > + return export_flow_keys(keys, BPF_OK); > > + > > return parse_eth_proto(skb, bpf_htons(ETH_P_IPV6)); > > case IPPROTO_GRE: > > gre = bpf_flow_dissect_get_header(skb, sizeof(*gre), &_gre); > > @@ -189,6 +195,8 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto) > > keys->thoff += 4; /* Step over sequence number */ > > > > keys->is_encap = true; > > + if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP) > > + return export_flow_keys(keys, BPF_OK); > > > > if (gre->proto == bpf_htons(ETH_P_TEB)) { > > eth = bpf_flow_dissect_get_header(skb, sizeof(*eth), > >
diff --git a/tools/testing/selftests/bpf/prog_tests/flow_dissector.c b/tools/testing/selftests/bpf/prog_tests/flow_dissector.c index ef83f145a6f1..700d73d2f22a 100644 --- a/tools/testing/selftests/bpf/prog_tests/flow_dissector.c +++ b/tools/testing/selftests/bpf/prog_tests/flow_dissector.c @@ -41,6 +41,13 @@ struct ipv4_pkt { struct tcphdr tcp; } __packed; +struct ipip_pkt { + struct ethhdr eth; + struct iphdr iph; + struct iphdr iph_inner; + struct tcphdr tcp; +} __packed; + struct svlan_ipv4_pkt { struct ethhdr eth; __u16 vlan_tci; @@ -82,6 +89,7 @@ struct test { union { struct ipv4_pkt ipv4; struct svlan_ipv4_pkt svlan_ipv4; + struct ipip_pkt ipip; struct ipv6_pkt ipv6; struct ipv6_frag_pkt ipv6_frag; struct dvlan_ipv6_pkt dvlan_ipv6; @@ -303,6 +311,62 @@ struct test tests[] = { }, .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL, }, + { + .name = "ipip-encap", + .pkt.ipip = { + .eth.h_proto = __bpf_constant_htons(ETH_P_IP), + .iph.ihl = 5, + .iph.protocol = IPPROTO_IPIP, + .iph.tot_len = __bpf_constant_htons(MAGIC_BYTES), + .iph_inner.ihl = 5, + .iph_inner.protocol = IPPROTO_TCP, + .iph_inner.tot_len = + __bpf_constant_htons(MAGIC_BYTES) - + sizeof(struct iphdr), + .tcp.doff = 5, + .tcp.source = 80, + .tcp.dest = 8080, + }, + .keys = { + .nhoff = 0, + .nhoff = ETH_HLEN, + .thoff = ETH_HLEN + sizeof(struct iphdr) + + sizeof(struct iphdr), + .addr_proto = ETH_P_IP, + .ip_proto = IPPROTO_TCP, + .n_proto = __bpf_constant_htons(ETH_P_IP), + .is_encap = true, + .sport = 80, + .dport = 8080, + }, + }, + { + .name = "ipip-no-encap", + .pkt.ipip = { + .eth.h_proto = __bpf_constant_htons(ETH_P_IP), + .iph.ihl = 5, + .iph.protocol = IPPROTO_IPIP, + .iph.tot_len = __bpf_constant_htons(MAGIC_BYTES), + .iph_inner.ihl = 5, + .iph_inner.protocol = IPPROTO_TCP, + .iph_inner.tot_len = + __bpf_constant_htons(MAGIC_BYTES) - + sizeof(struct iphdr), + .tcp.doff = 5, + .tcp.source = 80, + .tcp.dest = 8080, + }, + .keys = { + .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP, + .nhoff = ETH_HLEN, + .thoff = ETH_HLEN + sizeof(struct iphdr), + .addr_proto = ETH_P_IP, + .ip_proto = IPPROTO_IPIP, + .n_proto = __bpf_constant_htons(ETH_P_IP), + .is_encap = true, + }, + .flags = BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP, + }, }; 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 7fbfa22f33df..08bd8b9d58d0 100644 --- a/tools/testing/selftests/bpf/progs/bpf_flow.c +++ b/tools/testing/selftests/bpf/progs/bpf_flow.c @@ -167,9 +167,15 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto) return export_flow_keys(keys, BPF_OK); case IPPROTO_IPIP: keys->is_encap = true; + if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP) + return export_flow_keys(keys, BPF_OK); + return parse_eth_proto(skb, bpf_htons(ETH_P_IP)); case IPPROTO_IPV6: keys->is_encap = true; + if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP) + return export_flow_keys(keys, BPF_OK); + return parse_eth_proto(skb, bpf_htons(ETH_P_IPV6)); case IPPROTO_GRE: gre = bpf_flow_dissect_get_header(skb, sizeof(*gre), &_gre); @@ -189,6 +195,8 @@ static __always_inline int parse_ip_proto(struct __sk_buff *skb, __u8 proto) keys->thoff += 4; /* Step over sequence number */ keys->is_encap = true; + if (keys->flags & BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP) + return export_flow_keys(keys, BPF_OK); if (gre->proto == bpf_htons(ETH_P_TEB)) { eth = bpf_flow_dissect_get_header(skb, sizeof(*eth),