Skip to content

Commit

Permalink
bpf/flow_dissector: support ipv6 flow_label and BPF_FLOW_DISSECTOR_F_…
Browse files Browse the repository at this point in the history
…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>
  • Loading branch information
Stanislav Fomichev authored and Alexei Starovoitov committed Jul 26, 2019
1 parent ae173a9 commit 71c99e3
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -3533,6 +3533,7 @@ struct bpf_flow_keys {
};
};
__u32 flags;
__be32 flow_label;
};

struct bpf_func_info {
Expand Down
9 changes: 9 additions & 0 deletions net/core/flow_dissector.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions tools/include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -3530,6 +3530,7 @@ struct bpf_flow_keys {
};
};
__u32 flags;
__be32 flow_label;
};

struct bpf_func_info {
Expand Down
46 changes: 46 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/flow_dissector.c
Original file line number Diff line number Diff line change
Expand Up @@ -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, \
Expand All @@ -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)

Expand Down Expand Up @@ -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)
Expand Down
10 changes: 10 additions & 0 deletions tools/testing/selftests/bpf/progs/bpf_flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}
Expand Down

0 comments on commit 71c99e3

Please sign in to comment.