Skip to content

Commit c15ab23

Browse files
mishuang2017davem330
authored andcommitted
net/sched: Change cls_flower to use IDR
Currently, all filters with the same priority are linked in a doubly linked list. Every filter should have a unique handle. To make the handle unique, we need to iterate the list every time to see if the handle exists or not when inserting a new filter. It is time-consuming. For example, it takes about 5m3.169s to insert 64K rules. This patch changes cls_flower to use IDR. With this patch, it takes about 0m1.127s to insert 64K rules. The improvement is huge. But please note that in this testing, all filters share the same action. If every filter has a unique action, that is another bottleneck. Follow-up patch in this patchset addresses that. Signed-off-by: Chris Mi <[email protected]> Signed-off-by: Jiri Pirko <[email protected]> Acked-by: Jamal Hadi Salim <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 388f79f commit c15ab23

File tree

1 file changed

+23
-32
lines changed

1 file changed

+23
-32
lines changed

net/sched/cls_flower.c

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,14 @@ struct cls_fl_head {
6868
struct rhashtable ht;
6969
struct fl_flow_mask mask;
7070
struct flow_dissector dissector;
71-
u32 hgen;
7271
bool mask_assigned;
7372
struct list_head filters;
7473
struct rhashtable_params ht_params;
7574
union {
7675
struct work_struct work;
7776
struct rcu_head rcu;
7877
};
78+
struct idr handle_idr;
7979
};
8080

8181
struct cls_fl_filter {
@@ -210,6 +210,7 @@ static int fl_init(struct tcf_proto *tp)
210210

211211
INIT_LIST_HEAD_RCU(&head->filters);
212212
rcu_assign_pointer(tp->root, head);
213+
idr_init(&head->handle_idr);
213214

214215
return 0;
215216
}
@@ -295,6 +296,9 @@ static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
295296

296297
static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f)
297298
{
299+
struct cls_fl_head *head = rtnl_dereference(tp->root);
300+
301+
idr_remove_ext(&head->handle_idr, f->handle);
298302
list_del_rcu(&f->list);
299303
if (!tc_skip_hw(f->flags))
300304
fl_hw_destroy_filter(tp, f);
@@ -327,6 +331,7 @@ static void fl_destroy(struct tcf_proto *tp)
327331

328332
list_for_each_entry_safe(f, next, &head->filters, list)
329333
__fl_delete(tp, f);
334+
idr_destroy(&head->handle_idr);
330335

331336
__module_get(THIS_MODULE);
332337
call_rcu(&head->rcu, fl_destroy_rcu);
@@ -335,12 +340,8 @@ static void fl_destroy(struct tcf_proto *tp)
335340
static void *fl_get(struct tcf_proto *tp, u32 handle)
336341
{
337342
struct cls_fl_head *head = rtnl_dereference(tp->root);
338-
struct cls_fl_filter *f;
339343

340-
list_for_each_entry(f, &head->filters, list)
341-
if (f->handle == handle)
342-
return f;
343-
return NULL;
344+
return idr_find_ext(&head->handle_idr, handle);
344345
}
345346

346347
static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
@@ -859,27 +860,6 @@ static int fl_set_parms(struct net *net, struct tcf_proto *tp,
859860
return 0;
860861
}
861862

862-
static u32 fl_grab_new_handle(struct tcf_proto *tp,
863-
struct cls_fl_head *head)
864-
{
865-
unsigned int i = 0x80000000;
866-
u32 handle;
867-
868-
do {
869-
if (++head->hgen == 0x7FFFFFFF)
870-
head->hgen = 1;
871-
} while (--i > 0 && fl_get(tp, head->hgen));
872-
873-
if (unlikely(i == 0)) {
874-
pr_err("Insufficient number of handles\n");
875-
handle = 0;
876-
} else {
877-
handle = head->hgen;
878-
}
879-
880-
return handle;
881-
}
882-
883863
static int fl_change(struct net *net, struct sk_buff *in_skb,
884864
struct tcf_proto *tp, unsigned long base,
885865
u32 handle, struct nlattr **tca,
@@ -890,6 +870,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
890870
struct cls_fl_filter *fnew;
891871
struct nlattr **tb;
892872
struct fl_flow_mask mask = {};
873+
unsigned long idr_index;
893874
int err;
894875

895876
if (!tca[TCA_OPTIONS])
@@ -920,13 +901,21 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
920901
goto errout;
921902

922903
if (!handle) {
923-
handle = fl_grab_new_handle(tp, head);
924-
if (!handle) {
925-
err = -EINVAL;
904+
err = idr_alloc_ext(&head->handle_idr, fnew, &idr_index,
905+
1, 0x80000000, GFP_KERNEL);
906+
if (err)
926907
goto errout;
927-
}
908+
fnew->handle = idr_index;
909+
}
910+
911+
/* user specifies a handle and it doesn't exist */
912+
if (handle && !fold) {
913+
err = idr_alloc_ext(&head->handle_idr, fnew, &idr_index,
914+
handle, handle + 1, GFP_KERNEL);
915+
if (err)
916+
goto errout;
917+
fnew->handle = idr_index;
928918
}
929-
fnew->handle = handle;
930919

931920
if (tb[TCA_FLOWER_FLAGS]) {
932921
fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
@@ -980,6 +969,8 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
980969
*arg = fnew;
981970

982971
if (fold) {
972+
fnew->handle = handle;
973+
idr_replace_ext(&head->handle_idr, fnew, fnew->handle);
983974
list_replace_rcu(&fold->list, &fnew->list);
984975
tcf_unbind_filter(tp, &fold->res);
985976
call_rcu(&fold->rcu, fl_destroy_filter);

0 commit comments

Comments
 (0)