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>
This commit is contained in:
Stanislav Fomichev 2019-07-25 15:52:30 -07:00 committed by Alexei Starovoitov
parent ae173a9157
commit 71c99e32b9
5 changed files with 67 additions and 0 deletions

View File

@ -3533,6 +3533,7 @@ struct bpf_flow_keys {
}; };
}; };
__u32 flags; __u32 flags;
__be32 flow_label;
}; };
struct bpf_func_info { struct bpf_func_info {

View 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_basic *key_basic;
struct flow_dissector_key_addrs *key_addrs; struct flow_dissector_key_addrs *key_addrs;
struct flow_dissector_key_ports *key_ports; struct flow_dissector_key_ports *key_ports;
struct flow_dissector_key_tags *key_tags;
key_control = skb_flow_dissector_target(flow_dissector, key_control = skb_flow_dissector_target(flow_dissector,
FLOW_DISSECTOR_KEY_CONTROL, 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->src = flow_keys->sport;
key_ports->dst = flow_keys->dport; 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, bool bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx,

View File

@ -3530,6 +3530,7 @@ struct bpf_flow_keys {
}; };
}; };
__u32 flags; __u32 flags;
__be32 flow_label;
}; };
struct bpf_func_info { struct bpf_func_info {

View File

@ -20,6 +20,7 @@
"is_encap=%u/%u " \ "is_encap=%u/%u " \
"ip_proto=0x%x/0x%x " \ "ip_proto=0x%x/0x%x " \
"n_proto=0x%x/0x%x " \ "n_proto=0x%x/0x%x " \
"flow_label=0x%x/0x%x " \
"sport=%u/%u " \ "sport=%u/%u " \
"dport=%u/%u\n", \ "dport=%u/%u\n", \
got.nhoff, expected.nhoff, \ got.nhoff, expected.nhoff, \
@ -30,6 +31,7 @@
got.is_encap, expected.is_encap, \ got.is_encap, expected.is_encap, \
got.ip_proto, expected.ip_proto, \ got.ip_proto, expected.ip_proto, \
got.n_proto, expected.n_proto, \ got.n_proto, expected.n_proto, \
got.flow_label, expected.flow_label, \
got.sport, expected.sport, \ got.sport, expected.sport, \
got.dport, expected.dport) got.dport, expected.dport)
@ -257,6 +259,50 @@ struct test tests[] = {
.is_first_frag = true, .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) static int create_tap(const char *ifname)

View File

@ -83,6 +83,12 @@ static __always_inline int export_flow_keys(struct bpf_flow_keys *keys,
return ret; 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, static __always_inline void *bpf_flow_dissect_get_header(struct __sk_buff *skb,
__u16 hdr_size, __u16 hdr_size,
void *buffer) void *buffer)
@ -308,6 +314,10 @@ PROG(IPV6)(struct __sk_buff *skb)
keys->thoff += sizeof(struct ipv6hdr); keys->thoff += sizeof(struct ipv6hdr);
keys->ip_proto = ip6h->nexthdr; 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); return parse_ipv6_proto(skb, ip6h->nexthdr);
} }