aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/cls_tcindex.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/cls_tcindex.c')
-rw-r--r--net/sched/cls_tcindex.c80
1 files changed, 48 insertions, 32 deletions
diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c
index 9ccc93f257db..38bb882bb958 100644
--- a/net/sched/cls_tcindex.c
+++ b/net/sched/cls_tcindex.c
@@ -48,7 +48,7 @@ struct tcindex_data {
48 u32 hash; /* hash table size; 0 if undefined */ 48 u32 hash; /* hash table size; 0 if undefined */
49 u32 alloc_hash; /* allocated size */ 49 u32 alloc_hash; /* allocated size */
50 u32 fall_through; /* 0: only classify if explicit match */ 50 u32 fall_through; /* 0: only classify if explicit match */
51 struct rcu_head rcu; 51 struct rcu_work rwork;
52}; 52};
53 53
54static inline int tcindex_filter_is_set(struct tcindex_filter_result *r) 54static inline int tcindex_filter_is_set(struct tcindex_filter_result *r)
@@ -221,17 +221,11 @@ found:
221 return 0; 221 return 0;
222} 222}
223 223
224static int tcindex_destroy_element(struct tcf_proto *tp, 224static void tcindex_destroy_work(struct work_struct *work)
225 void *arg, struct tcf_walker *walker)
226{
227 bool last;
228
229 return tcindex_delete(tp, arg, &last, NULL);
230}
231
232static void __tcindex_destroy(struct rcu_head *head)
233{ 225{
234 struct tcindex_data *p = container_of(head, struct tcindex_data, rcu); 226 struct tcindex_data *p = container_of(to_rcu_work(work),
227 struct tcindex_data,
228 rwork);
235 229
236 kfree(p->perfect); 230 kfree(p->perfect);
237 kfree(p->h); 231 kfree(p->h);
@@ -258,9 +252,11 @@ static int tcindex_filter_result_init(struct tcindex_filter_result *r)
258 return tcf_exts_init(&r->exts, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); 252 return tcf_exts_init(&r->exts, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
259} 253}
260 254
261static void __tcindex_partial_destroy(struct rcu_head *head) 255static void tcindex_partial_destroy_work(struct work_struct *work)
262{ 256{
263 struct tcindex_data *p = container_of(head, struct tcindex_data, rcu); 257 struct tcindex_data *p = container_of(to_rcu_work(work),
258 struct tcindex_data,
259 rwork);
264 260
265 kfree(p->perfect); 261 kfree(p->perfect);
266 kfree(p); 262 kfree(p);
@@ -275,7 +271,7 @@ static void tcindex_free_perfect_hash(struct tcindex_data *cp)
275 kfree(cp->perfect); 271 kfree(cp->perfect);
276} 272}
277 273
278static int tcindex_alloc_perfect_hash(struct tcindex_data *cp) 274static int tcindex_alloc_perfect_hash(struct net *net, struct tcindex_data *cp)
279{ 275{
280 int i, err = 0; 276 int i, err = 0;
281 277
@@ -289,6 +285,9 @@ static int tcindex_alloc_perfect_hash(struct tcindex_data *cp)
289 TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); 285 TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
290 if (err < 0) 286 if (err < 0)
291 goto errout; 287 goto errout;
288#ifdef CONFIG_NET_CLS_ACT
289 cp->perfect[i].exts.net = net;
290#endif
292 } 291 }
293 292
294 return 0; 293 return 0;
@@ -305,9 +304,9 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
305 struct nlattr *est, bool ovr, struct netlink_ext_ack *extack) 304 struct nlattr *est, bool ovr, struct netlink_ext_ack *extack)
306{ 305{
307 struct tcindex_filter_result new_filter_result, *old_r = r; 306 struct tcindex_filter_result new_filter_result, *old_r = r;
308 struct tcindex_filter_result cr;
309 struct tcindex_data *cp = NULL, *oldp; 307 struct tcindex_data *cp = NULL, *oldp;
310 struct tcindex_filter *f = NULL; /* make gcc behave */ 308 struct tcindex_filter *f = NULL; /* make gcc behave */
309 struct tcf_result cr = {};
311 int err, balloc = 0; 310 int err, balloc = 0;
312 struct tcf_exts e; 311 struct tcf_exts e;
313 312
@@ -337,7 +336,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
337 if (p->perfect) { 336 if (p->perfect) {
338 int i; 337 int i;
339 338
340 if (tcindex_alloc_perfect_hash(cp) < 0) 339 if (tcindex_alloc_perfect_hash(net, cp) < 0)
341 goto errout; 340 goto errout;
342 for (i = 0; i < cp->hash; i++) 341 for (i = 0; i < cp->hash; i++)
343 cp->perfect[i].res = p->perfect[i].res; 342 cp->perfect[i].res = p->perfect[i].res;
@@ -348,11 +347,8 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
348 err = tcindex_filter_result_init(&new_filter_result); 347 err = tcindex_filter_result_init(&new_filter_result);
349 if (err < 0) 348 if (err < 0)
350 goto errout1; 349 goto errout1;
351 err = tcindex_filter_result_init(&cr);
352 if (err < 0)
353 goto errout1;
354 if (old_r) 350 if (old_r)
355 cr.res = r->res; 351 cr = r->res;
356 352
357 if (tb[TCA_TCINDEX_HASH]) 353 if (tb[TCA_TCINDEX_HASH])
358 cp->hash = nla_get_u32(tb[TCA_TCINDEX_HASH]); 354 cp->hash = nla_get_u32(tb[TCA_TCINDEX_HASH]);
@@ -406,7 +402,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
406 err = -ENOMEM; 402 err = -ENOMEM;
407 if (!cp->perfect && !cp->h) { 403 if (!cp->perfect && !cp->h) {
408 if (valid_perfect_hash(cp)) { 404 if (valid_perfect_hash(cp)) {
409 if (tcindex_alloc_perfect_hash(cp) < 0) 405 if (tcindex_alloc_perfect_hash(net, cp) < 0)
410 goto errout_alloc; 406 goto errout_alloc;
411 balloc = 1; 407 balloc = 1;
412 } else { 408 } else {
@@ -443,8 +439,8 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
443 } 439 }
444 440
445 if (tb[TCA_TCINDEX_CLASSID]) { 441 if (tb[TCA_TCINDEX_CLASSID]) {
446 cr.res.classid = nla_get_u32(tb[TCA_TCINDEX_CLASSID]); 442 cr.classid = nla_get_u32(tb[TCA_TCINDEX_CLASSID]);
447 tcf_bind_filter(tp, &cr.res, base); 443 tcf_bind_filter(tp, &cr, base);
448 } 444 }
449 445
450 if (old_r && old_r != r) { 446 if (old_r && old_r != r) {
@@ -456,7 +452,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
456 } 452 }
457 453
458 oldp = p; 454 oldp = p;
459 r->res = cr.res; 455 r->res = cr;
460 tcf_exts_change(&r->exts, &e); 456 tcf_exts_change(&r->exts, &e);
461 457
462 rcu_assign_pointer(tp->root, cp); 458 rcu_assign_pointer(tp->root, cp);
@@ -475,10 +471,12 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
475 ; /* nothing */ 471 ; /* nothing */
476 472
477 rcu_assign_pointer(*fp, f); 473 rcu_assign_pointer(*fp, f);
474 } else {
475 tcf_exts_destroy(&new_filter_result.exts);
478 } 476 }
479 477
480 if (oldp) 478 if (oldp)
481 call_rcu(&oldp->rcu, __tcindex_partial_destroy); 479 tcf_queue_work(&oldp->rwork, tcindex_partial_destroy_work);
482 return 0; 480 return 0;
483 481
484errout_alloc: 482errout_alloc:
@@ -487,7 +485,6 @@ errout_alloc:
487 else if (balloc == 2) 485 else if (balloc == 2)
488 kfree(cp->h); 486 kfree(cp->h);
489errout1: 487errout1:
490 tcf_exts_destroy(&cr.exts);
491 tcf_exts_destroy(&new_filter_result.exts); 488 tcf_exts_destroy(&new_filter_result.exts);
492errout: 489errout:
493 kfree(cp); 490 kfree(cp);
@@ -562,15 +559,34 @@ static void tcindex_destroy(struct tcf_proto *tp,
562 struct netlink_ext_ack *extack) 559 struct netlink_ext_ack *extack)
563{ 560{
564 struct tcindex_data *p = rtnl_dereference(tp->root); 561 struct tcindex_data *p = rtnl_dereference(tp->root);
565 struct tcf_walker walker; 562 int i;
566 563
567 pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p); 564 pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p);
568 walker.count = 0;
569 walker.skip = 0;
570 walker.fn = tcindex_destroy_element;
571 tcindex_walk(tp, &walker);
572 565
573 call_rcu(&p->rcu, __tcindex_destroy); 566 if (p->perfect) {
567 for (i = 0; i < p->hash; i++) {
568 struct tcindex_filter_result *r = p->perfect + i;
569
570 tcf_unbind_filter(tp, &r->res);
571 if (tcf_exts_get_net(&r->exts))
572 tcf_queue_work(&r->rwork,
573 tcindex_destroy_rexts_work);
574 else
575 __tcindex_destroy_rexts(r);
576 }
577 }
578
579 for (i = 0; p->h && i < p->hash; i++) {
580 struct tcindex_filter *f, *next;
581 bool last;
582
583 for (f = rtnl_dereference(p->h[i]); f; f = next) {
584 next = rtnl_dereference(f->next);
585 tcindex_delete(tp, &f->result, &last, NULL);
586 }
587 }
588
589 tcf_queue_work(&p->rwork, tcindex_destroy_work);
574} 590}
575 591
576 592