diff mbox series

[v3,bpf-next,2/5] libbpf: Allow the number of hashes in bloom filter maps to be configurable

Message ID 20210921210225.4095056-3-joannekoong@fb.com (mailing list archive)
State Changes Requested
Delegated to: BPF
Headers show
Series Implement bloom filter map | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-PR success PR summary
netdev/cover_letter success Link
netdev/fixes_present success Link
netdev/patch_count success Link
netdev/tree_selection success Clearly marked for bpf-next
netdev/subject_prefix success Link
netdev/cc_maintainers fail 13 maintainers not CCed: kpsingh@kernel.org john.fastabend@gmail.com yhs@fb.com haoluo@google.com daniel@iogearbox.net brouer@redhat.com jackmanb@google.com joe@cilium.io andrii@kernel.org songliubraving@fb.com netdev@vger.kernel.org ast@kernel.org kafai@fb.com
netdev/source_inline fail Was 0 now: 1
netdev/verify_signedoff success Link
netdev/module_param success Was 0 now: 0
netdev/build_32bit fail Errors and warnings before: 11824 this patch: 11843
netdev/kdoc success Errors and warnings before: 10 this patch: 10
netdev/verify_fixes success Link
netdev/checkpatch warning WARNING: line length of 81 exceeds 80 columns WARNING: line length of 82 exceeds 80 columns WARNING: line length of 84 exceeds 80 columns WARNING: line length of 90 exceeds 80 columns WARNING: line length of 97 exceeds 80 columns
netdev/build_allmodconfig_warn fail Errors and warnings before: 11429 this patch: 11501
netdev/header_inline success Link
bpf/vmtest-bpf-next success VM_Test

Commit Message

Joanne Koong Sept. 21, 2021, 9:02 p.m. UTC
This patch adds the libbpf infrastructure that will allow the user to
specify a configurable number of hash functions to use for the bloom
filter map.

Please note that this patch does not enforce that a pinned bloom filter
map may only be reused if the number of hash functions is the same. If
they are not the same, the number of hash functions used will be the one
that was set for the pinned map.

Signed-off-by: Joanne Koong <joannekoong@fb.com>
---
 include/uapi/linux/bpf.h        |  5 ++++-
 tools/include/uapi/linux/bpf.h  |  5 ++++-
 tools/lib/bpf/bpf.c             |  2 ++
 tools/lib/bpf/bpf.h             |  1 +
 tools/lib/bpf/libbpf.c          | 32 +++++++++++++++++++++++++++-----
 tools/lib/bpf/libbpf.h          |  2 ++
 tools/lib/bpf/libbpf.map        |  1 +
 tools/lib/bpf/libbpf_internal.h |  4 +++-
 8 files changed, 44 insertions(+), 8 deletions(-)

Comments

Joanne Koong Sept. 21, 2021, 10:24 p.m. UTC | #1
On 9/21/21 2:02 PM, Joanne Koong wrote:
> This patch adds the libbpf infrastructure that will allow the user to
> specify a configurable number of hash functions to use for the bloom
> filter map.
>
> Please note that this patch does not enforce that a pinned bloom filter
> map may only be reused if the number of hash functions is the same. If
> they are not the same, the number of hash functions used will be the one
> that was set for the pinned map.
>
> Signed-off-by: Joanne Koong <joannekoong@fb.com>
> ---
>   include/uapi/linux/bpf.h        |  5 ++++-
>   tools/include/uapi/linux/bpf.h  |  5 ++++-
>   tools/lib/bpf/bpf.c             |  2 ++
>   tools/lib/bpf/bpf.h             |  1 +
>   tools/lib/bpf/libbpf.c          | 32 +++++++++++++++++++++++++++-----
>   tools/lib/bpf/libbpf.h          |  2 ++
>   tools/lib/bpf/libbpf.map        |  1 +
>   tools/lib/bpf/libbpf_internal.h |  4 +++-
>   8 files changed, 44 insertions(+), 8 deletions(-)
>
> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> index fec9fcfe0629..2e3048488feb 100644
> --- a/include/uapi/linux/bpf.h
> +++ b/include/uapi/linux/bpf.h
> @@ -1262,7 +1262,10 @@ union bpf_attr {
>   		__u32	map_flags;	/* BPF_MAP_CREATE related
>   					 * flags defined above.
>   					 */
> -		__u32	inner_map_fd;	/* fd pointing to the inner map */
> +		union {
> +			__u32	inner_map_fd;	/* fd pointing to the inner map */
> +			__u32	nr_hash_funcs;  /* or number of hash functions */
> +		};
>   		__u32	numa_node;	/* numa node (effective only if
>   					 * BPF_F_NUMA_NODE is set).
>   					 */
> diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
> index fec9fcfe0629..2e3048488feb 100644
> --- a/tools/include/uapi/linux/bpf.h
> +++ b/tools/include/uapi/linux/bpf.h
> @@ -1262,7 +1262,10 @@ union bpf_attr {
>   		__u32	map_flags;	/* BPF_MAP_CREATE related
>   					 * flags defined above.
>   					 */
> -		__u32	inner_map_fd;	/* fd pointing to the inner map */
> +		union {
> +			__u32	inner_map_fd;	/* fd pointing to the inner map */
> +			__u32	nr_hash_funcs;  /* or number of hash functions */
> +		};
>   		__u32	numa_node;	/* numa node (effective only if
>   					 * BPF_F_NUMA_NODE is set).
>   					 */
> diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
> index 2401fad090c5..8a9dd4f6d6c8 100644
> --- a/tools/lib/bpf/bpf.c
> +++ b/tools/lib/bpf/bpf.c
> @@ -100,6 +100,8 @@ int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr)
>   	if (attr.map_type == BPF_MAP_TYPE_STRUCT_OPS)
>   		attr.btf_vmlinux_value_type_id =
>   			create_attr->btf_vmlinux_value_type_id;
> +	else if (attr.map_type == BPF_MAP_TYPE_BLOOM_FILTER)
> +		attr.nr_hash_funcs = create_attr->nr_hash_funcs;
>   	else
>   		attr.inner_map_fd = create_attr->inner_map_fd;
>   
> diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
> index 6fffb3cdf39b..1194b6f01572 100644
> --- a/tools/lib/bpf/bpf.h
> +++ b/tools/lib/bpf/bpf.h
> @@ -49,6 +49,7 @@ struct bpf_create_map_attr {
>   	union {
>   		__u32 inner_map_fd;
>   		__u32 btf_vmlinux_value_type_id;
> +		__u32 nr_hash_funcs;
>   	};
>   };
>   
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index da65a1666a5e..e51e68a07aaf 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -378,6 +378,7 @@ struct bpf_map {
>   	char *pin_path;
>   	bool pinned;
>   	bool reused;
> +	__u32 nr_hash_funcs;
>   };
>   
>   enum extern_type {
> @@ -1291,6 +1292,11 @@ static bool bpf_map_type__is_map_in_map(enum bpf_map_type type)
>   	return false;
>   }
>   
> +static inline bool bpf_map__is_bloom_filter(const struct bpf_map *map)
> +{
> +	return map->def.type == BPF_MAP_TYPE_BLOOM_FILTER;
> +}
> +
>   int bpf_object__section_size(const struct bpf_object *obj, const char *name,
>   			     __u32 *size)
>   {
> @@ -2238,6 +2244,10 @@ int parse_btf_map_def(const char *map_name, struct btf *btf,
>   			}
>   			map_def->pinning = val;
>   			map_def->parts |= MAP_DEF_PINNING;
> +		} else if (strcmp(name, "nr_hash_funcs") == 0) {
> +			if (!get_map_field_int(map_name, btf, m, &map_def->nr_hash_funcs))
> +				return -EINVAL;
> +			map_def->parts |= MAP_DEF_NR_HASH_FUNCS;
>   		} else {
>   			if (strict) {
>   				pr_warn("map '%s': unknown field '%s'.\n", map_name, name);
> @@ -2266,6 +2276,7 @@ static void fill_map_from_def(struct bpf_map *map, const struct btf_map_def *def
>   	map->numa_node = def->numa_node;
>   	map->btf_key_type_id = def->key_type_id;
>   	map->btf_value_type_id = def->value_type_id;
> +	map->nr_hash_funcs = def->nr_hash_funcs;
>   
>   	if (def->parts & MAP_DEF_MAP_TYPE)
>   		pr_debug("map '%s': found type = %u.\n", map->name, def->map_type);
> @@ -2290,6 +2301,8 @@ static void fill_map_from_def(struct bpf_map *map, const struct btf_map_def *def
>   		pr_debug("map '%s': found pinning = %u.\n", map->name, def->pinning);
>   	if (def->parts & MAP_DEF_NUMA_NODE)
>   		pr_debug("map '%s': found numa_node = %u.\n", map->name, def->numa_node);
> +	if (def->parts & MAP_DEF_NR_HASH_FUNCS)
> +		pr_debug("map '%s': found nr_hash_funcs = %u.\n", map->name, def->nr_hash_funcs);
>   
>   	if (def->parts & MAP_DEF_INNER_MAP)
>   		pr_debug("map '%s': found inner map definition.\n", map->name);
> @@ -4616,10 +4629,6 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b
>   		create_attr.max_entries = def->max_entries;
>   	}
>   
> -	if (bpf_map__is_struct_ops(map))
> -		create_attr.btf_vmlinux_value_type_id =
> -			map->btf_vmlinux_value_type_id;
> -
>   	create_attr.btf_fd = 0;
>   	create_attr.btf_key_type_id = 0;
>   	create_attr.btf_value_type_id = 0;
> @@ -4629,7 +4638,12 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b
>   		create_attr.btf_value_type_id = map->btf_value_type_id;
>   	}
>   
> -	if (bpf_map_type__is_map_in_map(def->type)) {
> +	if (bpf_map__is_struct_ops(map)) {
> +		create_attr.btf_vmlinux_value_type_id =
> +			map->btf_vmlinux_value_type_id;
> +	} else if (bpf_map__is_bloom_filter(map)) {
> +		create_attr.nr_hash_funcs = map->nr_hash_funcs;
> +	} else if (bpf_map_type__is_map_in_map(def->type)) {
>   		if (map->inner_map) {
>   			err = bpf_object__create_map(obj, map->inner_map, true);
>   			if (err) {
> @@ -8610,6 +8624,14 @@ int bpf_map__set_value_size(struct bpf_map *map, __u32 size)
>   	return 0;
>   }
>   
> +int bpf_map__set_nr_hash_funcs(struct bpf_map *map, __u32 nr_hash_funcs)
> +{
> +	if (map->fd >= 0)
> +		return libbpf_err(-EBUSY);
> +	map->nr_hash_funcs = nr_hash_funcs;
> +	return 0;
> +}
> +
>   __u32 bpf_map__btf_key_type_id(const struct bpf_map *map)
>   {
>   	return map ? map->btf_key_type_id : 0;
> diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
> index d0bedd673273..5c441744f766 100644
> --- a/tools/lib/bpf/libbpf.h
> +++ b/tools/lib/bpf/libbpf.h
> @@ -550,6 +550,8 @@ LIBBPF_API __u32 bpf_map__btf_value_type_id(const struct bpf_map *map);
>   /* get/set map if_index */
>   LIBBPF_API __u32 bpf_map__ifindex(const struct bpf_map *map);
>   LIBBPF_API int bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
> +/* set nr_hash_funcs */
> +LIBBPF_API int bpf_map__set_nr_hash_funcs(struct bpf_map *map, __u32 nr_hash_funcs);
>   
>   typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *);
>   LIBBPF_API int bpf_map__set_priv(struct bpf_map *map, void *priv,
> diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
> index 9e649cf9e771..ee0e1e7648f4 100644
> --- a/tools/lib/bpf/libbpf.map
> +++ b/tools/lib/bpf/libbpf.map
> @@ -385,6 +385,7 @@ LIBBPF_0.5.0 {
>   		btf__load_vmlinux_btf;
>   		btf_dump__dump_type_data;
>   		libbpf_set_strict_mode;
> +		bpf_map__set_nr_hash_funcs;
>   } LIBBPF_0.4.0;
>   
>   LIBBPF_0.6.0 {
> diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h
> index ceb0c98979bc..95dbbeba231f 100644
> --- a/tools/lib/bpf/libbpf_internal.h
> +++ b/tools/lib/bpf/libbpf_internal.h
> @@ -186,8 +186,9 @@ enum map_def_parts {
>   	MAP_DEF_NUMA_NODE	= 0x080,
>   	MAP_DEF_PINNING		= 0x100,
>   	MAP_DEF_INNER_MAP	= 0x200,
> +	MAP_DEF_NR_HASH_FUNCS	= 0x400,
>   
> -	MAP_DEF_ALL		= 0x3ff, /* combination of all above */
> +	MAP_DEF_ALL		= 0x7ff, /* combination of all above */
>   };
>   
>   struct btf_map_def {
> @@ -201,6 +202,7 @@ struct btf_map_def {
>   	__u32 map_flags;
>   	__u32 numa_node;
>   	__u32 pinning;
> +	__u32 nr_hash_funcs;
>   };
>   

I just realized that Andrii's comment on v1 stated that btf_map_def is 
fixed indefinitely.

This implies that for bloom filter maps where the number of hash 
functions needs to be set,
we will not be able to use the BTF-defined format and will instead need 
to use the older
map definition that uses bpf_map_def. Is my understanding of this 
correct? If so, I will go
ahead and fix this for v4.

>   int parse_btf_map_def(const char *map_name, struct btf *btf,
Andrii Nakryiko Sept. 21, 2021, 11:57 p.m. UTC | #2
On Tue, Sep 21, 2021 at 2:30 PM Joanne Koong <joannekoong@fb.com> wrote:
>
> This patch adds the libbpf infrastructure that will allow the user to
> specify a configurable number of hash functions to use for the bloom
> filter map.
>
> Please note that this patch does not enforce that a pinned bloom filter
> map may only be reused if the number of hash functions is the same. If
> they are not the same, the number of hash functions used will be the one
> that was set for the pinned map.
>
> Signed-off-by: Joanne Koong <joannekoong@fb.com>
> ---
>  include/uapi/linux/bpf.h        |  5 ++++-
>  tools/include/uapi/linux/bpf.h  |  5 ++++-
>  tools/lib/bpf/bpf.c             |  2 ++
>  tools/lib/bpf/bpf.h             |  1 +
>  tools/lib/bpf/libbpf.c          | 32 +++++++++++++++++++++++++++-----
>  tools/lib/bpf/libbpf.h          |  2 ++
>  tools/lib/bpf/libbpf.map        |  1 +
>  tools/lib/bpf/libbpf_internal.h |  4 +++-
>  8 files changed, 44 insertions(+), 8 deletions(-)
>
> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> index fec9fcfe0629..2e3048488feb 100644
> --- a/include/uapi/linux/bpf.h
> +++ b/include/uapi/linux/bpf.h
> @@ -1262,7 +1262,10 @@ union bpf_attr {
>                 __u32   map_flags;      /* BPF_MAP_CREATE related
>                                          * flags defined above.
>                                          */
> -               __u32   inner_map_fd;   /* fd pointing to the inner map */
> +               union {
> +                       __u32   inner_map_fd;   /* fd pointing to the inner map */
> +                       __u32   nr_hash_funcs;  /* or number of hash functions */
> +               };
>                 __u32   numa_node;      /* numa node (effective only if
>                                          * BPF_F_NUMA_NODE is set).
>                                          */
> diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
> index fec9fcfe0629..2e3048488feb 100644
> --- a/tools/include/uapi/linux/bpf.h
> +++ b/tools/include/uapi/linux/bpf.h
> @@ -1262,7 +1262,10 @@ union bpf_attr {
>                 __u32   map_flags;      /* BPF_MAP_CREATE related
>                                          * flags defined above.
>                                          */
> -               __u32   inner_map_fd;   /* fd pointing to the inner map */
> +               union {
> +                       __u32   inner_map_fd;   /* fd pointing to the inner map */
> +                       __u32   nr_hash_funcs;  /* or number of hash functions */
> +               };
>                 __u32   numa_node;      /* numa node (effective only if
>                                          * BPF_F_NUMA_NODE is set).
>                                          */

these changes should be part of patch 1, otherwise patch 1 leaves
kernel in non-compilable state and breaks bisection


> diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
> index 2401fad090c5..8a9dd4f6d6c8 100644
> --- a/tools/lib/bpf/bpf.c
> +++ b/tools/lib/bpf/bpf.c
> @@ -100,6 +100,8 @@ int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr)
>         if (attr.map_type == BPF_MAP_TYPE_STRUCT_OPS)
>                 attr.btf_vmlinux_value_type_id =
>                         create_attr->btf_vmlinux_value_type_id;
> +       else if (attr.map_type == BPF_MAP_TYPE_BLOOM_FILTER)
> +               attr.nr_hash_funcs = create_attr->nr_hash_funcs;
>         else
>                 attr.inner_map_fd = create_attr->inner_map_fd;
>
> diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
> index 6fffb3cdf39b..1194b6f01572 100644
> --- a/tools/lib/bpf/bpf.h
> +++ b/tools/lib/bpf/bpf.h
> @@ -49,6 +49,7 @@ struct bpf_create_map_attr {
>         union {
>                 __u32 inner_map_fd;
>                 __u32 btf_vmlinux_value_type_id;
> +               __u32 nr_hash_funcs;
>         };
>  };
>
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index da65a1666a5e..e51e68a07aaf 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -378,6 +378,7 @@ struct bpf_map {
>         char *pin_path;
>         bool pinned;
>         bool reused;
> +       __u32 nr_hash_funcs;

nit: please keep it next to inner_map_fd field

>  };
>
>  enum extern_type {
> @@ -1291,6 +1292,11 @@ static bool bpf_map_type__is_map_in_map(enum bpf_map_type type)
>         return false;
>  }
>
> +static inline bool bpf_map__is_bloom_filter(const struct bpf_map *map)
> +{
> +       return map->def.type == BPF_MAP_TYPE_BLOOM_FILTER;
> +}

this is used in only one place, it's ok to just open-code it

> +
>  int bpf_object__section_size(const struct bpf_object *obj, const char *name,
>                              __u32 *size)
>  {

[...]

> @@ -8610,6 +8624,14 @@ int bpf_map__set_value_size(struct bpf_map *map, __u32 size)
>         return 0;
>  }
>
> +int bpf_map__set_nr_hash_funcs(struct bpf_map *map, __u32 nr_hash_funcs)
> +{
> +       if (map->fd >= 0)
> +               return libbpf_err(-EBUSY);

should we disallow this for anything but BLOOM_FILTER?

> +       map->nr_hash_funcs = nr_hash_funcs;
> +       return 0;
> +}
> +
>  __u32 bpf_map__btf_key_type_id(const struct bpf_map *map)
>  {
>         return map ? map->btf_key_type_id : 0;
> diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
> index d0bedd673273..5c441744f766 100644
> --- a/tools/lib/bpf/libbpf.h
> +++ b/tools/lib/bpf/libbpf.h
> @@ -550,6 +550,8 @@ LIBBPF_API __u32 bpf_map__btf_value_type_id(const struct bpf_map *map);
>  /* get/set map if_index */
>  LIBBPF_API __u32 bpf_map__ifindex(const struct bpf_map *map);
>  LIBBPF_API int bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
> +/* set nr_hash_funcs */
> +LIBBPF_API int bpf_map__set_nr_hash_funcs(struct bpf_map *map, __u32 nr_hash_funcs);

Let's not add this setter at all right now. Let's allow setting this
from BPF source code only in BTF map definition. It's unlikely anyone
would be setting the number of hash functions dynamically and I just
hate the idea of this one-off setter just for one specific map type.
We can always add it later if there really will be a need for that.

>
>  typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *);
>  LIBBPF_API int bpf_map__set_priv(struct bpf_map *map, void *priv,

[...]
Andrii Nakryiko Sept. 22, 2021, 11:14 p.m. UTC | #3
On Tue, Sep 21, 2021 at 7:02 PM Joanne Koong <joannekoong@fb.com> wrote:
>
>
> On 9/21/21 2:02 PM, Joanne Koong wrote:
> > This patch adds the libbpf infrastructure that will allow the user to
> > specify a configurable number of hash functions to use for the bloom
> > filter map.
> >
> > Please note that this patch does not enforce that a pinned bloom filter
> > map may only be reused if the number of hash functions is the same. If
> > they are not the same, the number of hash functions used will be the one
> > that was set for the pinned map.
> >
> > Signed-off-by: Joanne Koong <joannekoong@fb.com>
> > ---
> >   include/uapi/linux/bpf.h        |  5 ++++-
> >   tools/include/uapi/linux/bpf.h  |  5 ++++-
> >   tools/lib/bpf/bpf.c             |  2 ++
> >   tools/lib/bpf/bpf.h             |  1 +
> >   tools/lib/bpf/libbpf.c          | 32 +++++++++++++++++++++++++++-----
> >   tools/lib/bpf/libbpf.h          |  2 ++
> >   tools/lib/bpf/libbpf.map        |  1 +
> >   tools/lib/bpf/libbpf_internal.h |  4 +++-
> >   8 files changed, 44 insertions(+), 8 deletions(-)
> >

[...]

> >
> >   struct btf_map_def {
> > @@ -201,6 +202,7 @@ struct btf_map_def {
> >       __u32 map_flags;
> >       __u32 numa_node;
> >       __u32 pinning;
> > +     __u32 nr_hash_funcs;
> >   };
> >
>
> I just realized that Andrii's comment on v1 stated that btf_map_def is
> fixed indefinitely.
>
> This implies that for bloom filter maps where the number of hash
> functions needs to be set,
> we will not be able to use the BTF-defined format and will instead need
> to use the older
> map definition that uses bpf_map_def. Is my understanding of this
> correct? If so, I will go
> ahead and fix this for v4.

You are confusing bpf_map_def (which is part of the public libbpf API,
even if to-be-deprecated) and btf_map_def, which is only
libbpf-internal. So it's ok to modify that struct.

>
> >   int parse_btf_map_def(const char *map_name, struct btf *btf,
diff mbox series

Patch

diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index fec9fcfe0629..2e3048488feb 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -1262,7 +1262,10 @@  union bpf_attr {
 		__u32	map_flags;	/* BPF_MAP_CREATE related
 					 * flags defined above.
 					 */
-		__u32	inner_map_fd;	/* fd pointing to the inner map */
+		union {
+			__u32	inner_map_fd;	/* fd pointing to the inner map */
+			__u32	nr_hash_funcs;  /* or number of hash functions */
+		};
 		__u32	numa_node;	/* numa node (effective only if
 					 * BPF_F_NUMA_NODE is set).
 					 */
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index fec9fcfe0629..2e3048488feb 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -1262,7 +1262,10 @@  union bpf_attr {
 		__u32	map_flags;	/* BPF_MAP_CREATE related
 					 * flags defined above.
 					 */
-		__u32	inner_map_fd;	/* fd pointing to the inner map */
+		union {
+			__u32	inner_map_fd;	/* fd pointing to the inner map */
+			__u32	nr_hash_funcs;  /* or number of hash functions */
+		};
 		__u32	numa_node;	/* numa node (effective only if
 					 * BPF_F_NUMA_NODE is set).
 					 */
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 2401fad090c5..8a9dd4f6d6c8 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -100,6 +100,8 @@  int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr)
 	if (attr.map_type == BPF_MAP_TYPE_STRUCT_OPS)
 		attr.btf_vmlinux_value_type_id =
 			create_attr->btf_vmlinux_value_type_id;
+	else if (attr.map_type == BPF_MAP_TYPE_BLOOM_FILTER)
+		attr.nr_hash_funcs = create_attr->nr_hash_funcs;
 	else
 		attr.inner_map_fd = create_attr->inner_map_fd;
 
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 6fffb3cdf39b..1194b6f01572 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -49,6 +49,7 @@  struct bpf_create_map_attr {
 	union {
 		__u32 inner_map_fd;
 		__u32 btf_vmlinux_value_type_id;
+		__u32 nr_hash_funcs;
 	};
 };
 
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index da65a1666a5e..e51e68a07aaf 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -378,6 +378,7 @@  struct bpf_map {
 	char *pin_path;
 	bool pinned;
 	bool reused;
+	__u32 nr_hash_funcs;
 };
 
 enum extern_type {
@@ -1291,6 +1292,11 @@  static bool bpf_map_type__is_map_in_map(enum bpf_map_type type)
 	return false;
 }
 
+static inline bool bpf_map__is_bloom_filter(const struct bpf_map *map)
+{
+	return map->def.type == BPF_MAP_TYPE_BLOOM_FILTER;
+}
+
 int bpf_object__section_size(const struct bpf_object *obj, const char *name,
 			     __u32 *size)
 {
@@ -2238,6 +2244,10 @@  int parse_btf_map_def(const char *map_name, struct btf *btf,
 			}
 			map_def->pinning = val;
 			map_def->parts |= MAP_DEF_PINNING;
+		} else if (strcmp(name, "nr_hash_funcs") == 0) {
+			if (!get_map_field_int(map_name, btf, m, &map_def->nr_hash_funcs))
+				return -EINVAL;
+			map_def->parts |= MAP_DEF_NR_HASH_FUNCS;
 		} else {
 			if (strict) {
 				pr_warn("map '%s': unknown field '%s'.\n", map_name, name);
@@ -2266,6 +2276,7 @@  static void fill_map_from_def(struct bpf_map *map, const struct btf_map_def *def
 	map->numa_node = def->numa_node;
 	map->btf_key_type_id = def->key_type_id;
 	map->btf_value_type_id = def->value_type_id;
+	map->nr_hash_funcs = def->nr_hash_funcs;
 
 	if (def->parts & MAP_DEF_MAP_TYPE)
 		pr_debug("map '%s': found type = %u.\n", map->name, def->map_type);
@@ -2290,6 +2301,8 @@  static void fill_map_from_def(struct bpf_map *map, const struct btf_map_def *def
 		pr_debug("map '%s': found pinning = %u.\n", map->name, def->pinning);
 	if (def->parts & MAP_DEF_NUMA_NODE)
 		pr_debug("map '%s': found numa_node = %u.\n", map->name, def->numa_node);
+	if (def->parts & MAP_DEF_NR_HASH_FUNCS)
+		pr_debug("map '%s': found nr_hash_funcs = %u.\n", map->name, def->nr_hash_funcs);
 
 	if (def->parts & MAP_DEF_INNER_MAP)
 		pr_debug("map '%s': found inner map definition.\n", map->name);
@@ -4616,10 +4629,6 @@  static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b
 		create_attr.max_entries = def->max_entries;
 	}
 
-	if (bpf_map__is_struct_ops(map))
-		create_attr.btf_vmlinux_value_type_id =
-			map->btf_vmlinux_value_type_id;
-
 	create_attr.btf_fd = 0;
 	create_attr.btf_key_type_id = 0;
 	create_attr.btf_value_type_id = 0;
@@ -4629,7 +4638,12 @@  static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b
 		create_attr.btf_value_type_id = map->btf_value_type_id;
 	}
 
-	if (bpf_map_type__is_map_in_map(def->type)) {
+	if (bpf_map__is_struct_ops(map)) {
+		create_attr.btf_vmlinux_value_type_id =
+			map->btf_vmlinux_value_type_id;
+	} else if (bpf_map__is_bloom_filter(map)) {
+		create_attr.nr_hash_funcs = map->nr_hash_funcs;
+	} else if (bpf_map_type__is_map_in_map(def->type)) {
 		if (map->inner_map) {
 			err = bpf_object__create_map(obj, map->inner_map, true);
 			if (err) {
@@ -8610,6 +8624,14 @@  int bpf_map__set_value_size(struct bpf_map *map, __u32 size)
 	return 0;
 }
 
+int bpf_map__set_nr_hash_funcs(struct bpf_map *map, __u32 nr_hash_funcs)
+{
+	if (map->fd >= 0)
+		return libbpf_err(-EBUSY);
+	map->nr_hash_funcs = nr_hash_funcs;
+	return 0;
+}
+
 __u32 bpf_map__btf_key_type_id(const struct bpf_map *map)
 {
 	return map ? map->btf_key_type_id : 0;
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index d0bedd673273..5c441744f766 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -550,6 +550,8 @@  LIBBPF_API __u32 bpf_map__btf_value_type_id(const struct bpf_map *map);
 /* get/set map if_index */
 LIBBPF_API __u32 bpf_map__ifindex(const struct bpf_map *map);
 LIBBPF_API int bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
+/* set nr_hash_funcs */
+LIBBPF_API int bpf_map__set_nr_hash_funcs(struct bpf_map *map, __u32 nr_hash_funcs);
 
 typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *);
 LIBBPF_API int bpf_map__set_priv(struct bpf_map *map, void *priv,
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index 9e649cf9e771..ee0e1e7648f4 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -385,6 +385,7 @@  LIBBPF_0.5.0 {
 		btf__load_vmlinux_btf;
 		btf_dump__dump_type_data;
 		libbpf_set_strict_mode;
+		bpf_map__set_nr_hash_funcs;
 } LIBBPF_0.4.0;
 
 LIBBPF_0.6.0 {
diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h
index ceb0c98979bc..95dbbeba231f 100644
--- a/tools/lib/bpf/libbpf_internal.h
+++ b/tools/lib/bpf/libbpf_internal.h
@@ -186,8 +186,9 @@  enum map_def_parts {
 	MAP_DEF_NUMA_NODE	= 0x080,
 	MAP_DEF_PINNING		= 0x100,
 	MAP_DEF_INNER_MAP	= 0x200,
+	MAP_DEF_NR_HASH_FUNCS	= 0x400,
 
-	MAP_DEF_ALL		= 0x3ff, /* combination of all above */
+	MAP_DEF_ALL		= 0x7ff, /* combination of all above */
 };
 
 struct btf_map_def {
@@ -201,6 +202,7 @@  struct btf_map_def {
 	__u32 map_flags;
 	__u32 numa_node;
 	__u32 pinning;
+	__u32 nr_hash_funcs;
 };
 
 int parse_btf_map_def(const char *map_name, struct btf *btf,