X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fsched%2Fcls_u32.c;h=30d26d4fe34a90b43fa8bd1fcb4635d7d8d4723b;hb=9bf4aaab3e101692164d49b7ca357651eb691cb6;hp=938d88744b636b34f4afc5f7cae7cda154a5caf9;hpb=db216c3d5e4c040e557a50f8f5d35d5c415e8c1c;p=linux-2.6.git diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 938d88744..30d26d4fe 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -23,6 +23,10 @@ * It is especially useful for link sharing combined with QoS; * pure RSVP doesn't need such a general approach and can use * much simpler (and faster) schemes, sort of cls_rsvp.c. + * + * JHS: We should remove the CONFIG_NET_CLS_IND from here + * eventually when the meta match extension is made available + * */ #include @@ -58,11 +62,22 @@ struct tc_u_knode struct tc_u_knode *next; u32 handle; struct tc_u_hnode *ht_up; +#ifdef CONFIG_NET_CLS_ACT + struct tc_action *action; +#else #ifdef CONFIG_NET_CLS_POLICE struct tcf_police *police; #endif +#endif +#ifdef CONFIG_NET_CLS_IND + char indev[IFNAMSIZ]; +#endif + u8 fshift; struct tcf_result res; struct tc_u_hnode *ht_down; +#ifdef CONFIG_CLS_U32_PERF + struct tc_u32_pcnt *pf; +#endif struct tc_u32_sel sel; }; @@ -88,12 +103,10 @@ struct tc_u_common static struct tc_u_common *u32_list; -static __inline__ unsigned u32_hash_fold(u32 key, struct tc_u32_sel *sel) +static __inline__ unsigned u32_hash_fold(u32 key, struct tc_u32_sel *sel, u8 fshift) { - unsigned h = key & sel->hmask; + unsigned h = (key & sel->hmask)>>fshift; - h ^= h>>16; - h ^= h>>8; return h; } @@ -110,6 +123,9 @@ static int u32_classify(struct sk_buff *skb, struct tcf_proto *tp, struct tcf_re int sdepth = 0; int off2 = 0; int sel = 0; +#ifdef CONFIG_CLS_U32_PERF + int j; +#endif int i; next_ht: @@ -119,22 +135,63 @@ next_knode: if (n) { struct tc_u32_key *key = n->sel.keys; +#ifdef CONFIG_CLS_U32_PERF + n->pf->rcnt +=1; + j = 0; +#endif for (i = n->sel.nkeys; i>0; i--, key++) { + if ((*(u32*)(ptr+key->off+(off2&key->offmask))^key->val)&key->mask) { n = n->next; goto next_knode; } +#ifdef CONFIG_CLS_U32_PERF + n->pf->kcnts[j] +=1; + j++; +#endif } if (n->ht_down == NULL) { check_terminal: if (n->sel.flags&TC_U32_TERMINAL) { + *res = n->res; +#ifdef CONFIG_NET_CLS_IND + /* yes, i know it sucks but the feature is + ** optional dammit! - JHS */ + if (0 != n->indev[0]) { + if (NULL == skb->input_dev) { + n = n->next; + goto next_knode; + } else { + if (0 != strcmp(n->indev, skb->input_dev->name)) { + n = n->next; + goto next_knode; + } + } + } +#endif +#ifdef CONFIG_CLS_U32_PERF + n->pf->rhit +=1; +#endif +#ifdef CONFIG_NET_CLS_ACT + if (n->action) { + int pol_res = tcf_action_exec(skb, n->action); + if (skb->tc_classid > 0) { + res->classid = skb->tc_classid; + skb->tc_classid = 0; + } + + if (pol_res >= 0) + return pol_res; + } else +#else #ifdef CONFIG_NET_CLS_POLICE if (n->police) { int pol_res = tcf_police(skb, n->police); if (pol_res >= 0) return pol_res; } else +#endif #endif return 0; } @@ -152,7 +209,7 @@ check_terminal: ht = n->ht_down; sel = 0; if (ht->divisor) - sel = ht->divisor&u32_hash_fold(*(u32*)(ptr+n->sel.hoff), &n->sel); + sel = ht->divisor&u32_hash_fold(*(u32*)(ptr+n->sel.hoff), &n->sel,n->fshift); if (!(n->sel.flags&(TC_U32_VAROFFSET|TC_U32_OFFSET|TC_U32_EAT))) goto next_ht; @@ -298,11 +355,21 @@ static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n) if ((cl = __cls_set_class(&n->res.class, 0)) != 0) tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); +#ifdef CONFIG_NET_CLS_ACT + if (n->action) { + tcf_action_destroy(n->action, TCA_ACT_UNBIND); + } +#else #ifdef CONFIG_NET_CLS_POLICE - tcf_police_release(n->police); + tcf_police_release(n->police, TCA_ACT_UNBIND); +#endif #endif if (n->ht_down) n->ht_down->refcnt--; +#ifdef CONFIG_CLS_U32_PERF + if (n && (NULL != n->pf)) + kfree(n->pf); +#endif kfree(n); return 0; } @@ -438,6 +505,10 @@ static int u32_set_parms(struct Qdisc *q, unsigned long base, struct tc_u_knode *n, struct rtattr **tb, struct rtattr *est) { +#ifdef CONFIG_NET_CLS_ACT + struct tc_action *act = NULL; + int ret; +#endif if (tb[TCA_U32_LINK-1]) { u32 handle = *(u32*)RTA_DATA(tb[TCA_U32_LINK-1]); struct tc_u_hnode *ht_down = NULL; @@ -470,17 +541,74 @@ static int u32_set_parms(struct Qdisc *q, unsigned long base, if (cl) q->ops->cl_ops->unbind_tcf(q, cl); } +#ifdef CONFIG_NET_CLS_ACT + /*backward compatibility */ + if (tb[TCA_U32_POLICE-1]) + { + act = kmalloc(sizeof(*act),GFP_KERNEL); + if (NULL == act) + return -ENOMEM; + + memset(act,0,sizeof(*act)); + ret = tcf_action_init_1(tb[TCA_U32_POLICE-1], est,act,"police", TCA_ACT_NOREPLACE, TCA_ACT_BIND); + if (0 > ret){ + tcf_action_destroy(act, TCA_ACT_UNBIND); + return ret; + } + act->type = TCA_OLD_COMPAT; + + sch_tree_lock(q); + act = xchg(&n->action, act); + sch_tree_unlock(q); + + tcf_action_destroy(act, TCA_ACT_UNBIND); + + } + + if(tb[TCA_U32_ACT-1]) { + act = kmalloc(sizeof(*act),GFP_KERNEL); + if (NULL == act) + return -ENOMEM; + memset(act,0,sizeof(*act)); + ret = tcf_action_init(tb[TCA_U32_ACT-1], est,act,NULL,TCA_ACT_NOREPLACE, TCA_ACT_BIND); + if (0 > ret) { + tcf_action_destroy(act, TCA_ACT_UNBIND); + return ret; + } + + sch_tree_lock(q); + act = xchg(&n->action, act); + sch_tree_unlock(q); + + tcf_action_destroy(act, TCA_ACT_UNBIND); + } + + +#else #ifdef CONFIG_NET_CLS_POLICE if (tb[TCA_U32_POLICE-1]) { struct tcf_police *police = tcf_police_locate(tb[TCA_U32_POLICE-1], est); - sch_tree_lock(q); police = xchg(&n->police, police); sch_tree_unlock(q); - - tcf_police_release(police); + tcf_police_release(police, TCA_ACT_UNBIND); + } +#endif +#endif +#ifdef CONFIG_NET_CLS_IND + n->indev[0] = 0; + if(tb[TCA_U32_INDEV-1]) { + struct rtattr *input_dev = tb[TCA_U32_INDEV-1]; + if (RTA_PAYLOAD(input_dev) >= IFNAMSIZ) { + printk("cls_u32: bad indev name %s\n",(char*)RTA_DATA(input_dev)); + /* should we clear state first? */ + return -EINVAL; + } + sprintf(n->indev, "%s", (char*)RTA_DATA(input_dev)); + printk("got IND %s\n",n->indev); } #endif + return 0; } @@ -566,13 +694,35 @@ static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle, return -EINVAL; s = RTA_DATA(tb[TCA_U32_SEL-1]); + n = kmalloc(sizeof(*n) + s->nkeys*sizeof(struct tc_u32_key), GFP_KERNEL); if (n == NULL) return -ENOBUFS; + memset(n, 0, sizeof(*n) + s->nkeys*sizeof(struct tc_u32_key)); +#ifdef CONFIG_CLS_U32_PERF + n->pf = kmalloc(sizeof(struct tc_u32_pcnt) + s->nkeys*sizeof(__u64), GFP_KERNEL); + if (n->pf == NULL) { + kfree(n); + return -ENOBUFS; + } + memset(n->pf, 0, sizeof(struct tc_u32_pcnt) + s->nkeys*sizeof(__u64)); +#endif + memcpy(&n->sel, s, sizeof(*s) + s->nkeys*sizeof(struct tc_u32_key)); n->ht_up = ht; n->handle = handle; +{ + u8 i = 0; + u32 mask = s->hmask; + if (mask) { + while (!(mask & 1)) { + i++; + mask>>=1; + } + } + n->fshift = i; +} err = u32_set_parms(tp->q, base, ht, n, tb, tca[TCA_RATE-1]); if (err == 0) { struct tc_u_knode **ins; @@ -587,6 +737,10 @@ static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle, *arg = (unsigned long)n; return 0; } +#ifdef CONFIG_CLS_U32_PERF + if (n && (NULL != n->pf)) + kfree(n->pf); +#endif kfree(n); return err; } @@ -656,26 +810,74 @@ static int u32_dump(struct tcf_proto *tp, unsigned long fh, RTA_PUT(skb, TCA_U32_CLASSID, 4, &n->res.classid); if (n->ht_down) RTA_PUT(skb, TCA_U32_LINK, 4, &n->ht_down->handle); +#ifdef CONFIG_NET_CLS_ACT + /* again for backward compatible mode - we want + * to work with both old and new modes of entering + * tc data even if iproute2 was newer - jhs + */ + if (n->action) { + struct rtattr * p_rta = (struct rtattr*)skb->tail; + + if (n->action->type != TCA_OLD_COMPAT) { + RTA_PUT(skb, TCA_U32_ACT, 0, NULL); + if (tcf_action_dump(skb,n->action, 0, 0) < 0) { + goto rtattr_failure; + } + } else { + RTA_PUT(skb, TCA_U32_POLICE, 0, NULL); + if (tcf_action_dump_old(skb,n->action,0,0) < 0) { + goto rtattr_failure; + } + } + + p_rta->rta_len = skb->tail - (u8*)p_rta; + } + +#else #ifdef CONFIG_NET_CLS_POLICE if (n->police) { struct rtattr * p_rta = (struct rtattr*)skb->tail; - RTA_PUT(skb, TCA_U32_POLICE, 0, NULL); - + if (tcf_police_dump(skb, n->police) < 0) goto rtattr_failure; p_rta->rta_len = skb->tail - (u8*)p_rta; + + } +#endif +#endif + +#ifdef CONFIG_NET_CLS_IND + if(strlen(n->indev)) { + struct rtattr * p_rta = (struct rtattr*)skb->tail; + RTA_PUT(skb, TCA_U32_INDEV, IFNAMSIZ, n->indev); + p_rta->rta_len = skb->tail - (u8*)p_rta; } +#endif +#ifdef CONFIG_CLS_U32_PERF + RTA_PUT(skb, TCA_U32_PCNT, + sizeof(struct tc_u32_pcnt) + n->sel.nkeys*sizeof(__u64), + n->pf); #endif } rta->rta_len = skb->tail - b; +#ifdef CONFIG_NET_CLS_ACT + if (TC_U32_KEY(n->handle) != 0) { + if (TC_U32_KEY(n->handle) && n->action && n->action->type == TCA_OLD_COMPAT) { + if (tcf_action_copy_stats(skb,n->action)) + goto rtattr_failure; + } + } +#else #ifdef CONFIG_NET_CLS_POLICE if (TC_U32_KEY(n->handle) && n->police) { - if (qdisc_copy_stats(skb, &n->police->stats)) + if (qdisc_copy_stats(skb, &n->police->stats, + n->police->stats_lock)) goto rtattr_failure; } +#endif #endif return skb->len; @@ -701,6 +903,19 @@ static struct tcf_proto_ops cls_u32_ops = { static int __init init_u32(void) { + printk("u32 classifier\n"); +#ifdef CONFIG_CLS_U32_PERF + printk(" Perfomance counters on\n"); +#endif +#ifdef CONFIG_NET_CLS_POLICE + printk(" OLD policer on \n"); +#endif +#ifdef CONFIG_NET_CLS_IND + printk(" input device check on \n"); +#endif +#ifdef CONFIG_NET_CLS_ACT + printk(" Actions configured \n"); +#endif return register_tcf_proto_ops(&cls_u32_ops); }