日期:2014-05-16 浏览次数:20686 次
5.8 GRED(Generic Random Early Detection queue) GRED算法是GRED的通用化,还是以RED算法为基础,但不再是根据一个RED流控节点计算丢包情况,而 是可以定义多个虚拟RED流控节点,然后根据skb数据包中的tc_index参数将数据分配到不同的节点, 每个节点都按RED算法进行流控。之所以叫虚拟队列,因为实际的队列数据结构还是只有一个队列, 但每个skb包的入队出队是由不同的RED流控结构控制的。 GRED和RED的关系就类似PRIO和pfifo_fast的关系,但队列只是一个。 5.8.1 GRED操作结构定义 // GRED算法参数 struct gred_sched_data { // 流量限制值 u32 limit; /* HARD maximal queue length */ u32 DP; /* the drop pramaters */ // 该虚拟队列看到的字节数和包数 u32 bytesin; /* bytes seen on virtualQ so far*/ u32 packetsin; /* packets seen on virtualQ so far*/ // 队列中正在等待的数据长度 u32 backlog; /* bytes on the virtualQ */ // 该虚拟队列优先级 u8 prio; /* the prio of this vq */ // RED算法参数和统计结构 struct red_parms parms; struct red_stats stats; }; // WRED模式或RIO模式 enum { // WRED模式是处理有相同的PRIO的不同虚拟队列的情况 GRED_WGRED_MODE = 1, // RIO应该就是PRIO吧, 队列优先级有效 GRED_RIO_MODE, }; // GRED私有数据结构 struct gred_sched { // 最大MAX_DPs(16)个GRED参数项, 每个相当于一个RED虚拟队列 struct gred_sched_data *tab[MAX_DPs]; unsigned long flags; // 包括WRED和RIO标志 u32 red_flags; // RED算法标志, 包括ECN和HARDDROP u32 DPs; // DP的数量, 有效的tab的数量, 小于16 u32 def; // 缺省DP struct red_parms wred_set; // RED算法总体参数 }; // GRED流控操作结构 static struct Qdisc_ops gred_qdisc_ops = { .id = "gred", .priv_size = sizeof(struct gred_sched), .enqueue = gred_enqueue, .dequeue = gred_dequeue, .requeue = gred_requeue, .drop = gred_drop, .init = gred_init, .reset = gred_reset, .destroy = gred_destroy, .change = gred_change, .dump = gred_dump, .owner = THIS_MODULE, }; GRED没有定义类别操作结构 5.8.1 GRED一些操作函数 // 检查是否设置WRED模式, 检测WRED位是否设置 static inline int gred_wred_mode(struct gred_sched *table) { return test_bit(GRED_WRED_MODE, &table->flags); } // 打开WRED模式 static inline void gred_enable_wred_mode(struct gred_sched *table) { __set_bit(GRED_WRED_MODE, &table->flags); } // 关闭WRED模式 static inline void gred_disable_wred_mode(struct gred_sched *table) { __clear_bit(GRED_WRED_MODE, &table->flags); } // 检测是否设置RIO模式, 检测RIO位是否设置 static inline int gred_rio_mode(struct gred_sched *table) { return test_bit(GRED_RIO_MODE, &table->flags); } // 打开RIO模式 static inline void gred_enable_rio_mode(struct gred_sched *table) { __set_bit(GRED_RIO_MODE, &table->flags); } // 关闭RIO模式 static inline void gred_disable_rio_mode(struct gred_sched *table) { __clear_bit(GRED_RIO_MODE, &table->flags); } // WRED模式检查 static inline int gred_wred_mode_check(struct Qdisc *sch) { // GRED私有数据 struct gred_sched *table = qdisc_priv(sch); int i; // 两层循环比较不同的表项的prio值是否相同 /* Really ugly O(n^2) but shouldn't be necessary too frequent. */ for (i = 0; i < table->DPs; i++) { struct gred_sched_data *q = table->tab[i]; int n; if (q == NULL) continue; for (n = 0; n < table->DPs; n++) if (table->tab[n] && table->tab[n] != q && table->tab[n]->prio == q->prio) // 有prio相同的不同表项返回1 return 1; } // prio值都不同返回0 return 0; } // GRED等待队列值 static inline unsigned int gred_backlog(struct gred_sched *table, struct gred_sched_data *q, struct Qdisc *sch) { // WRED模式下使用qdisc的统计值 if (gred_wred_mode(table)) return sch->qstats.backlog; else // 否则返回GRED的backlog return q->backlog; } // 将skb包的tc_index转换为DP索引值 static inline u16 tc_index_to_dp(struct sk_buff *skb) { // 直接和GRED_VQ_MASK(MAX_DPs - 1)相与, 不知道为什么不用%, 这样就不必限制 // MAX_DPs是2的整数幂 return skb->tc_index & GRED_VQ_MASK; } // 加载RED参数, 从gred_sched到gred_sched_data static inline void gred_load_wred_set(struct gred_sched *table, struct gred_sched_data *q) { // 平均队列值 q->parms.qavg = table->wred_set.qavg; // 休眠起始时间 q->parms.qidlestart = table->wred_set.qidlestart; } // 恢复RED参数, 从gred_sched_data到gred_sched static inline void gred_store_wred_set(struct gred_sched *table,