日期:2014-05-16  浏览次数:20756 次

Linux内核中流量控制(14)
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn
5.14  CBQ(Class Based Queueing, 基于类别的排队)

CBQ(Class-Based Queueing discipline)是个经典的基于分类的流控算法,比较复杂, 具体算法基础也是TBF, 也是根据令牌情况决定是否发送数据包。CBQ在HTB出现后一般用得就少了, 其实对于分类的类别操作和HTB也差不多, 所以只简要介绍一下入队和出队操作过程, 其他处理过程不再详细分析了。

5.14.1 CBQ相关结构定义

// CBQ流控结构
static struct Qdisc_ops cbq_qdisc_ops = {
 .next  = NULL,
 .cl_ops  = &cbq_class_ops,
 .id  = "cbq",
// 私有数据是一个用于CBQ调度的数据结构struct cbq_sched_data
 .priv_size = sizeof(struct cbq_sched_data),
 .enqueue = cbq_enqueue,
 .dequeue = cbq_dequeue,
 .requeue = cbq_requeue,
 .drop  = cbq_drop,
 .init  = cbq_init,
 .reset  = cbq_reset,
 .destroy = cbq_destroy,
 .change  = NULL,
 .dump  = cbq_dump,
 .dump_stats = cbq_dump_stats,
 .owner  = THIS_MODULE,
};

// CBQ类别操作结构
static struct Qdisc_class_ops cbq_class_ops = {
 .graft  = cbq_graft,
 .leaf  = cbq_leaf,
 .get  = cbq_get,
 .put  = cbq_put,
 .change  = cbq_change_class,
 .delete  = cbq_delete,
 .walk  = cbq_walk,
 .tcf_chain = cbq_find_tcf,
 .bind_tcf = cbq_bind_filter,
 .unbind_tcf = cbq_unbind_filter,
 .dump  = cbq_dump_class,
 .dump_stats = cbq_dump_class_stats,
};

// CBQ调度数据, 是作为CBQ调度算法的Qdisc的私有数据
struct cbq_sched_data
{
// 类别HASH表, 16个链表
 struct cbq_class *classes[16];  /* Hash table of all classes */
 int   nclasses[TC_CBQ_MAXPRIO+1];
 unsigned  quanta[TC_CBQ_MAXPRIO+1];
 struct cbq_class link;
 unsigned  activemask;
// 活动的CBQ类别链表, 最多8+1个, 按类别优先权区分
 struct cbq_class *active[TC_CBQ_MAXPRIO+1]; /* List of all classes
           with backlog */
#ifdef CONFIG_NET_CLS_POLICE
// 接收用的CBQ类别结构
 struct cbq_class *rx_class;
#endif
// 发送用的CBQ类别结构
 struct cbq_class *tx_class;
// 借带宽时的CBQ类别结构
 struct cbq_class *tx_borrowed;
 int   tx_len;
 psched_time_t  now;  /* Cached timestamp */
 psched_time_t  now_rt;  /* Cached real time */
 unsigned  pmask;
 struct timer_list delay_timer;
 struct timer_list wd_timer; /* Watchdog timer,
         started when CBQ has
         backlog, but cannot
         transmit just now */
 long   wd_expires;
 int   toplevel;
 u32   hgenerator;
};

// CBQ类别结构
struct cbq_class
{
// 链表下一项
 struct cbq_class *next;  /* hash table link */
// backlog中的下一个活动的类别结构
 struct cbq_class *next_alive; /* next class with backlog in this priority band */
/* Parameters */
// 类型ID值
 u32   classid;
// 正常情况下的优先权值
 unsigned char  priority; /* class priority */
// 流量超过限制值后使用的优先权值
 unsigned char  priority2; /* priority to be used after overlimit */
//
 unsigned char  ewma_log; /* time constant for idle time calculation */
// ovl策略
 unsigned char  ovl_strategy;
#ifdef CONFIG_NET_CLS_POLICE
 unsigned char  police;
#endif
// 缺省
 u32   defmap;
 /* Link-sharing scheduler parameters */
 long   maxidle; /* Class parameters: see below. */
 long   offtime;
 long   minidle;
 u32   avpkt;
// 流量表指针
 struct qdisc_rate_table *R_tab;
 /* Overlimit strategy parameters */
// 超过限制时的处理函数
 void   (*overlimit)(struct cbq_class *cl);
 long   penalty;
 /* General scheduler (WRR) parameters */
 long   allot;
 long   quantum; /* Allotment per WRR round */
 long   weight;  /* Relative allotment: see below */
// 指向当前Qdisc结构
 struct Qdisc  *qdisc;  /* Ptr to CBQ discipline */
 struct cbq_class *split;  /* Ptr to split node */
 struct cbq_class *share;  /* Ptr to LS parent in the class tree */
 struct cbq_class *tparent; /* Ptr to tree parent in the class tree */
 struct cbq_class *borrow; /* NULL if class is bandwidth limited;
         parent otherwise */
 struct cbq_class *sibling; /* Sibling chain */
 struct cbq_class *children; /* Pointer to children chain */
// 内部流控节点, 实际通过该Qdisc完成流控操作
 struct Qdisc  *q;  /* Elementary queueing discipline */

/* Variables */
 unsigned char  cpriority; /* Effective priority */
 unsigned char  delayed;
 unsigned char  level;  /* level of the class in hierarchy:
         0 for leaf classes, and maximal
         level of children + 1 for nodes.
       */
 psched_time_