Linux内核中游量控制(8)

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

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,

Linux内核中游量控制(8)

相关文章:

你感兴趣的文章:

标签云: