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@xxxxxxxxxx> > Acked-by: Willem de Bruijn <willemb@xxxxxxxxxx> > Acked-by: Song Liu <songliubraving@xxxxxx> > Cc: Song Liu <songliubraving@xxxxxx> > Cc: Willem de Bruijn <willemb@xxxxxxxxxx> > Cc: Petar Penkov <ppenkov@xxxxxxxxxx> > Signed-off-by: Stanislav Fomichev <sdf@xxxxxxxxxx> > --- > .../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), >