X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fsched%2Fpolice.c;h=c03545faf5233c23e2b9c0dabbd4f4c17493c9e2;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=12bd44006537668f955fc3f30f50bece458a211c;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/net/sched/police.c b/net/sched/police.c index 12bd44006..c03545faf 100644 --- a/net/sched/police.c +++ b/net/sched/police.c @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include @@ -31,7 +31,7 @@ #include #include #include -#include +#include #define L2T(p,L) ((p)->R_tab->data[(L)>>(p)->R_tab->rate.cell_log]) #define L2T_P(p,L) ((p)->P_tab->data[(L)>>(p)->P_tab->rate.cell_log]) @@ -43,7 +43,7 @@ static u32 idx_gen; static struct tcf_police *tcf_police_ht[MY_TAB_SIZE]; /* Policer hash table lock */ -static rwlock_t police_lock = RW_LOCK_UNLOCKED; +static DEFINE_RWLOCK(police_lock); /* Each policer is serialized by its individual spinlock */ @@ -66,11 +66,12 @@ static __inline__ struct tcf_police * tcf_police_lookup(u32 index) } #ifdef CONFIG_NET_CLS_ACT -static __inline__ int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb, int type, struct tc_action *a) +static int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb, + int type, struct tc_action *a) { struct tcf_police *p; - int err =0, index = -1,i= 0, s_i = 0, n_i = 0; - struct rtattr *r ; + int err = 0, index = -1, i = 0, s_i = 0, n_i = 0; + struct rtattr *r; read_lock(&police_lock); @@ -91,7 +92,7 @@ static __inline__ int tcf_generic_walker(struct sk_buff *skb, struct netlink_cal err = tcf_action_dump_1(skb, a, 0, 1); else err = tcf_action_dump_1(skb, a, 0, 0); - if (0 > err) { + if (err < 0) { index--; skb_trim(skb, (u8*)r - skb->data); goto done; @@ -123,11 +124,9 @@ tcf_hash_search(struct tc_action *a, u32 index) return 0; } } - - #endif -static __inline__ u32 tcf_police_new_index(void) +static inline u32 tcf_police_new_index(void) { do { if (++idx_gen == 0) @@ -137,7 +136,6 @@ static __inline__ u32 tcf_police_new_index(void) return idx_gen; } - void tcf_police_destroy(struct tcf_police *p) { unsigned h = tcf_police_hash(p->index); @@ -149,7 +147,7 @@ void tcf_police_destroy(struct tcf_police *p) *p1p = p->next; write_unlock_bh(&police_lock); #ifdef CONFIG_NET_ESTIMATOR - qdisc_kill_estimator(&p->stats); + gen_kill_estimator(&p->bstats, &p->rate_est); #endif if (p->R_tab) qdisc_put_rtab(p->R_tab); @@ -163,48 +161,48 @@ void tcf_police_destroy(struct tcf_police *p) } #ifdef CONFIG_NET_CLS_ACT -int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,struct tc_action *a, int ovr, int bind) +static int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est, + struct tc_action *a, int ovr, int bind) { unsigned h; - int ret = 0; + int ret = 0, err; struct rtattr *tb[TCA_POLICE_MAX]; struct tc_police *parm; struct tcf_police *p; + struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL; - if (NULL == a) { - if (net_ratelimit()) - printk("BUG: tcf_police_locate called with NULL params\n"); - return -1; - } - - if (rtattr_parse(tb, TCA_POLICE_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)) < 0) - return -1; - - if (tb[TCA_POLICE_TBF-1] == NULL) - return -1; + if (rta == NULL || rtattr_parse_nested(tb, TCA_POLICE_MAX, rta) < 0) + return -EINVAL; + if (tb[TCA_POLICE_TBF-1] == NULL || + RTA_PAYLOAD(tb[TCA_POLICE_TBF-1]) != sizeof(*parm)) + return -EINVAL; parm = RTA_DATA(tb[TCA_POLICE_TBF-1]); + if (tb[TCA_POLICE_RESULT-1] != NULL && + RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32)) + return -EINVAL; + if (tb[TCA_POLICE_RESULT-1] != NULL && + RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32)) + return -EINVAL; + if (parm->index && (p = tcf_police_lookup(parm->index)) != NULL) { - a->priv = (void *)p; - spin_lock(&p->lock); + a->priv = p; if (bind) { p->bindcnt += 1; p->refcnt += 1; } - if (ovr) { + if (ovr) goto override; - } - spin_unlock(&p->lock); - return ret; + return ret; } p = kmalloc(sizeof(*p), GFP_KERNEL); if (p == NULL) - return -1; - + return -ENOMEM; memset(p, 0, sizeof(*p)); - ret = 1; + + ret = ACT_P_CREATED; p->refcnt = 1; spin_lock_init(&p->lock); p->stats_lock = &p->lock; @@ -212,20 +210,32 @@ int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,struct tc_actio p->bindcnt = 1; override: if (parm->rate.rate) { - if ((p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1])) == NULL) { - goto failure; - } - if (parm->peakrate.rate && - (p->P_tab = qdisc_get_rtab(&parm->peakrate, tb[TCA_POLICE_PEAKRATE-1])) == NULL) { + err = -ENOMEM; + R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1]); + if (R_tab == NULL) goto failure; + if (parm->peakrate.rate) { + P_tab = qdisc_get_rtab(&parm->peakrate, + tb[TCA_POLICE_PEAKRATE-1]); + if (p->P_tab == NULL) { + qdisc_put_rtab(R_tab); + goto failure; + } } } + /* No failure allowed after this point */ + spin_lock_bh(&p->lock); + if (R_tab != NULL) { + qdisc_put_rtab(p->R_tab); + p->R_tab = R_tab; + } + if (P_tab != NULL) { + qdisc_put_rtab(p->P_tab); + p->P_tab = P_tab; + } + if (tb[TCA_POLICE_RESULT-1]) - p->result = *(int*)RTA_DATA(tb[TCA_POLICE_RESULT-1]); -#ifdef CONFIG_NET_ESTIMATOR - if (tb[TCA_POLICE_AVRATE-1]) - p->ewma_rate = *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]); -#endif + p->result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]); p->toks = p->burst = parm->burst; p->mtu = parm->mtu; if (p->mtu == 0) { @@ -237,77 +247,59 @@ override: p->ptoks = L2T_P(p, p->mtu); p->action = parm->action; - if (ovr) { - spin_unlock(&p->lock); - return ret; - } - PSCHED_GET_TIME(p->t_c); - p->index = parm->index ? : tcf_police_new_index(); #ifdef CONFIG_NET_ESTIMATOR + if (tb[TCA_POLICE_AVRATE-1]) + p->ewma_rate = *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]); if (est) - qdisc_new_estimator(&p->stats, p->stats_lock, est); + gen_replace_estimator(&p->bstats, &p->rate_est, p->stats_lock, est); #endif + + spin_unlock_bh(&p->lock); + if (ret != ACT_P_CREATED) + return ret; + + PSCHED_GET_TIME(p->t_c); + p->index = parm->index ? : tcf_police_new_index(); h = tcf_police_hash(p->index); write_lock_bh(&police_lock); p->next = tcf_police_ht[h]; tcf_police_ht[h] = p; write_unlock_bh(&police_lock); - a->priv = (void *)p; - return ret; + a->priv = p; + return ret; failure: - if (p->R_tab) - qdisc_put_rtab(p->R_tab); - if (ovr) - spin_unlock(&p->lock); - kfree(p); - return -1; + if (ret == ACT_P_CREATED) + kfree(p); + return err; } -int tcf_act_police_cleanup(struct tc_action *a, int bind) +static int tcf_act_police_cleanup(struct tc_action *a, int bind) { - struct tcf_police *p; - p = PRIV(a); - if (NULL != p) - return tcf_police_release(p, bind); + struct tcf_police *p = PRIV(a); + if (p != NULL) + return tcf_police_release(p, bind); return 0; } -int tcf_act_police_stats(struct sk_buff *skb, struct tc_action *a) -{ - struct tcf_police *p; - p = PRIV(a); - if (NULL != p) - return qdisc_copy_stats(skb, &p->stats, p->stats_lock); - - return 1; -} - -int tcf_act_police(struct sk_buff **pskb, struct tc_action *a) +static int tcf_act_police(struct sk_buff **pskb, struct tc_action *a) { psched_time_t now; struct sk_buff *skb = *pskb; - struct tcf_police *p; + struct tcf_police *p = PRIV(a); long toks; long ptoks = 0; - p = PRIV(a); - - if (NULL == p) { - printk("BUG: tcf_police called with NULL params\n"); - return -1; - } - spin_lock(&p->lock); - p->stats.bytes += skb->len; - p->stats.packets++; + p->bstats.bytes += skb->len; + p->bstats.packets++; #ifdef CONFIG_NET_ESTIMATOR - if (p->ewma_rate && p->stats.bps >= p->ewma_rate) { - p->stats.overlimits++; + if (p->ewma_rate && p->rate_est.bps >= p->ewma_rate) { + p->qstats.overlimits++; spin_unlock(&p->lock); return p->action; } @@ -343,22 +335,17 @@ int tcf_act_police(struct sk_buff **pskb, struct tc_action *a) } } - p->stats.overlimits++; + p->qstats.overlimits++; spin_unlock(&p->lock); return p->action; } -int tcf_act_police_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) +static int +tcf_act_police_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) { unsigned char *b = skb->tail; struct tc_police opt; - struct tcf_police *p; - - p = PRIV(a); - if (NULL == p) { - printk("BUG: tcf_police_dump called with NULL params\n"); - goto rtattr_failure; - } + struct tcf_police *p = PRIV(a); opt.index = p->index; opt.action = p->action; @@ -392,15 +379,12 @@ MODULE_AUTHOR("Alexey Kuznetsov"); MODULE_DESCRIPTION("Policing actions"); MODULE_LICENSE("GPL"); - static struct tc_action_ops act_police_ops = { - .next = NULL, .kind = "police", - .type = TCA_ID_POLICE, - .capab = TCA_CAP_NONE, + .type = TCA_ID_POLICE, + .capab = TCA_CAP_NONE, .owner = THIS_MODULE, .act = tcf_act_police, - .get_stats = tcf_act_police_stats, .dump = tcf_act_police_dump, .cleanup = tcf_act_police_cleanup, .lookup = tcf_hash_search, @@ -432,10 +416,11 @@ struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est) struct rtattr *tb[TCA_POLICE_MAX]; struct tc_police *parm; - if (rtattr_parse(tb, TCA_POLICE_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)) < 0) + if (rtattr_parse_nested(tb, TCA_POLICE_MAX, rta) < 0) return NULL; - if (tb[TCA_POLICE_TBF-1] == NULL) + if (tb[TCA_POLICE_TBF-1] == NULL || + RTA_PAYLOAD(tb[TCA_POLICE_TBF-1]) != sizeof(*parm)) return NULL; parm = RTA_DATA(tb[TCA_POLICE_TBF-1]); @@ -454,17 +439,27 @@ struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est) spin_lock_init(&p->lock); p->stats_lock = &p->lock; if (parm->rate.rate) { - if ((p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1])) == NULL) + p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1]); + if (p->R_tab == NULL) goto failure; - if (parm->peakrate.rate && - (p->P_tab = qdisc_get_rtab(&parm->peakrate, tb[TCA_POLICE_PEAKRATE-1])) == NULL) + if (parm->peakrate.rate) { + p->P_tab = qdisc_get_rtab(&parm->peakrate, + tb[TCA_POLICE_PEAKRATE-1]); + if (p->P_tab == NULL) + goto failure; + } + } + if (tb[TCA_POLICE_RESULT-1]) { + if (RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32)) goto failure; + p->result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]); } - if (tb[TCA_POLICE_RESULT-1]) - p->result = *(int*)RTA_DATA(tb[TCA_POLICE_RESULT-1]); #ifdef CONFIG_NET_ESTIMATOR - if (tb[TCA_POLICE_AVRATE-1]) + if (tb[TCA_POLICE_AVRATE-1]) { + if (RTA_PAYLOAD(tb[TCA_POLICE_AVRATE-1]) != sizeof(u32)) + goto failure; p->ewma_rate = *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]); + } #endif p->toks = p->burst = parm->burst; p->mtu = parm->mtu; @@ -480,7 +475,7 @@ struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est) p->action = parm->action; #ifdef CONFIG_NET_ESTIMATOR if (est) - qdisc_new_estimator(&p->stats, p->stats_lock, est); + gen_new_estimator(&p->bstats, &p->rate_est, p->stats_lock, est); #endif h = tcf_police_hash(p->index); write_lock_bh(&police_lock); @@ -504,12 +499,12 @@ int tcf_police(struct sk_buff *skb, struct tcf_police *p) spin_lock(&p->lock); - p->stats.bytes += skb->len; - p->stats.packets++; + p->bstats.bytes += skb->len; + p->bstats.packets++; #ifdef CONFIG_NET_ESTIMATOR - if (p->ewma_rate && p->stats.bps >= p->ewma_rate) { - p->stats.overlimits++; + if (p->ewma_rate && p->rate_est.bps >= p->ewma_rate) { + p->qstats.overlimits++; spin_unlock(&p->lock); return p->action; } @@ -545,7 +540,7 @@ int tcf_police(struct sk_buff *skb, struct tcf_police *p) } } - p->stats.overlimits++; + p->qstats.overlimits++; spin_unlock(&p->lock); return p->action; } @@ -581,9 +576,35 @@ rtattr_failure: return -1; } +int tcf_police_dump_stats(struct sk_buff *skb, struct tcf_police *p) +{ + struct gnet_dump d; + + if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, + TCA_XSTATS, p->stats_lock, &d) < 0) + goto errout; + + if (gnet_stats_copy_basic(&d, &p->bstats) < 0 || +#ifdef CONFIG_NET_ESTIMATOR + gnet_stats_copy_rate_est(&d, &p->rate_est) < 0 || +#endif + gnet_stats_copy_queue(&d, &p->qstats) < 0) + goto errout; + + if (gnet_stats_finish_copy(&d) < 0) + goto errout; + + return 0; + +errout: + return -1; +} + + EXPORT_SYMBOL(tcf_police); EXPORT_SYMBOL(tcf_police_destroy); EXPORT_SYMBOL(tcf_police_dump); +EXPORT_SYMBOL(tcf_police_dump_stats); EXPORT_SYMBOL(tcf_police_hash); EXPORT_SYMBOL(tcf_police_ht); EXPORT_SYMBOL(tcf_police_locate);