aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/cls_api.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_api.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_api.c')
-rw-r--r--net/sched/cls_api.c14
1 files changed, 10 insertions, 4 deletions
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index baef987fe2c0..8b0470e418dc 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -286,7 +286,7 @@ replay:
286 RCU_INIT_POINTER(*back, next); 286 RCU_INIT_POINTER(*back, next);
287 287
288 tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER); 288 tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER);
289 tcf_destroy(tp); 289 tcf_destroy(tp, true);
290 err = 0; 290 err = 0;
291 goto errout; 291 goto errout;
292 } 292 }
@@ -301,14 +301,20 @@ replay:
301 err = -EEXIST; 301 err = -EEXIST;
302 if (n->nlmsg_flags & NLM_F_EXCL) { 302 if (n->nlmsg_flags & NLM_F_EXCL) {
303 if (tp_created) 303 if (tp_created)
304 tcf_destroy(tp); 304 tcf_destroy(tp, true);
305 goto errout; 305 goto errout;
306 } 306 }
307 break; 307 break;
308 case RTM_DELTFILTER: 308 case RTM_DELTFILTER:
309 err = tp->ops->delete(tp, fh); 309 err = tp->ops->delete(tp, fh);
310 if (err == 0) 310 if (err == 0) {
311 tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER); 311 tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER);
312 if (tcf_destroy(tp, false)) {
313 struct tcf_proto *next = rtnl_dereference(tp->next);
314
315 RCU_INIT_POINTER(*back, next);
316 }
317 }
312 goto errout; 318 goto errout;
313 case RTM_GETTFILTER: 319 case RTM_GETTFILTER:
314 err = tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER); 320 err = tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER);
@@ -329,7 +335,7 @@ replay:
329 tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER); 335 tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER);
330 } else { 336 } else {
331 if (tp_created) 337 if (tp_created)
332 tcf_destroy(tp); 338 tcf_destroy(tp, true);
333 } 339 }
334 340
335errout: 341errout: