Skip to content

Commit 69c087b

Browse files
yonghong-songAlexei Starovoitov
authored and
Alexei Starovoitov
committed
bpf: Add bpf_for_each_map_elem() helper
The bpf_for_each_map_elem() helper is introduced which iterates all map elements with a callback function. The helper signature looks like long bpf_for_each_map_elem(map, callback_fn, callback_ctx, flags) and for each map element, the callback_fn will be called. For example, like hashmap, the callback signature may look like long callback_fn(map, key, val, callback_ctx) There are two known use cases for this. One is from upstream ([1]) where a for_each_map_elem helper may help implement a timeout mechanism in a more generic way. Another is from our internal discussion for a firewall use case where a map contains all the rules. The packet data can be compared to all these rules to decide allow or deny the packet. For array maps, users can already use a bounded loop to traverse elements. Using this helper can avoid using bounded loop. For other type of maps (e.g., hash maps) where bounded loop is hard or impossible to use, this helper provides a convenient way to operate on all elements. For callback_fn, besides map and map element, a callback_ctx, allocated on caller stack, is also passed to the callback function. This callback_ctx argument can provide additional input and allow to write to caller stack for output. If the callback_fn returns 0, the helper will iterate through next element if available. If the callback_fn returns 1, the helper will stop iterating and returns to the bpf program. Other return values are not used for now. Currently, this helper is only available with jit. It is possible to make it work with interpreter with so effort but I leave it as the future work. [1]: https://lore.kernel.org/bpf/[email protected]/ Signed-off-by: Yonghong Song <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Acked-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 282a0f4 commit 69c087b

File tree

8 files changed

+307
-13
lines changed

8 files changed

+307
-13
lines changed

include/linux/bpf.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct bpf_local_storage;
3939
struct bpf_local_storage_map;
4040
struct kobject;
4141
struct mem_cgroup;
42+
struct bpf_func_state;
4243

4344
extern struct idr btf_idr;
4445
extern spinlock_t btf_idr_lock;
@@ -129,6 +130,13 @@ struct bpf_map_ops {
129130
bool (*map_meta_equal)(const struct bpf_map *meta0,
130131
const struct bpf_map *meta1);
131132

133+
134+
int (*map_set_for_each_callback_args)(struct bpf_verifier_env *env,
135+
struct bpf_func_state *caller,
136+
struct bpf_func_state *callee);
137+
int (*map_for_each_callback)(struct bpf_map *map, void *callback_fn,
138+
void *callback_ctx, u64 flags);
139+
132140
/* BTF name and id of struct allocated by map_alloc */
133141
const char * const map_btf_name;
134142
int *map_btf_id;
@@ -295,6 +303,8 @@ enum bpf_arg_type {
295303
ARG_CONST_ALLOC_SIZE_OR_ZERO, /* number of allocated bytes requested */
296304
ARG_PTR_TO_BTF_ID_SOCK_COMMON, /* pointer to in-kernel sock_common or bpf-mirrored bpf_sock */
297305
ARG_PTR_TO_PERCPU_BTF_ID, /* pointer to in-kernel percpu type */
306+
ARG_PTR_TO_FUNC, /* pointer to a bpf program function */
307+
ARG_PTR_TO_STACK_OR_NULL, /* pointer to stack or NULL */
298308
__BPF_ARG_TYPE_MAX,
299309
};
300310

@@ -411,6 +421,8 @@ enum bpf_reg_type {
411421
PTR_TO_RDWR_BUF, /* reg points to a read/write buffer */
412422
PTR_TO_RDWR_BUF_OR_NULL, /* reg points to a read/write buffer or NULL */
413423
PTR_TO_PERCPU_BTF_ID, /* reg points to a percpu kernel variable */
424+
PTR_TO_FUNC, /* reg points to a bpf program function */
425+
PTR_TO_MAP_KEY, /* reg points to a map element key */
414426
};
415427

416428
/* The information passed from prog-specific *_is_valid_access
@@ -1887,6 +1899,7 @@ extern const struct bpf_func_proto bpf_sock_from_file_proto;
18871899
extern const struct bpf_func_proto bpf_get_socket_ptr_cookie_proto;
18881900
extern const struct bpf_func_proto bpf_task_storage_get_proto;
18891901
extern const struct bpf_func_proto bpf_task_storage_delete_proto;
1902+
extern const struct bpf_func_proto bpf_for_each_map_elem_proto;
18901903

18911904
const struct bpf_func_proto *bpf_tracing_func_proto(
18921905
enum bpf_func_id func_id, const struct bpf_prog *prog);

include/linux/bpf_verifier.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ struct bpf_reg_state {
6868
unsigned long raw1;
6969
unsigned long raw2;
7070
} raw;
71+
72+
u32 subprogno; /* for PTR_TO_FUNC */
7173
};
7274
/* For PTR_TO_PACKET, used to find other pointers with the same variable
7375
* offset, so they can share range knowledge.
@@ -204,6 +206,7 @@ struct bpf_func_state {
204206
int acquired_refs;
205207
struct bpf_reference_state *refs;
206208
int allocated_stack;
209+
bool in_callback_fn;
207210
struct bpf_stack_state *stack;
208211
};
209212

include/uapi/linux/bpf.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,15 @@ enum bpf_link_type {
393393
* is struct/union.
394394
*/
395395
#define BPF_PSEUDO_BTF_ID 3
396+
/* insn[0].src_reg: BPF_PSEUDO_FUNC
397+
* insn[0].imm: insn offset to the func
398+
* insn[1].imm: 0
399+
* insn[0].off: 0
400+
* insn[1].off: 0
401+
* ldimm64 rewrite: address of the function
402+
* verifier type: PTR_TO_FUNC.
403+
*/
404+
#define BPF_PSEUDO_FUNC 4
396405

397406
/* when bpf_call->src_reg == BPF_PSEUDO_CALL, bpf_call->imm == pc-relative
398407
* offset to another bpf function
@@ -3909,6 +3918,34 @@ union bpf_attr {
39093918
* * **BPF_MTU_CHK_RET_FRAG_NEEDED**
39103919
* * **BPF_MTU_CHK_RET_SEGS_TOOBIG**
39113920
*
3921+
* long bpf_for_each_map_elem(struct bpf_map *map, void *callback_fn, void *callback_ctx, u64 flags)
3922+
* Description
3923+
* For each element in **map**, call **callback_fn** function with
3924+
* **map**, **callback_ctx** and other map-specific parameters.
3925+
* The **callback_fn** should be a static function and
3926+
* the **callback_ctx** should be a pointer to the stack.
3927+
* The **flags** is used to control certain aspects of the helper.
3928+
* Currently, the **flags** must be 0.
3929+
*
3930+
* The following are a list of supported map types and their
3931+
* respective expected callback signatures:
3932+
*
3933+
* BPF_MAP_TYPE_HASH, BPF_MAP_TYPE_PERCPU_HASH,
3934+
* BPF_MAP_TYPE_LRU_HASH, BPF_MAP_TYPE_LRU_PERCPU_HASH,
3935+
* BPF_MAP_TYPE_ARRAY, BPF_MAP_TYPE_PERCPU_ARRAY
3936+
*
3937+
* long (\*callback_fn)(struct bpf_map \*map, const void \*key, void \*value, void \*ctx);
3938+
*
3939+
* For per_cpu maps, the map_value is the value on the cpu where the
3940+
* bpf_prog is running.
3941+
*
3942+
* If **callback_fn** return 0, the helper will continue to the next
3943+
* element. If return value is 1, the helper will skip the rest of
3944+
* elements and return. Other return values are not used now.
3945+
*
3946+
* Return
3947+
* The number of traversed map elements for success, **-EINVAL** for
3948+
* invalid **flags**.
39123949
*/
39133950
#define __BPF_FUNC_MAPPER(FN) \
39143951
FN(unspec), \
@@ -4075,6 +4112,7 @@ union bpf_attr {
40754112
FN(ima_inode_hash), \
40764113
FN(sock_from_file), \
40774114
FN(check_mtu), \
4115+
FN(for_each_map_elem), \
40784116
/* */
40794117

40804118
/* integer value in 'imm' field of BPF_CALL instruction selects which helper

kernel/bpf/bpf_iter.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,3 +675,19 @@ int bpf_iter_run_prog(struct bpf_prog *prog, void *ctx)
675675
*/
676676
return ret == 0 ? 0 : -EAGAIN;
677677
}
678+
679+
BPF_CALL_4(bpf_for_each_map_elem, struct bpf_map *, map, void *, callback_fn,
680+
void *, callback_ctx, u64, flags)
681+
{
682+
return map->ops->map_for_each_callback(map, callback_fn, callback_ctx, flags);
683+
}
684+
685+
const struct bpf_func_proto bpf_for_each_map_elem_proto = {
686+
.func = bpf_for_each_map_elem,
687+
.gpl_only = false,
688+
.ret_type = RET_INTEGER,
689+
.arg1_type = ARG_CONST_MAP_PTR,
690+
.arg2_type = ARG_PTR_TO_FUNC,
691+
.arg3_type = ARG_PTR_TO_STACK_OR_NULL,
692+
.arg4_type = ARG_ANYTHING,
693+
};

kernel/bpf/helpers.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,8 @@ bpf_base_func_proto(enum bpf_func_id func_id)
708708
return &bpf_ringbuf_discard_proto;
709709
case BPF_FUNC_ringbuf_query:
710710
return &bpf_ringbuf_query_proto;
711+
case BPF_FUNC_for_each_map_elem:
712+
return &bpf_for_each_map_elem_proto;
711713
default:
712714
break;
713715
}

0 commit comments

Comments
 (0)