summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVlad Buslov <vladbu@mellanox.com>2018-07-09 13:29:11 +0300
committerDavid S. Miller <davem@davemloft.net>2018-07-13 18:24:27 -0700
commit01683a1469995cc7aaf833d6f8b3f1c1d2fc3b92 (patch)
treed93f015b6615afe81d4834c5ff052d2e3b00a001
parentc921c2077b32081617789a645120148bc8b60c98 (diff)
net: sched: refactor flower walk to iterate over idr
Extend struct tcf_walker with additional 'cookie' field. It is intended to be used by classifier walk implementations to continue iteration directly from particular filter, instead of iterating 'skip' number of times. Change flower walk implementation to save filter handle in 'cookie'. Each time flower walk is called, it looks up filter with saved handle directly with idr, instead of iterating over filter linked list 'skip' number of times. This change improves complexity of dumping flower classifier from quadratic to linearithmic. (assuming idr lookup has logarithmic complexity) Reviewed-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: Vlad Buslov <vladbu@mellanox.com> Reported-by: Simon Horman <simon.horman@netronome.com> Reviewed-by: Simon Horman <simon.horman@netronome.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/pkt_cls.h1
-rw-r--r--net/sched/cls_api.c2
-rw-r--r--net/sched/cls_flower.c20
3 files changed, 12 insertions, 11 deletions
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 2081e4219f81..e4252a176eec 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -13,6 +13,7 @@ struct tcf_walker {
int stop;
int skip;
int count;
+ unsigned long cookie;
int (*fn)(struct tcf_proto *, void *node, struct tcf_walker *);
};
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 73d9967c3739..c51b1b12450d 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -1508,7 +1508,9 @@ static bool tcf_chain_dump(struct tcf_chain *chain, struct Qdisc *q, u32 parent,
arg.w.stop = 0;
arg.w.skip = cb->args[1] - 1;
arg.w.count = 0;
+ arg.w.cookie = cb->args[2];
tp->ops->walk(tp, &arg.w);
+ cb->args[2] = arg.w.cookie;
cb->args[1] = arg.w.count + 1;
if (arg.w.stop)
return false;
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index 8b2474293db1..c53fdd411f90 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c
@@ -1099,19 +1099,17 @@ static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg)
{
struct cls_fl_head *head = rtnl_dereference(tp->root);
struct cls_fl_filter *f;
- struct fl_flow_mask *mask;
- list_for_each_entry_rcu(mask, &head->masks, list) {
- list_for_each_entry_rcu(f, &mask->filters, list) {
- if (arg->count < arg->skip)
- goto skip;
- if (arg->fn(tp, f, arg) < 0) {
- arg->stop = 1;
- break;
- }
-skip:
- arg->count++;
+ arg->count = arg->skip;
+
+ while ((f = idr_get_next_ul(&head->handle_idr,
+ &arg->cookie)) != NULL) {
+ if (arg->fn(tp, f, arg) < 0) {
+ arg->stop = 1;
+ break;
}
+ arg->cookie = f->handle + 1;
+ arg->count++;
}
}