Skip to content

Commit 76cf546

Browse files
congwangdavem330
authored andcommitted
net_sched: use idr to allocate bpf filter handles
Instead of calling cls_bpf_get() in a loop to find a unused handle, just switch to idr API to allocate new handles. Cc: Daniel Borkmann <[email protected]> Cc: Chris Mi <[email protected]> Cc: Jamal Hadi Salim <[email protected]> Signed-off-by: Cong Wang <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 8f1975e commit 76cf546

File tree

1 file changed

+28
-29
lines changed

1 file changed

+28
-29
lines changed

net/sched/cls_bpf.c

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/skbuff.h>
1818
#include <linux/filter.h>
1919
#include <linux/bpf.h>
20+
#include <linux/idr.h>
2021

2122
#include <net/rtnetlink.h>
2223
#include <net/pkt_cls.h>
@@ -32,7 +33,7 @@ MODULE_DESCRIPTION("TC BPF based classifier");
3233

3334
struct cls_bpf_head {
3435
struct list_head plist;
35-
u32 hgen;
36+
struct idr handle_idr;
3637
struct rcu_head rcu;
3738
};
3839

@@ -238,6 +239,7 @@ static int cls_bpf_init(struct tcf_proto *tp)
238239
return -ENOBUFS;
239240

240241
INIT_LIST_HEAD_RCU(&head->plist);
242+
idr_init(&head->handle_idr);
241243
rcu_assign_pointer(tp->root, head);
242244

243245
return 0;
@@ -264,6 +266,9 @@ static void cls_bpf_delete_prog_rcu(struct rcu_head *rcu)
264266

265267
static void __cls_bpf_delete(struct tcf_proto *tp, struct cls_bpf_prog *prog)
266268
{
269+
struct cls_bpf_head *head = rtnl_dereference(tp->root);
270+
271+
idr_remove_ext(&head->handle_idr, prog->handle);
267272
cls_bpf_stop_offload(tp, prog);
268273
list_del_rcu(&prog->link);
269274
tcf_unbind_filter(tp, &prog->res);
@@ -287,6 +292,7 @@ static void cls_bpf_destroy(struct tcf_proto *tp)
287292
list_for_each_entry_safe(prog, tmp, &head->plist, link)
288293
__cls_bpf_delete(tp, prog);
289294

295+
idr_destroy(&head->handle_idr);
290296
kfree_rcu(head, rcu);
291297
}
292298

@@ -421,27 +427,6 @@ static int cls_bpf_set_parms(struct net *net, struct tcf_proto *tp,
421427
return 0;
422428
}
423429

424-
static u32 cls_bpf_grab_new_handle(struct tcf_proto *tp,
425-
struct cls_bpf_head *head)
426-
{
427-
unsigned int i = 0x80000000;
428-
u32 handle;
429-
430-
do {
431-
if (++head->hgen == 0x7FFFFFFF)
432-
head->hgen = 1;
433-
} while (--i > 0 && cls_bpf_get(tp, head->hgen));
434-
435-
if (unlikely(i == 0)) {
436-
pr_err("Insufficient number of handles\n");
437-
handle = 0;
438-
} else {
439-
handle = head->hgen;
440-
}
441-
442-
return handle;
443-
}
444-
445430
static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
446431
struct tcf_proto *tp, unsigned long base,
447432
u32 handle, struct nlattr **tca,
@@ -451,6 +436,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
451436
struct cls_bpf_prog *oldprog = *arg;
452437
struct nlattr *tb[TCA_BPF_MAX + 1];
453438
struct cls_bpf_prog *prog;
439+
unsigned long idr_index;
454440
int ret;
455441

456442
if (tca[TCA_OPTIONS] == NULL)
@@ -476,21 +462,30 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
476462
}
477463
}
478464

479-
if (handle == 0)
480-
prog->handle = cls_bpf_grab_new_handle(tp, head);
481-
else
465+
if (handle == 0) {
466+
ret = idr_alloc_ext(&head->handle_idr, prog, &idr_index,
467+
1, 0x7FFFFFFF, GFP_KERNEL);
468+
if (ret)
469+
goto errout;
470+
prog->handle = idr_index;
471+
} else {
472+
if (!oldprog) {
473+
ret = idr_alloc_ext(&head->handle_idr, prog, &idr_index,
474+
handle, handle + 1, GFP_KERNEL);
475+
if (ret)
476+
goto errout;
477+
}
482478
prog->handle = handle;
483-
if (prog->handle == 0) {
484-
ret = -EINVAL;
485-
goto errout;
486479
}
487480

488481
ret = cls_bpf_set_parms(net, tp, prog, base, tb, tca[TCA_RATE], ovr);
489482
if (ret < 0)
490-
goto errout;
483+
goto errout_idr;
491484

492485
ret = cls_bpf_offload(tp, prog, oldprog);
493486
if (ret) {
487+
if (!oldprog)
488+
idr_remove_ext(&head->handle_idr, prog->handle);
494489
__cls_bpf_delete_prog(prog);
495490
return ret;
496491
}
@@ -499,6 +494,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
499494
prog->gen_flags |= TCA_CLS_FLAGS_NOT_IN_HW;
500495

501496
if (oldprog) {
497+
idr_replace_ext(&head->handle_idr, prog, handle);
502498
list_replace_rcu(&oldprog->link, &prog->link);
503499
tcf_unbind_filter(tp, &oldprog->res);
504500
call_rcu(&oldprog->rcu, cls_bpf_delete_prog_rcu);
@@ -509,6 +505,9 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
509505
*arg = prog;
510506
return 0;
511507

508+
errout_idr:
509+
if (!oldprog)
510+
idr_remove_ext(&head->handle_idr, prog->handle);
512511
errout:
513512
tcf_exts_destroy(&prog->exts);
514513
kfree(prog);

0 commit comments

Comments
 (0)