Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 01683a14 authored by Vlad Buslov's avatar Vlad Buslov Committed by David S. Miller
Browse files

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: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarVlad Buslov <vladbu@mellanox.com>
Reported-by: default avatarSimon Horman <simon.horman@netronome.com>
Reviewed-by: default avatarSimon Horman <simon.horman@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c921c207
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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 *);
};

+2 −0
Original line number Diff line number Diff line
@@ -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;
+9 −11
Original line number Diff line number Diff line
@@ -1099,21 +1099,19 @@ 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;
	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;
		}
skip:
		arg->cookie = f->handle + 1;
		arg->count++;
	}
}
}

static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
			void *cb_priv, struct netlink_ext_ack *extack)