aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/act_police.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/act_police.c')
-rw-r--r--net/sched/act_police.c246
1 files changed, 13 insertions, 233 deletions
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index d20403890877..bf90e60f8411 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -50,7 +50,6 @@ struct tc_police_compat
50 50
51/* Each policer is serialized by its individual spinlock */ 51/* Each policer is serialized by its individual spinlock */
52 52
53#ifdef CONFIG_NET_CLS_ACT
54static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *cb, 53static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *cb,
55 int type, struct tc_action *a) 54 int type, struct tc_action *a)
56{ 55{
@@ -96,9 +95,8 @@ rtattr_failure:
96 nlmsg_trim(skb, r); 95 nlmsg_trim(skb, r);
97 goto done; 96 goto done;
98} 97}
99#endif
100 98
101void tcf_police_destroy(struct tcf_police *p) 99static void tcf_police_destroy(struct tcf_police *p)
102{ 100{
103 unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK); 101 unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK);
104 struct tcf_common **p1p; 102 struct tcf_common **p1p;
@@ -121,7 +119,6 @@ void tcf_police_destroy(struct tcf_police *p)
121 BUG_TRAP(0); 119 BUG_TRAP(0);
122} 120}
123 121
124#ifdef CONFIG_NET_CLS_ACT
125static int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est, 122static int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,
126 struct tc_action *a, int ovr, int bind) 123 struct tc_action *a, int ovr, int bind)
127{ 124{
@@ -247,10 +244,19 @@ failure:
247static int tcf_act_police_cleanup(struct tc_action *a, int bind) 244static int tcf_act_police_cleanup(struct tc_action *a, int bind)
248{ 245{
249 struct tcf_police *p = a->priv; 246 struct tcf_police *p = a->priv;
247 int ret = 0;
250 248
251 if (p != NULL) 249 if (p != NULL) {
252 return tcf_police_release(p, bind); 250 if (bind)
253 return 0; 251 p->tcf_bindcnt--;
252
253 p->tcf_refcnt--;
254 if (p->tcf_refcnt <= 0 && !p->tcf_bindcnt) {
255 tcf_police_destroy(p);
256 ret = 1;
257 }
258 }
259 return ret;
254} 260}
255 261
256static int tcf_act_police(struct sk_buff *skb, struct tc_action *a, 262static int tcf_act_police(struct sk_buff *skb, struct tc_action *a,
@@ -372,229 +378,3 @@ police_cleanup_module(void)
372 378
373module_init(police_init_module); 379module_init(police_init_module);
374module_exit(police_cleanup_module); 380module_exit(police_cleanup_module);
375
376#else /* CONFIG_NET_CLS_ACT */
377
378static struct tcf_common *tcf_police_lookup(u32 index)
379{
380 struct tcf_hashinfo *hinfo = &police_hash_info;
381 struct tcf_common *p;
382
383 read_lock(hinfo->lock);
384 for (p = hinfo->htab[tcf_hash(index, hinfo->hmask)]; p;
385 p = p->tcfc_next) {
386 if (p->tcfc_index == index)
387 break;
388 }
389 read_unlock(hinfo->lock);
390
391 return p;
392}
393
394static u32 tcf_police_new_index(void)
395{
396 u32 *idx_gen = &police_idx_gen;
397 u32 val = *idx_gen;
398
399 do {
400 if (++val == 0)
401 val = 1;
402 } while (tcf_police_lookup(val));
403
404 return (*idx_gen = val);
405}
406
407struct tcf_police *tcf_police_locate(struct rtattr *rta, struct rtattr *est)
408{
409 unsigned int h;
410 struct tcf_police *police;
411 struct rtattr *tb[TCA_POLICE_MAX];
412 struct tc_police *parm;
413 int size;
414
415 if (rtattr_parse_nested(tb, TCA_POLICE_MAX, rta) < 0)
416 return NULL;
417
418 if (tb[TCA_POLICE_TBF-1] == NULL)
419 return NULL;
420 size = RTA_PAYLOAD(tb[TCA_POLICE_TBF-1]);
421 if (size != sizeof(*parm) && size != sizeof(struct tc_police_compat))
422 return NULL;
423
424 parm = RTA_DATA(tb[TCA_POLICE_TBF-1]);
425
426 if (parm->index) {
427 struct tcf_common *pc;
428
429 pc = tcf_police_lookup(parm->index);
430 if (pc) {
431 police = to_police(pc);
432 police->tcf_refcnt++;
433 return police;
434 }
435 }
436 police = kzalloc(sizeof(*police), GFP_KERNEL);
437 if (unlikely(!police))
438 return NULL;
439
440 police->tcf_refcnt = 1;
441 spin_lock_init(&police->tcf_lock);
442 if (parm->rate.rate) {
443 police->tcfp_R_tab =
444 qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1]);
445 if (police->tcfp_R_tab == NULL)
446 goto failure;
447 if (parm->peakrate.rate) {
448 police->tcfp_P_tab =
449 qdisc_get_rtab(&parm->peakrate,
450 tb[TCA_POLICE_PEAKRATE-1]);
451 if (police->tcfp_P_tab == NULL)
452 goto failure;
453 }
454 }
455 if (tb[TCA_POLICE_RESULT-1]) {
456 if (RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32))
457 goto failure;
458 police->tcfp_result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]);
459 }
460 if (tb[TCA_POLICE_AVRATE-1]) {
461 if (RTA_PAYLOAD(tb[TCA_POLICE_AVRATE-1]) != sizeof(u32))
462 goto failure;
463 police->tcfp_ewma_rate =
464 *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]);
465 }
466 police->tcfp_toks = police->tcfp_burst = parm->burst;
467 police->tcfp_mtu = parm->mtu;
468 if (police->tcfp_mtu == 0) {
469 police->tcfp_mtu = ~0;
470 if (police->tcfp_R_tab)
471 police->tcfp_mtu = 255<<police->tcfp_R_tab->rate.cell_log;
472 }
473 if (police->tcfp_P_tab)
474 police->tcfp_ptoks = L2T_P(police, police->tcfp_mtu);
475 police->tcfp_t_c = psched_get_time();
476 police->tcf_index = parm->index ? parm->index :
477 tcf_police_new_index();
478 police->tcf_action = parm->action;
479 if (est)
480 gen_new_estimator(&police->tcf_bstats, &police->tcf_rate_est,
481 &police->tcf_lock, est);
482 h = tcf_hash(police->tcf_index, POL_TAB_MASK);
483 write_lock_bh(&police_lock);
484 police->tcf_next = tcf_police_ht[h];
485 tcf_police_ht[h] = &police->common;
486 write_unlock_bh(&police_lock);
487 return police;
488
489failure:
490 if (police->tcfp_R_tab)
491 qdisc_put_rtab(police->tcfp_R_tab);
492 kfree(police);
493 return NULL;
494}
495
496int tcf_police(struct sk_buff *skb, struct tcf_police *police)
497{
498 psched_time_t now;
499 long toks;
500 long ptoks = 0;
501
502 spin_lock(&police->tcf_lock);
503
504 police->tcf_bstats.bytes += skb->len;
505 police->tcf_bstats.packets++;
506
507 if (police->tcfp_ewma_rate &&
508 police->tcf_rate_est.bps >= police->tcfp_ewma_rate) {
509 police->tcf_qstats.overlimits++;
510 spin_unlock(&police->tcf_lock);
511 return police->tcf_action;
512 }
513 if (skb->len <= police->tcfp_mtu) {
514 if (police->tcfp_R_tab == NULL) {
515 spin_unlock(&police->tcf_lock);
516 return police->tcfp_result;
517 }
518
519 now = psched_get_time();
520 toks = psched_tdiff_bounded(now, police->tcfp_t_c,
521 police->tcfp_burst);
522 if (police->tcfp_P_tab) {
523 ptoks = toks + police->tcfp_ptoks;
524 if (ptoks > (long)L2T_P(police, police->tcfp_mtu))
525 ptoks = (long)L2T_P(police, police->tcfp_mtu);
526 ptoks -= L2T_P(police, skb->len);
527 }
528 toks += police->tcfp_toks;
529 if (toks > (long)police->tcfp_burst)
530 toks = police->tcfp_burst;
531 toks -= L2T(police, skb->len);
532 if ((toks|ptoks) >= 0) {
533 police->tcfp_t_c = now;
534 police->tcfp_toks = toks;
535 police->tcfp_ptoks = ptoks;
536 spin_unlock(&police->tcf_lock);
537 return police->tcfp_result;
538 }
539 }
540
541 police->tcf_qstats.overlimits++;
542 spin_unlock(&police->tcf_lock);
543 return police->tcf_action;
544}
545EXPORT_SYMBOL(tcf_police);
546
547int tcf_police_dump(struct sk_buff *skb, struct tcf_police *police)
548{
549 unsigned char *b = skb_tail_pointer(skb);
550 struct tc_police opt;
551
552 opt.index = police->tcf_index;
553 opt.action = police->tcf_action;
554 opt.mtu = police->tcfp_mtu;
555 opt.burst = police->tcfp_burst;
556 if (police->tcfp_R_tab)
557 opt.rate = police->tcfp_R_tab->rate;
558 else
559 memset(&opt.rate, 0, sizeof(opt.rate));
560 if (police->tcfp_P_tab)
561 opt.peakrate = police->tcfp_P_tab->rate;
562 else
563 memset(&opt.peakrate, 0, sizeof(opt.peakrate));
564 RTA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt);
565 if (police->tcfp_result)
566 RTA_PUT(skb, TCA_POLICE_RESULT, sizeof(int),
567 &police->tcfp_result);
568 if (police->tcfp_ewma_rate)
569 RTA_PUT(skb, TCA_POLICE_AVRATE, 4, &police->tcfp_ewma_rate);
570 return skb->len;
571
572rtattr_failure:
573 nlmsg_trim(skb, b);
574 return -1;
575}
576
577int tcf_police_dump_stats(struct sk_buff *skb, struct tcf_police *police)
578{
579 struct gnet_dump d;
580
581 if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS,
582 TCA_XSTATS, &police->tcf_lock,
583 &d) < 0)
584 goto errout;
585
586 if (gnet_stats_copy_basic(&d, &police->tcf_bstats) < 0 ||
587 gnet_stats_copy_rate_est(&d, &police->tcf_rate_est) < 0 ||
588 gnet_stats_copy_queue(&d, &police->tcf_qstats) < 0)
589 goto errout;
590
591 if (gnet_stats_finish_copy(&d) < 0)
592 goto errout;
593
594 return 0;
595
596errout:
597 return -1;
598}
599
600#endif /* CONFIG_NET_CLS_ACT */