- 求职 : 通讯/电信开
- 论坛徽章:
- 2
|
各位兄弟姐妹,经过上面的兄弟的提醒,我找到了PFIFO_FAST流控算法,目前是默认的流控算法,用到了skb->priority字段,给大家一个参考,共同进步。感谢Chinaunix- 5. 流控算法的具体实现
- 5.1 PFIFO_FAST
- PFIFO_FAST是缺省的流控算法,网卡初始化时就是设置该算法为网卡的流控算法,算法比较简单,就
- 在net/sched/sch_generic.c中定义了,没在单独文件中定义。
- 5.1.1 操作结构定义
- #define PFIFO_FAST_BANDS 3
- static struct Qdisc_ops pfifo_fast_ops = {
- .id = "pfifo_fast",
- // 私有数据是3个skb数据包链表头
- .priv_size = PFIFO_FAST_BANDS * sizeof(struct sk_buff_head),
- .enqueue = pfifo_fast_enqueue,
- .dequeue = pfifo_fast_dequeue,
- .requeue = pfifo_fast_requeue,
- .init = pfifo_fast_init,
- .reset = pfifo_fast_reset,
- .dump = pfifo_fast_dump,
- .owner = THIS_MODULE,
- };
- 该算法中, 数据队列是3个, 流控算法就是将数据包输入特定的队列, 从特定队列中取数据包。
- 5.1.2 初始化
- static int pfifo_fast_init(struct Qdisc *qdisc, struct rtattr *opt)
- {
- int prio;
- // qdisc私有数据指针, 数据包链表头
- struct sk_buff_head *list = qdisc_priv(qdisc);
- // 初始化3个链表头
- for (prio = 0; prio < PFIFO_FAST_BANDS; prio++)
- skb_queue_head_init(list + prio);
- return 0;
- }
- 5.1.3 入队
- static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc* qdisc)
- {
- // 根据数据包的优先级参数挑一个队列头准备将数据包插入该队列
- struct sk_buff_head *list = prio2list(skb, qdisc);
- // 如果当前队列中的数据包数量小于网卡设备允许的输出队列的数量
- // 则将该数据包插入该队列
- if (skb_queue_len(list) < qdisc->dev->tx_queue_len) {
- qdisc->q.qlen++;
- return __qdisc_enqueue_tail(skb, qdisc, list);
- }
- // 否则的话丢弃该数据包
- return qdisc_drop(skb, qdisc);
- }
- // 选队列处理
- static inline struct sk_buff_head *prio2list(struct sk_buff *skb,
- struct Qdisc *qdisc)
- {
- // qdisc私有数据指针, 数据包链表头
- struct sk_buff_head *list = qdisc_priv(qdisc);
- // 根据数据包的优先权值确定队列头偏移值
- // skb->priority是个32位整数, 只使用最后4位
- return list + prio2band[skb->priority & TC_PRIO_MAX];
- }
- // 优先权值到队列号的变换数组, 该数组体现算法内容, 通过修改该数组可以调整算法效果
- // 该数组定义中, 优先值(低4位)为1,2,3,5时使用2号队列, 优先值(低4位)为6,7时使用0号
- // 队列, 其他值为1号队列
- // 在普通情况下skb->priority都是0, 所有应该只使用了1号队列
- // 这个数组实际是根据RFC1349中定义的TOS类型值定义的, 在该RFC中TOS就是只有4位有效
- static const u8 prio2band[TC_PRIO_MAX+1] =
- { 1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1 };
- 5.1.4 出队
- static struct sk_buff *pfifo_fast_dequeue(struct Qdisc* qdisc)
- {
- int prio;
- struct sk_buff_head *list = qdisc_priv(qdisc);
- // 循环3个队列
- for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) {
- // 如果队列非空, 返回队列头的那个数据包
- if (!skb_queue_empty(list + prio)) {
- qdisc->q.qlen--;
- return __qdisc_dequeue_head(qdisc, list + prio);
- }
- }
- return NULL;
- }
- 由此可见, 0号队列有最高优先级, 2号队列优先级最低, 只有高优先级队列中的数据都发送完后才发
- 送低优先级队列中的数据。
- 5.1.5 重入队
- static int pfifo_fast_requeue(struct sk_buff *skb, struct Qdisc* qdisc)
- {
- // 队列长度递增
- qdisc->q.qlen++;
- // 使用标准重入队函数将数据插回队列链表
- return __qdisc_requeue(skb, qdisc, prio2list(skb, qdisc));
- }
- 5.1.6 复位
- static void pfifo_fast_reset(struct Qdisc* qdisc)
- {
- int prio;
- struct sk_buff_head *list = qdisc_priv(qdisc);
- // 释放三个队列链表中的所有数据包
- for (prio = 0; prio < PFIFO_FAST_BANDS; prio++)
- __qdisc_reset_queue(qdisc, list + prio);
- // 计数清零
- qdisc->qstats.backlog = 0;
- qdisc->q.qlen = 0;
- }
- 5.1.7 输出
- 输出当前算法的内容信息, 由于PFIFO_FAST算法核心就是prio2band数组, 因此就是将该数组内容输
- 出到数据包供用户空间获取。
- static int pfifo_fast_dump(struct Qdisc *qdisc, struct sk_buff *skb)
- {
- // TC优先权数组结构
- struct tc_prio_qopt opt = { .bands = PFIFO_FAST_BANDS };
- // 将当前prio2band数组内容拷贝到选项数据中
- memcpy(&opt.priomap, prio2band, TC_PRIO_MAX+1);
- // 将结构作为路由属性复制到数据包中供返回
- RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
- return skb->len;
- rtattr_failure:
- return -1;
- }
-
- ...... 待续 ......
- 发表于: 2007-07-28,修改于: 2007-07-29 15:30,已浏览3052次,有评论2条 推荐 投诉
- 网友: burning423 时间:2007-09-21 08:53:33 IP地址:218.108.51.★
-
- 5.1.2 初始化
- static int pfifo_fast_init(struct Qdisc *qdisc, struct rtattr *opt)
- {
- int prio;
- // qdisc私有数据指针, 数据包链表头
- struct sk_buff_head *list = qdisc_priv(qdisc);
- ........................................
- struct sk_buff_head *list = qdisc_priv(qdisc);这语句是怎样得到qdisc的私有数据的?我看了qdisc_priv(qdisc)函数的定义,可还是不是很明白.你能否给我解释一下?谢谢了..刚开始看内核的东西....
- 网友: yfydz 时间:2007-09-22 21:44:39 IP地址:123.116.100.★
-
- 每种qdisc定义都包括基本的Qdisc结构和后面一些参数, 大小由prive_size指定, 那些参数就是该qdisc的私有数据, 获取私有数据的指针就是从Qdisc起始位置移动标准Qdisc大小就是了
复制代码 |
|