Skip to content

Commit 9e3e66c

Browse files
Martin KaFai LauAlexei Starovoitov
authored andcommitted
bpf: Add bpf_rbtree_{root,left,right} kfunc
In a bpf fq implementation that is much closer to the kernel fq, it will need to traverse the rbtree: https://lore.kernel.org/bpf/[email protected]/ The much simplified logic that uses the bpf_rbtree_{root,left,right} to traverse the rbtree is like: struct fq_flow { struct bpf_rb_node fq_node; struct bpf_rb_node rate_node; struct bpf_refcount refcount; unsigned long sk_long; }; struct fq_flow_root { struct bpf_spin_lock lock; struct bpf_rb_root root __contains(fq_flow, fq_node); }; struct fq_flow *fq_classify(...) { struct bpf_rb_node *tofree[FQ_GC_MAX]; struct fq_flow_root *root; struct fq_flow *gc_f, *f; struct bpf_rb_node *p; int i, fcnt = 0; /* ... */ f = NULL; bpf_spin_lock(&root->lock); p = bpf_rbtree_root(&root->root); while (can_loop) { if (!p) break; gc_f = bpf_rb_entry(p, struct fq_flow, fq_node); if (gc_f->sk_long == sk_long) { f = bpf_refcount_acquire(gc_f); break; } /* To be removed from the rbtree */ if (fcnt < FQ_GC_MAX && fq_gc_candidate(gc_f, jiffies_now)) tofree[fcnt++] = p; if (gc_f->sk_long > sk_long) p = bpf_rbtree_left(&root->root, p); else p = bpf_rbtree_right(&root->root, p); } /* remove from the rbtree */ for (i = 0; i < fcnt; i++) { p = tofree[i]; tofree[i] = bpf_rbtree_remove(&root->root, p); } bpf_spin_unlock(&root->lock); /* bpf_obj_drop the fq_flow(s) that have just been removed * from the rbtree. */ for (i = 0; i < fcnt; i++) { p = tofree[i]; if (p) { gc_f = bpf_rb_entry(p, struct fq_flow, fq_node); bpf_obj_drop(gc_f); } } return f; } The above simplified code needs to traverse the rbtree for two purposes, 1) find the flow with the desired sk_long value 2) while searching for the sk_long, collect flows that are the fq_gc_candidate. They will be removed from the rbtree. This patch adds the bpf_rbtree_{root,left,right} kfunc to enable the rbtree traversal. The returned bpf_rb_node pointer will be a non-owning reference which is the same as the returned pointer of the exisiting bpf_rbtree_first kfunc. Acked-by: Kumar Kartikeya Dwivedi <[email protected]> Signed-off-by: Martin KaFai Lau <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 7faccdf commit 9e3e66c

File tree

2 files changed

+48
-4
lines changed

2 files changed

+48
-4
lines changed

kernel/bpf/helpers.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2366,6 +2366,33 @@ __bpf_kfunc struct bpf_rb_node *bpf_rbtree_first(struct bpf_rb_root *root)
23662366
return (struct bpf_rb_node *)rb_first_cached(r);
23672367
}
23682368

2369+
__bpf_kfunc struct bpf_rb_node *bpf_rbtree_root(struct bpf_rb_root *root)
2370+
{
2371+
struct rb_root_cached *r = (struct rb_root_cached *)root;
2372+
2373+
return (struct bpf_rb_node *)r->rb_root.rb_node;
2374+
}
2375+
2376+
__bpf_kfunc struct bpf_rb_node *bpf_rbtree_left(struct bpf_rb_root *root, struct bpf_rb_node *node)
2377+
{
2378+
struct bpf_rb_node_kern *node_internal = (struct bpf_rb_node_kern *)node;
2379+
2380+
if (READ_ONCE(node_internal->owner) != root)
2381+
return NULL;
2382+
2383+
return (struct bpf_rb_node *)node_internal->rb_node.rb_left;
2384+
}
2385+
2386+
__bpf_kfunc struct bpf_rb_node *bpf_rbtree_right(struct bpf_rb_root *root, struct bpf_rb_node *node)
2387+
{
2388+
struct bpf_rb_node_kern *node_internal = (struct bpf_rb_node_kern *)node;
2389+
2390+
if (READ_ONCE(node_internal->owner) != root)
2391+
return NULL;
2392+
2393+
return (struct bpf_rb_node *)node_internal->rb_node.rb_right;
2394+
}
2395+
23692396
/**
23702397
* bpf_task_acquire - Acquire a reference to a task. A task acquired by this
23712398
* kfunc which is not stored in a map as a kptr, must be released by calling
@@ -3214,6 +3241,9 @@ BTF_ID_FLAGS(func, bpf_task_release, KF_RELEASE)
32143241
BTF_ID_FLAGS(func, bpf_rbtree_remove, KF_ACQUIRE | KF_RET_NULL)
32153242
BTF_ID_FLAGS(func, bpf_rbtree_add_impl)
32163243
BTF_ID_FLAGS(func, bpf_rbtree_first, KF_RET_NULL)
3244+
BTF_ID_FLAGS(func, bpf_rbtree_root, KF_RET_NULL)
3245+
BTF_ID_FLAGS(func, bpf_rbtree_left, KF_RET_NULL)
3246+
BTF_ID_FLAGS(func, bpf_rbtree_right, KF_RET_NULL)
32173247

32183248
#ifdef CONFIG_CGROUPS
32193249
BTF_ID_FLAGS(func, bpf_cgroup_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL)

kernel/bpf/verifier.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12081,6 +12081,9 @@ enum special_kfunc_type {
1208112081
KF_bpf_rbtree_remove,
1208212082
KF_bpf_rbtree_add_impl,
1208312083
KF_bpf_rbtree_first,
12084+
KF_bpf_rbtree_root,
12085+
KF_bpf_rbtree_left,
12086+
KF_bpf_rbtree_right,
1208412087
KF_bpf_dynptr_from_skb,
1208512088
KF_bpf_dynptr_from_xdp,
1208612089
KF_bpf_dynptr_slice,
@@ -12121,6 +12124,9 @@ BTF_ID(func, bpf_rdonly_cast)
1212112124
BTF_ID(func, bpf_rbtree_remove)
1212212125
BTF_ID(func, bpf_rbtree_add_impl)
1212312126
BTF_ID(func, bpf_rbtree_first)
12127+
BTF_ID(func, bpf_rbtree_root)
12128+
BTF_ID(func, bpf_rbtree_left)
12129+
BTF_ID(func, bpf_rbtree_right)
1212412130
#ifdef CONFIG_NET
1212512131
BTF_ID(func, bpf_dynptr_from_skb)
1212612132
BTF_ID(func, bpf_dynptr_from_xdp)
@@ -12156,6 +12162,9 @@ BTF_ID(func, bpf_rcu_read_unlock)
1215612162
BTF_ID(func, bpf_rbtree_remove)
1215712163
BTF_ID(func, bpf_rbtree_add_impl)
1215812164
BTF_ID(func, bpf_rbtree_first)
12165+
BTF_ID(func, bpf_rbtree_root)
12166+
BTF_ID(func, bpf_rbtree_left)
12167+
BTF_ID(func, bpf_rbtree_right)
1215912168
#ifdef CONFIG_NET
1216012169
BTF_ID(func, bpf_dynptr_from_skb)
1216112170
BTF_ID(func, bpf_dynptr_from_xdp)
@@ -12591,7 +12600,10 @@ static bool is_bpf_rbtree_api_kfunc(u32 btf_id)
1259112600
{
1259212601
return btf_id == special_kfunc_list[KF_bpf_rbtree_add_impl] ||
1259312602
btf_id == special_kfunc_list[KF_bpf_rbtree_remove] ||
12594-
btf_id == special_kfunc_list[KF_bpf_rbtree_first];
12603+
btf_id == special_kfunc_list[KF_bpf_rbtree_first] ||
12604+
btf_id == special_kfunc_list[KF_bpf_rbtree_root] ||
12605+
btf_id == special_kfunc_list[KF_bpf_rbtree_left] ||
12606+
btf_id == special_kfunc_list[KF_bpf_rbtree_right];
1259512607
}
1259612608

1259712609
static bool is_bpf_iter_num_api_kfunc(u32 btf_id)
@@ -12691,7 +12703,9 @@ static bool check_kfunc_is_graph_node_api(struct bpf_verifier_env *env,
1269112703
break;
1269212704
case BPF_RB_NODE:
1269312705
ret = (kfunc_btf_id == special_kfunc_list[KF_bpf_rbtree_remove] ||
12694-
kfunc_btf_id == special_kfunc_list[KF_bpf_rbtree_add_impl]);
12706+
kfunc_btf_id == special_kfunc_list[KF_bpf_rbtree_add_impl] ||
12707+
kfunc_btf_id == special_kfunc_list[KF_bpf_rbtree_left] ||
12708+
kfunc_btf_id == special_kfunc_list[KF_bpf_rbtree_right]);
1269512709
break;
1269612710
default:
1269712711
verbose(env, "verifier internal error: unexpected graph node argument type %s\n",
@@ -13216,11 +13230,11 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
1321613230
}
1321713231
} else {
1321813232
if (!type_is_non_owning_ref(reg->type) || reg->ref_obj_id) {
13219-
verbose(env, "rbtree_remove node input must be non-owning ref\n");
13233+
verbose(env, "%s node input must be non-owning ref\n", func_name);
1322013234
return -EINVAL;
1322113235
}
1322213236
if (in_rbtree_lock_required_cb(env)) {
13223-
verbose(env, "rbtree_remove not allowed in rbtree cb\n");
13237+
verbose(env, "%s not allowed in rbtree cb\n", func_name);
1322413238
return -EINVAL;
1322513239
}
1322613240
}

0 commit comments

Comments
 (0)