Russell Stuart
2006-Jun-15 09:01 UTC
[PATCH 1/2] Runtime configuration of HTB''s HYSTERESIS option (kernel)
The HTB qdisc has a compile time option, HTB_HYSTERESIS, that trades accuracy of traffic classification for CPU time. These patches change hysteresis to be a runtime option under the control of "tc". The effects of HYSTERESIS on HTB''s accuracy are significant (see chapter 7, section 7.3.1, pp 69-70 in Jesper Brouer''s thesis: http://www.adsl-optimizer.dk/thesis/ ), whereas HTB''s CPU usage on modern machines using broadband links is minimal. Currently HYSTERESIS is on by default, and requires a kernel re-compile to change. Altering it to be a runtime option will make life easier for the bulk of its users. Further documentation on the patch and its usage can be found here: http://www.stuart.id.au/russell/files/tc/tc-atm Signed-off-by: Russell Stuart <russell-tcatm@stuart.id.au> Signed-off-by: Jesper Dangaard Brouer <hawk@comx.dk> --- diff -Nurp kernel-source-2.6.11.orig/include/linux/pkt_sched.h kernel-source-2.6.11/include/linux/pkt_sched.h --- kernel-source-2.6.11.orig/include/linux/pkt_sched.h 2005-03-02 17:38:13.000000000 +1000 +++ kernel-source-2.6.11/include/linux/pkt_sched.h 2006-06-13 11:34:25.000000000 +1000 @@ -231,6 +231,10 @@ struct tc_gred_sopt #define TC_HTB_MAXDEPTH 8 #define TC_HTB_PROTOVER 3 /* the same as HTB and TC''s major */ +struct tc_htb_hopt +{ + __u32 nohyst; +}; struct tc_htb_opt { struct tc_ratespec rate; @@ -258,6 +262,7 @@ enum TCA_HTB_INIT, TCA_HTB_CTAB, TCA_HTB_RTAB, + TCA_HTB_NOHYST, __TCA_HTB_MAX, }; diff -Nurp kernel-source-2.6.11.orig/net/sched/sch_htb.c kernel-source-2.6.11/net/sched/sch_htb.c --- kernel-source-2.6.11.orig/net/sched/sch_htb.c 2005-03-02 17:38:12.000000000 +1000 +++ kernel-source-2.6.11/net/sched/sch_htb.c 2006-06-13 11:34:25.000000000 +1000 @@ -73,7 +73,6 @@ #define HTB_EWMAC 2 /* rate average over HTB_EWMAC*HTB_HSIZE sec */ #undef HTB_DEBUG /* compile debugging support (activated by tc tool) */ #define HTB_RATECM 1 /* whether to use rate computer */ -#define HTB_HYSTERESIS 1/* whether to use mode hysteresis for speedup */ #define HTB_QLOCK(S) spin_lock_bh(&(S)->dev->queue_lock) #define HTB_QUNLOCK(S) spin_unlock_bh(&(S)->dev->queue_lock) #define HTB_VER 0x30011 /* major must be matched with number suplied by TC as version */ @@ -190,6 +189,7 @@ struct htb_class /* class attached filters */ struct tcf_proto *filter_list; int filter_cnt; + int nohyst; /* Don''t use hysteresis htb_class_mode */ int warned; /* only one warning about non work conserving .. */ @@ -622,20 +622,14 @@ static __inline__ enum htb_cmode htb_class_mode(struct htb_class *cl,long *diff) { long toks; + long hysteresis + (cl->nohyst || cl->cmode == HTB_CANT_SEND) ? 0 : -cl->cbuffer; - if ((toks = (cl->ctokens + *diff)) < ( -#if HTB_HYSTERESIS - cl->cmode != HTB_CANT_SEND ? -cl->cbuffer : -#endif - 0)) { + if ((toks = (cl->ctokens + *diff)) < hysteresis) { *diff = -toks; return HTB_CANT_SEND; } - if ((toks = (cl->tokens + *diff)) >= ( -#if HTB_HYSTERESIS - cl->cmode == HTB_CAN_SEND ? -cl->buffer : -#endif - 0)) + if ((toks = (cl->tokens + *diff)) >= hysteresis) return HTB_CAN_SEND; *diff = -toks; @@ -1323,6 +1317,7 @@ static int htb_dump_class(struct Qdisc * unsigned char *b = skb->tail; struct rtattr *rta; struct tc_htb_opt opt; + struct tc_htb_hopt hopt; HTB_DBG(0,1,"htb_dump_class handle=%X clid=%X\n",sch->handle,cl->classid); @@ -1342,6 +1337,8 @@ static int htb_dump_class(struct Qdisc * opt.quantum = cl->un.leaf.quantum; opt.prio = cl->un.leaf.prio; opt.level = cl->level; RTA_PUT(skb, TCA_HTB_PARMS, sizeof(opt), &opt); + hopt.nohyst = cl->nohyst; + RTA_PUT(skb, TCA_HTB_NOHYST, sizeof(hopt), &hopt); rta->rta_len = skb->tail - b; HTB_QUNLOCK(sch); return skb->len; @@ -1527,11 +1524,12 @@ static int htb_change_class(struct Qdisc struct htb_class *cl = (struct htb_class*)*arg,*parent; struct rtattr *opt = tca[TCA_OPTIONS-1]; struct qdisc_rate_table *rtab = NULL, *ctab = NULL; - struct rtattr *tb[TCA_HTB_RTAB]; + struct rtattr *tb[TCA_HTB_MAX]; struct tc_htb_opt *hopt; + struct tc_htb_hopt *uhopt; /* extract all subattrs from opt attr */ - if (!opt || rtattr_parse_nested(tb, TCA_HTB_RTAB, opt) || + if (!opt || rtattr_parse_nested(tb, TCA_HTB_MAX, opt) || tb[TCA_HTB_PARMS-1] == NULL || RTA_PAYLOAD(tb[TCA_HTB_PARMS-1]) < sizeof(*hopt)) goto failure; @@ -1544,6 +1542,10 @@ static int htb_change_class(struct Qdisc ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB-1]); if (!rtab || !ctab) goto failure; + uhopt = RTA_DATA(tb[TCA_HTB_NOHYST-1]); + if (uhopt != NULL && RTA_PAYLOAD(tb[TCA_HTB_NOHYST-1]) < sizeof(*uhopt)) + goto failure; + if (!cl) { /* new class */ struct Qdisc *new_q; /* check for valid classid */ @@ -1636,6 +1638,7 @@ static int htb_change_class(struct Qdisc cl->cbuffer = hopt->cbuffer; if (cl->rate) qdisc_put_rtab(cl->rate); cl->rate = rtab; if (cl->ceil) qdisc_put_rtab(cl->ceil); cl->ceil = ctab; + if (uhopt) cl->nohyst = uhopt->nohyst; sch_tree_unlock(sch); *arg = (unsigned long)cl;