aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/cls_route.c
diff options
context:
space:
mode:
authorCong Wang <cwang@twopensource.com>2015-03-06 14:47:59 -0500
committerDavid S. Miller <davem@davemloft.net>2015-03-09 15:35:55 -0400
commit1e052be69d045c8d0f82ff1116fd3e5a79661745 (patch)
treec237348cf8f28ca178c3ebfcec0e0013ef18b4c5 /net/sched/cls_route.c
parentfc6c6c2b8a2e1fbaa9e864af62c873dae15420ea (diff)
net_sched: destroy proto tp when all filters are gone
Kernel automatically creates a tp for each (kind, protocol, priority) tuple, which has handle 0, when we add a new filter, but it still is left there after we remove our own, unless we don't specify the handle (literally means all the filters under the tuple). For example this one is left: # tc filter show dev eth0 filter parent 8001: protocol arp pref 49152 basic The user-space is hard to clean up these for kernel because filters like u32 are organized in a complex way. So kernel is responsible to remove it after all filters are gone. Each type of filter has its own way to store the filters, so each type has to provide its way to check if all filters are gone. Cc: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: Cong Wang <cwang@twopensource.com> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Acked-by: Jamal Hadi Salim<jhs@mojatatu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched/cls_route.c')
-rw-r--r--net/sched/cls_route.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
index bb8a60235d01..08a3b0a6f5ab 100644
--- a/net/sched/cls_route.c
+++ b/net/sched/cls_route.c
@@ -277,13 +277,20 @@ route4_delete_filter(struct rcu_head *head)
277 kfree(f); 277 kfree(f);
278} 278}
279 279
280static void route4_destroy(struct tcf_proto *tp) 280static bool route4_destroy(struct tcf_proto *tp, bool force)
281{ 281{
282 struct route4_head *head = rtnl_dereference(tp->root); 282 struct route4_head *head = rtnl_dereference(tp->root);
283 int h1, h2; 283 int h1, h2;
284 284
285 if (head == NULL) 285 if (head == NULL)
286 return; 286 return true;
287
288 if (!force) {
289 for (h1 = 0; h1 <= 256; h1++) {
290 if (rcu_access_pointer(head->table[h1]))
291 return false;
292 }
293 }
287 294
288 for (h1 = 0; h1 <= 256; h1++) { 295 for (h1 = 0; h1 <= 256; h1++) {
289 struct route4_bucket *b; 296 struct route4_bucket *b;
@@ -308,6 +315,7 @@ static void route4_destroy(struct tcf_proto *tp)
308 } 315 }
309 RCU_INIT_POINTER(tp->root, NULL); 316 RCU_INIT_POINTER(tp->root, NULL);
310 kfree_rcu(head, rcu); 317 kfree_rcu(head, rcu);
318 return true;
311} 319}
312 320
313static int route4_delete(struct tcf_proto *tp, unsigned long arg) 321static int route4_delete(struct tcf_proto *tp, unsigned long arg)