diff options
Diffstat (limited to 'net/sched/act_police.c')
-rw-r--r-- | net/sched/act_police.c | 246 |
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 | ||
54 | static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *cb, | 53 | static 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 | ||
101 | void tcf_police_destroy(struct tcf_police *p) | 99 | static 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 | ||
125 | static int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est, | 122 | static 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: | |||
247 | static int tcf_act_police_cleanup(struct tc_action *a, int bind) | 244 | static 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 | ||
256 | static int tcf_act_police(struct sk_buff *skb, struct tc_action *a, | 262 | static int tcf_act_police(struct sk_buff *skb, struct tc_action *a, |
@@ -372,229 +378,3 @@ police_cleanup_module(void) | |||
372 | 378 | ||
373 | module_init(police_init_module); | 379 | module_init(police_init_module); |
374 | module_exit(police_cleanup_module); | 380 | module_exit(police_cleanup_module); |
375 | |||
376 | #else /* CONFIG_NET_CLS_ACT */ | ||
377 | |||
378 | static 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 | |||
394 | static 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 | |||
407 | struct 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 | |||
489 | failure: | ||
490 | if (police->tcfp_R_tab) | ||
491 | qdisc_put_rtab(police->tcfp_R_tab); | ||
492 | kfree(police); | ||
493 | return NULL; | ||
494 | } | ||
495 | |||
496 | int 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 | } | ||
545 | EXPORT_SYMBOL(tcf_police); | ||
546 | |||
547 | int 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 | |||
572 | rtattr_failure: | ||
573 | nlmsg_trim(skb, b); | ||
574 | return -1; | ||
575 | } | ||
576 | |||
577 | int 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 | |||
596 | errout: | ||
597 | return -1; | ||
598 | } | ||
599 | |||
600 | #endif /* CONFIG_NET_CLS_ACT */ | ||