Message ID | 20210608170224.1138264-2-tannerlove.kernel@gmail.com |
---|---|
State | New |
Headers | show |
Series | [net-next,v4,1/3] net: flow_dissector: extend bpf flow dissector support with vnet hdr | expand |
On Tue, Jun 08, 2021 at 01:02:22PM -0400, Tanner Love wrote: [ ... ] > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index 9dc44ba97584..a333e6177de1 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -430,6 +430,8 @@ enum bpf_reg_type { > PTR_TO_PERCPU_BTF_ID, /* reg points to a percpu kernel variable */ > PTR_TO_FUNC, /* reg points to a bpf program function */ > PTR_TO_MAP_KEY, /* reg points to a map element key */ > + PTR_TO_VNET_HDR, /* reg points to struct virtio_net_hdr */ > + PTR_TO_VNET_HDR_OR_NULL, /* reg points to virtio_net_hdr or NULL */ > __BPF_REG_TYPE_MAX, > }; > [ ... ] > diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h > index 418b9b813d65..e1ac34548f9a 100644 > --- a/include/uapi/linux/bpf.h > +++ b/include/uapi/linux/bpf.h > @@ -6017,6 +6017,8 @@ struct bpf_flow_keys { > }; > __u32 flags; > __be32 flow_label; > + __bpf_md_ptr(const struct virtio_net_hdr *, vhdr); > + __u8 vhdr_is_little_endian; > }; > > struct bpf_func_info { > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index 331b170d9fcc..2962b537da28 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -22,6 +22,7 @@ > #include <linux/error-injection.h> > #include <linux/bpf_lsm.h> > #include <linux/btf_ids.h> > +#include <linux/virtio_net.h> > > #include "disasm.h" > > @@ -441,7 +442,8 @@ static bool reg_type_not_null(enum bpf_reg_type type) > type == PTR_TO_TCP_SOCK || > type == PTR_TO_MAP_VALUE || > type == PTR_TO_MAP_KEY || > - type == PTR_TO_SOCK_COMMON; > + type == PTR_TO_SOCK_COMMON || > + type == PTR_TO_VNET_HDR; > } > > static bool reg_type_may_be_null(enum bpf_reg_type type) > @@ -453,7 +455,8 @@ static bool reg_type_may_be_null(enum bpf_reg_type type) > type == PTR_TO_BTF_ID_OR_NULL || > type == PTR_TO_MEM_OR_NULL || > type == PTR_TO_RDONLY_BUF_OR_NULL || > - type == PTR_TO_RDWR_BUF_OR_NULL; > + type == PTR_TO_RDWR_BUF_OR_NULL || > + type == PTR_TO_VNET_HDR_OR_NULL; > } > > static bool reg_may_point_to_spin_lock(const struct bpf_reg_state *reg) > @@ -576,6 +579,8 @@ static const char * const reg_type_str[] = { > [PTR_TO_RDWR_BUF_OR_NULL] = "rdwr_buf_or_null", > [PTR_TO_FUNC] = "func", > [PTR_TO_MAP_KEY] = "map_key", > + [PTR_TO_VNET_HDR] = "virtio_net_hdr", > + [PTR_TO_VNET_HDR_OR_NULL] = "virtio_net_hdr_or_null", > }; > > static char slot_type_char[] = { > @@ -1166,6 +1171,9 @@ static void mark_ptr_not_null_reg(struct bpf_reg_state *reg) > case PTR_TO_RDWR_BUF_OR_NULL: > reg->type = PTR_TO_RDWR_BUF; > break; > + case PTR_TO_VNET_HDR_OR_NULL: > + reg->type = PTR_TO_VNET_HDR; > + break; > default: > WARN_ONCE(1, "unknown nullable register type"); > } > @@ -2528,6 +2536,8 @@ static bool is_spillable_regtype(enum bpf_reg_type type) > case PTR_TO_MEM_OR_NULL: > case PTR_TO_FUNC: > case PTR_TO_MAP_KEY: > + case PTR_TO_VNET_HDR: > + case PTR_TO_VNET_HDR_OR_NULL: > return true; > default: > return false; > @@ -3384,6 +3394,18 @@ static int check_flow_keys_access(struct bpf_verifier_env *env, int off, > return 0; > } > > +static int check_virtio_net_hdr_access(struct bpf_verifier_env *env, int off, > + int size) > +{ > + if (size < 0 || off < 0 || > + (u64)off + size > sizeof(struct virtio_net_hdr)) { > + verbose(env, "invalid access to virtio_net_hdr off=%d size=%d\n", > + off, size); > + return -EACCES; > + } > + return 0; > +} > + > static int check_sock_access(struct bpf_verifier_env *env, int insn_idx, > u32 regno, int off, int size, > enum bpf_access_type t) > @@ -3568,6 +3590,9 @@ static int check_ptr_alignment(struct bpf_verifier_env *env, > case PTR_TO_XDP_SOCK: > pointer_desc = "xdp_sock "; > break; > + case PTR_TO_VNET_HDR: > + pointer_desc = "virtio_net_hdr "; > + break; > default: > break; > } > @@ -4218,6 +4243,23 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn > } > > err = check_flow_keys_access(env, off, size); > + if (!err && t == BPF_READ && value_regno >= 0) { > + if (off == offsetof(struct bpf_flow_keys, vhdr)) { > + regs[value_regno].type = PTR_TO_VNET_HDR_OR_NULL; check_flow_keys_access() needs some modifications 1. What if t == BPF_WRITE? I think "keys->vhdr = 0xdead" has to be rejected. 2. It needs to check loading keys->vhdr is in sizeof(__u64) like other pointer loading does. Take a look at the flow_keys case in flow_dissector_is_valid_access(). It also needs to convert the pointer loading like how flow_dissector_convert_ctx_access() does on flow_keys. A high level design question. "struct virtio_net_hdr" is in uapi and there is no need to do convert_ctx. I think using PTR_TO_BTF_ID_OR_NULL will be easier here and the new PTR_TO_VNET_HDR* related changes will go away. The "else if (reg->type == PTR_TO_CTX)" case earlier could be a good example. To get the btf_id for "struct virtio_net_hdr", take a look at the BTF_ID_LIST_SINGLE() usage in filter.c > + /* required for dropping or_null */ > + regs[value_regno].id = ++env->id_gen; > + } else { > + mark_reg_unknown(env, regs, value_regno); > + } > + } > + } else if (reg->type == PTR_TO_VNET_HDR) { > + if (t == BPF_WRITE) { > + verbose(env, "R%d cannot write into %s\n", > + regno, reg_type_str[reg->type]); > + return -EACCES; > + } > + > + err = check_virtio_net_hdr_access(env, off, size); > if (!err && t == BPF_READ && value_regno >= 0) > mark_reg_unknown(env, regs, value_regno); > } else if (type_is_sk_pointer(reg->type)) { [ ... ] > @@ -8390,6 +8392,30 @@ static u32 flow_dissector_convert_ctx_access(enum bpf_access_type type, > si->dst_reg, si->src_reg, > offsetof(struct bpf_flow_dissector, flow_keys)); > break; > + > + case offsetof(struct __sk_buff, len): > + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct bpf_flow_dissector, skb), > + si->dst_reg, si->src_reg, > + offsetof(struct bpf_flow_dissector, skb)); > + *insn++ = BPF_JMP_IMM(BPF_JNE, si->dst_reg, 0, 4); > + /* bpf_flow_dissector->skb == NULL */ > + /* dst_reg = bpf_flow_dissector->data_end */ > + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct bpf_flow_dissector, data_end), > + si->dst_reg, si->src_reg, > + offsetof(struct bpf_flow_dissector, data_end)); > + /* TMP = bpf_flow_dissector->data */ > + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct bpf_flow_dissector, data), > + BPF_REG_TMP, si->src_reg, I don't think BPF_REG_TMP can be used here. My understanding is that is for classic bpf. Try BPF_REG_AX instead. It will be a good idea to cover this case if it has not been done in patch 3. > + offsetof(struct bpf_flow_dissector, data)); > + /* dst_reg -= bpf_flow_dissector->data */ > + *insn++ = BPF_ALU64_REG(BPF_SUB, si->dst_reg, BPF_REG_TMP); > + *insn++ = BPF_JMP_A(1); > + /* bpf_flow_dissector->skb != NULL */ > + /* bpf_flow_dissector->skb->len */ > + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, len), > + si->dst_reg, si->dst_reg, > + offsetof(struct sk_buff, len)); > + break; > } > > return insn - insn_buf;
On Wed, Jun 09, 2021 at 10:12:36AM -0700, Tanner Love wrote: [ ... ] > > > @@ -4218,6 +4243,23 @@ static int check_mem_access(struct > > bpf_verifier_env *env, int insn_idx, u32 regn > > > } > > > > > > err = check_flow_keys_access(env, off, size); > > > + if (!err && t == BPF_READ && value_regno >= 0) { > > > + if (off == offsetof(struct bpf_flow_keys, vhdr)) { > > > + regs[value_regno].type = > > PTR_TO_VNET_HDR_OR_NULL; > > check_flow_keys_access() needs some modifications > > > > 1. What if t == BPF_WRITE? I think "keys->vhdr = 0xdead" has to be > > rejected. > > > > 2. It needs to check loading keys->vhdr is in sizeof(__u64) like other > > pointer loading does. Take a look at the flow_keys case in > > flow_dissector_is_valid_access(). > > > > It also needs to convert the pointer loading like how > > flow_dissector_convert_ctx_access() does on flow_keys. > > > > I understand 1 and 2, and I agree. I will make the changes in the > next version. Thanks. But I do not understand your comment "It > also needs to convert the pointer loading like how > flow_dissector_convert_ctx_access() does on flow_keys." > Convert it to what? The pointer to struct virtio_net_hdr is in struct > bpf_flow_keys, not struct bpf_flow_dissector (the kernel context). > Could you please elaborate? Thank you! Ah, right. There is no kernel counter part for bpf_flow_keys. Please ignore the "convert the pointer loading" comment. > > > > > A high level design question. "struct virtio_net_hdr" is in uapi and > > there is no need to do convert_ctx. I think using PTR_TO_BTF_ID_OR_NULL > > will be easier here and the new PTR_TO_VNET_HDR* related changes will go > > away. > > > > The "else if (reg->type == PTR_TO_CTX)" case earlier could be a good > > example. > > > > To get the btf_id for "struct virtio_net_hdr", take a look at > > the BTF_ID_LIST_SINGLE() usage in filter.c > > > > Thanks for the suggestion. Still ruminating on this, but figured I'd send my > above question in the meantime. btf_id points to a BTF debuginfo that describes how a kernel struct looks like. PTR_TO_BTF_ID(_NOT_NULL) means a reg is a pointer to a kernel struct described by a BTF (so the btf_id). With the BTF, the access is checked commonly in btf_struct_access() for any kernel struct. It needs the BPF_PROBE_MEM support in the JIT which is currently in x86/arm64/s390.
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index eb79a9f05914..36993636d56d 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3554,7 +3554,7 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb, case BOND_XMIT_POLICY_ENCAP34: memset(fk, 0, sizeof(*fk)); return __skb_flow_dissect(NULL, skb, &flow_keys_bonding, - fk, NULL, 0, 0, 0, 0); + fk, NULL, 0, 0, 0, 0, NULL, false); default: break; } diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 9dc44ba97584..a333e6177de1 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -430,6 +430,8 @@ enum bpf_reg_type { PTR_TO_PERCPU_BTF_ID, /* reg points to a percpu kernel variable */ PTR_TO_FUNC, /* reg points to a bpf program function */ PTR_TO_MAP_KEY, /* reg points to a map element key */ + PTR_TO_VNET_HDR, /* reg points to struct virtio_net_hdr */ + PTR_TO_VNET_HDR_OR_NULL, /* reg points to virtio_net_hdr or NULL */ __BPF_REG_TYPE_MAX, }; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index b2db9cd9a73f..4e390cd8f72a 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1314,21 +1314,27 @@ void skb_flow_dissector_init(struct flow_dissector *flow_dissector, unsigned int key_count); struct bpf_flow_dissector; +struct virtio_net_hdr; bool bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx, - __be16 proto, int nhoff, int hlen, unsigned int flags); + __be16 proto, int nhoff, int hlen, unsigned int flags, + const struct virtio_net_hdr *vhdr, + bool vhdr_is_little_endian); bool __skb_flow_dissect(const struct net *net, const struct sk_buff *skb, struct flow_dissector *flow_dissector, void *target_container, const void *data, - __be16 proto, int nhoff, int hlen, unsigned int flags); + __be16 proto, int nhoff, int hlen, unsigned int flags, + const struct virtio_net_hdr *vhdr, + bool vhdr_is_little_endian); static inline bool skb_flow_dissect(const struct sk_buff *skb, struct flow_dissector *flow_dissector, void *target_container, unsigned int flags) { return __skb_flow_dissect(NULL, skb, flow_dissector, - target_container, NULL, 0, 0, 0, flags); + target_container, NULL, 0, 0, 0, flags, NULL, + false); } static inline bool skb_flow_dissect_flow_keys(const struct sk_buff *skb, @@ -1337,7 +1343,22 @@ static inline bool skb_flow_dissect_flow_keys(const struct sk_buff *skb, { memset(flow, 0, sizeof(*flow)); return __skb_flow_dissect(NULL, skb, &flow_keys_dissector, - flow, NULL, 0, 0, 0, flags); + flow, NULL, 0, 0, 0, flags, NULL, false); +} + +static inline bool +__skb_flow_dissect_flow_keys_basic(const struct net *net, + const struct sk_buff *skb, + struct flow_keys_basic *flow, + const void *data, __be16 proto, + int nhoff, int hlen, unsigned int flags, + const struct virtio_net_hdr *vhdr, + bool vhdr_is_little_endian) +{ + memset(flow, 0, sizeof(*flow)); + return __skb_flow_dissect(net, skb, &flow_keys_basic_dissector, flow, + data, proto, nhoff, hlen, flags, vhdr, + vhdr_is_little_endian); } static inline bool @@ -1347,9 +1368,9 @@ skb_flow_dissect_flow_keys_basic(const struct net *net, const void *data, __be16 proto, int nhoff, int hlen, unsigned int flags) { - memset(flow, 0, sizeof(*flow)); - return __skb_flow_dissect(net, skb, &flow_keys_basic_dissector, flow, - data, proto, nhoff, hlen, flags); + return __skb_flow_dissect_flow_keys_basic(net, skb, flow, data, proto, + nhoff, hlen, flags, NULL, + false); } void skb_flow_dissect_meta(const struct sk_buff *skb, diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 418b9b813d65..e1ac34548f9a 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -6017,6 +6017,8 @@ struct bpf_flow_keys { }; __u32 flags; __be32 flow_label; + __bpf_md_ptr(const struct virtio_net_hdr *, vhdr); + __u8 vhdr_is_little_endian; }; struct bpf_func_info { diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 331b170d9fcc..2962b537da28 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -22,6 +22,7 @@ #include <linux/error-injection.h> #include <linux/bpf_lsm.h> #include <linux/btf_ids.h> +#include <linux/virtio_net.h> #include "disasm.h" @@ -441,7 +442,8 @@ static bool reg_type_not_null(enum bpf_reg_type type) type == PTR_TO_TCP_SOCK || type == PTR_TO_MAP_VALUE || type == PTR_TO_MAP_KEY || - type == PTR_TO_SOCK_COMMON; + type == PTR_TO_SOCK_COMMON || + type == PTR_TO_VNET_HDR; } static bool reg_type_may_be_null(enum bpf_reg_type type) @@ -453,7 +455,8 @@ static bool reg_type_may_be_null(enum bpf_reg_type type) type == PTR_TO_BTF_ID_OR_NULL || type == PTR_TO_MEM_OR_NULL || type == PTR_TO_RDONLY_BUF_OR_NULL || - type == PTR_TO_RDWR_BUF_OR_NULL; + type == PTR_TO_RDWR_BUF_OR_NULL || + type == PTR_TO_VNET_HDR_OR_NULL; } static bool reg_may_point_to_spin_lock(const struct bpf_reg_state *reg) @@ -576,6 +579,8 @@ static const char * const reg_type_str[] = { [PTR_TO_RDWR_BUF_OR_NULL] = "rdwr_buf_or_null", [PTR_TO_FUNC] = "func", [PTR_TO_MAP_KEY] = "map_key", + [PTR_TO_VNET_HDR] = "virtio_net_hdr", + [PTR_TO_VNET_HDR_OR_NULL] = "virtio_net_hdr_or_null", }; static char slot_type_char[] = { @@ -1166,6 +1171,9 @@ static void mark_ptr_not_null_reg(struct bpf_reg_state *reg) case PTR_TO_RDWR_BUF_OR_NULL: reg->type = PTR_TO_RDWR_BUF; break; + case PTR_TO_VNET_HDR_OR_NULL: + reg->type = PTR_TO_VNET_HDR; + break; default: WARN_ONCE(1, "unknown nullable register type"); } @@ -2528,6 +2536,8 @@ static bool is_spillable_regtype(enum bpf_reg_type type) case PTR_TO_MEM_OR_NULL: case PTR_TO_FUNC: case PTR_TO_MAP_KEY: + case PTR_TO_VNET_HDR: + case PTR_TO_VNET_HDR_OR_NULL: return true; default: return false; @@ -3384,6 +3394,18 @@ static int check_flow_keys_access(struct bpf_verifier_env *env, int off, return 0; } +static int check_virtio_net_hdr_access(struct bpf_verifier_env *env, int off, + int size) +{ + if (size < 0 || off < 0 || + (u64)off + size > sizeof(struct virtio_net_hdr)) { + verbose(env, "invalid access to virtio_net_hdr off=%d size=%d\n", + off, size); + return -EACCES; + } + return 0; +} + static int check_sock_access(struct bpf_verifier_env *env, int insn_idx, u32 regno, int off, int size, enum bpf_access_type t) @@ -3568,6 +3590,9 @@ static int check_ptr_alignment(struct bpf_verifier_env *env, case PTR_TO_XDP_SOCK: pointer_desc = "xdp_sock "; break; + case PTR_TO_VNET_HDR: + pointer_desc = "virtio_net_hdr "; + break; default: break; } @@ -4218,6 +4243,23 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn } err = check_flow_keys_access(env, off, size); + if (!err && t == BPF_READ && value_regno >= 0) { + if (off == offsetof(struct bpf_flow_keys, vhdr)) { + regs[value_regno].type = PTR_TO_VNET_HDR_OR_NULL; + /* required for dropping or_null */ + regs[value_regno].id = ++env->id_gen; + } else { + mark_reg_unknown(env, regs, value_regno); + } + } + } else if (reg->type == PTR_TO_VNET_HDR) { + if (t == BPF_WRITE) { + verbose(env, "R%d cannot write into %s\n", + regno, reg_type_str[reg->type]); + return -EACCES; + } + + err = check_virtio_net_hdr_access(env, off, size); if (!err && t == BPF_READ && value_regno >= 0) mark_reg_unknown(env, regs, value_regno); } else if (type_is_sk_pointer(reg->type)) { @@ -9989,6 +10031,8 @@ static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur, case PTR_TO_TCP_SOCK: case PTR_TO_TCP_SOCK_OR_NULL: case PTR_TO_XDP_SOCK: + case PTR_TO_VNET_HDR: + case PTR_TO_VNET_HDR_OR_NULL: /* Only valid matches are exact, which memcmp() above * would have accepted */ diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index aa47af349ba8..a11c5ce99ccb 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -797,7 +797,7 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog, bpf_test_timer_enter(&t); do { retval = bpf_flow_dissect(prog, &ctx, eth->h_proto, ETH_HLEN, - size, flags); + size, flags, NULL, false); } while (bpf_test_timer_continue(&t, repeat, &ret, &duration)); bpf_test_timer_leave(&t); diff --git a/net/core/filter.c b/net/core/filter.c index 239de1306de9..58a8a43380ee 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -8358,6 +8358,8 @@ static bool flow_dissector_is_valid_access(int off, int size, return false; info->reg_type = PTR_TO_FLOW_KEYS; return true; + case bpf_ctx_range(struct __sk_buff, len): + return size == size_default; default: return false; } @@ -8390,6 +8392,30 @@ static u32 flow_dissector_convert_ctx_access(enum bpf_access_type type, si->dst_reg, si->src_reg, offsetof(struct bpf_flow_dissector, flow_keys)); break; + + case offsetof(struct __sk_buff, len): + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct bpf_flow_dissector, skb), + si->dst_reg, si->src_reg, + offsetof(struct bpf_flow_dissector, skb)); + *insn++ = BPF_JMP_IMM(BPF_JNE, si->dst_reg, 0, 4); + /* bpf_flow_dissector->skb == NULL */ + /* dst_reg = bpf_flow_dissector->data_end */ + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct bpf_flow_dissector, data_end), + si->dst_reg, si->src_reg, + offsetof(struct bpf_flow_dissector, data_end)); + /* TMP = bpf_flow_dissector->data */ + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct bpf_flow_dissector, data), + BPF_REG_TMP, si->src_reg, + offsetof(struct bpf_flow_dissector, data)); + /* dst_reg -= bpf_flow_dissector->data */ + *insn++ = BPF_ALU64_REG(BPF_SUB, si->dst_reg, BPF_REG_TMP); + *insn++ = BPF_JMP_A(1); + /* bpf_flow_dissector->skb != NULL */ + /* bpf_flow_dissector->skb->len */ + *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, len), + si->dst_reg, si->dst_reg, + offsetof(struct sk_buff, len)); + break; } return insn - insn_buf; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 3ed7c98a98e1..4bdad2b1d3a0 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -28,6 +28,7 @@ #include <scsi/fc/fc_fcoe.h> #include <uapi/linux/batadv_packet.h> #include <linux/bpf.h> +#include <linux/virtio_net.h> #if IS_ENABLED(CONFIG_NF_CONNTRACK) #include <net/netfilter/nf_conntrack_core.h> #include <net/netfilter/nf_conntrack_labels.h> @@ -864,7 +865,9 @@ static void __skb_flow_bpf_to_target(const struct bpf_flow_keys *flow_keys, } bool bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx, - __be16 proto, int nhoff, int hlen, unsigned int flags) + __be16 proto, int nhoff, int hlen, unsigned int flags, + const struct virtio_net_hdr *vhdr, + bool vhdr_is_little_endian) { struct bpf_flow_keys *flow_keys = ctx->flow_keys; u32 result; @@ -874,6 +877,8 @@ bool bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx, flow_keys->n_proto = proto; flow_keys->nhoff = nhoff; flow_keys->thoff = flow_keys->nhoff; + flow_keys->vhdr = vhdr; + flow_keys->vhdr_is_little_endian = vhdr_is_little_endian; BUILD_BUG_ON((int)BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG != (int)FLOW_DISSECTOR_F_PARSE_1ST_FRAG); @@ -915,7 +920,9 @@ bool __skb_flow_dissect(const struct net *net, const struct sk_buff *skb, struct flow_dissector *flow_dissector, void *target_container, const void *data, - __be16 proto, int nhoff, int hlen, unsigned int flags) + __be16 proto, int nhoff, int hlen, unsigned int flags, + const struct virtio_net_hdr *vhdr, + bool vhdr_is_little_endian) { struct flow_dissector_key_control *key_control; struct flow_dissector_key_basic *key_basic; @@ -1012,7 +1019,8 @@ bool __skb_flow_dissect(const struct net *net, prog = READ_ONCE(run_array->items[0].prog); ret = bpf_flow_dissect(prog, &ctx, n_proto, nhoff, - hlen, flags); + hlen, flags, vhdr, + vhdr_is_little_endian); __skb_flow_bpf_to_target(&flow_keys, flow_dissector, target_container); rcu_read_unlock(); @@ -1610,7 +1618,7 @@ u32 __skb_get_hash_symmetric(const struct sk_buff *skb) memset(&keys, 0, sizeof(keys)); __skb_flow_dissect(NULL, skb, &flow_keys_dissector_symmetric, &keys, NULL, 0, 0, 0, - FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); + FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL, NULL, false); return __flow_hash_from_keys(&keys, &hashrnd); } diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 418b9b813d65..e1ac34548f9a 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -6017,6 +6017,8 @@ struct bpf_flow_keys { }; __u32 flags; __be32 flow_label; + __bpf_md_ptr(const struct virtio_net_hdr *, vhdr); + __u8 vhdr_is_little_endian; }; struct bpf_func_info {