Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: sched: set dedicated tcf_walker flag when tp is empty

Using tcf_walker->stop flag to determine when tcf_walker->fn() was called
at least once is unreliable. Some classifiers set 'stop' flag on error
before calling walker callback, other classifiers used to call it with NULL
filter pointer when empty. In order to prevent further regressions, extend
tcf_walker structure with dedicated 'nonempty' flag. Set this flag in
tcf_walker->fn() implementation that is used to check if classifier has
filters configured.

Fixes: 8b64678e0af8 ("net: sched: refactor tp insert/delete for concurrent execution")
Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
Suggested-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Vlad Buslov and committed by
David S. Miller
6676d5e4 e3af71a3

+10 -4
+1
include/net/pkt_cls.h
··· 17 17 int stop; 18 18 int skip; 19 19 int count; 20 + bool nonempty; 20 21 unsigned long cookie; 21 22 int (*fn)(struct tcf_proto *, void *node, struct tcf_walker *); 22 23 };
+9 -4
net/sched/cls_api.c
··· 238 238 tcf_proto_destroy(tp, rtnl_held, extack); 239 239 } 240 240 241 - static int walker_noop(struct tcf_proto *tp, void *d, struct tcf_walker *arg) 241 + static int walker_check_empty(struct tcf_proto *tp, void *d, 242 + struct tcf_walker *arg) 242 243 { 243 - return -1; 244 + if (tp) { 245 + arg->nonempty = true; 246 + return -1; 247 + } 248 + return 0; 244 249 } 245 250 246 251 static bool tcf_proto_is_empty(struct tcf_proto *tp, bool rtnl_held) 247 252 { 248 - struct tcf_walker walker = { .fn = walker_noop, }; 253 + struct tcf_walker walker = { .fn = walker_check_empty, }; 249 254 250 255 if (tp->ops->walk) { 251 256 tp->ops->walk(tp, &walker, rtnl_held); 252 - return !walker.stop; 257 + return !walker.nonempty; 253 258 } 254 259 return true; 255 260 }