isc)
{
…………..
for (prio=0; prio < 3; prio++)
skb_queue_purge(list+prio); /*释放3个优先级队列中的所有数据包*/
…………..
}
在数据包发送的时候会调用Qdisc->enqueue函数(在qdisc_create_dflt函数中已经将Qdisc_ops的enqueue,dequeue,requeue函数分别赋值于Qdisc分别对应的函数指针)。
int dev_queue_xmit(struct sk_buff *skb)
{
……………….
q = dev->qdisc;
if (q->enqueue) {
/* 对应于pfifo_fast_enqueue 函数*/
int ret = q->enqueue(skb, q);
/*启动这个设备的发送,这里涉及到两个函数pfifo_fast_dequeue ,pfifo_fast_requeue 稍后介绍*/
qdisc_run(dev);
return;
}
……………
}
|
入队列函数pfifo_fast_enqueue:
static int
pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc* qdisc)
{
…………..
list = ((struct sk_buff_head*)qdisc->data) +
prio2band[skb->priority&TC_PRIO_MAX];
/*首先确定这个数据包的优先级,决定放入的队列*/
if (list->qlen <= skb->dev->tx_queue_len) {
__skb_queue_tail(list, skb); /*将数据包放入队列的尾部*/
qdisc->q.qlen++;
return 0;
}
……………..
}
|
在数据包放入队列之后,调用qdisc_run来发送数据包。
static inline void qdisc_run(struct net_device *dev)
{
while (!netif_queue_stopped(dev) &&
qdisc_restart(dev)<0)
/* NOTHING */;
}
|
在qdisc_restart函数中,首先从队列中取出一个数据包(调用函数pfifo_fast_dequeue)。然后调用网卡驱动的发送函数(dev->hard_start_xmit)发送数据包,如果发送失败,则需要将这个数据包重新压入队列(pfifo_fast_requeue),然后启动协议栈的发送软中断进行再次的发送。
static struct sk_buff *
pfifo_fast_dequeue(struct Qdisc* qdisc)
{
…………..
for (prio = 0; prio < 3; prio++, list++) {
skb = __skb_dequeue(list);
if (skb) {
qdisc->q.qlen--;
return skb;
}
}
……………….
}
|
从dequeue函数中可以看出,pfifo的策略是:从高优先级队列中取出数据包,只有高优先级的队列为空,才会对下一优先级的队列进行处理。
requeue函数重新将数据包压入相应优先级队列的头部。
static int
pfifo_fast_requeue(struct sk_buff *skb, struct Qdisc* qdisc)
{
struct sk_buff_head *list;
list = ((struct sk_buff_head*)qdisc->data) +
prio2band[skb->priority&TC_PRIO_MAX];
/*确定相应优先级的队列*/
__skb_queue_head(list, skb);/*将数据包压入队列的头部*/
qdisc->q.qlen++;
return 0;
}
|
总结:
QoS是当前一个非常热门的话题,几乎所有高端的网络设备都支持QoS功能,并且这个功能也是当前网络设备之间竞争的一个关键技术。Linux为了在在高端服务器能够占有一席之地,从2.2.x内核开始就支持了QoS。本文在linux 2.4.0的代码基础上对Linux如何支持QoS进行了分析。并且分析了Linux内核的缺省队列处理方法PFIFO的实现。
参考文献:
(1) linux 2.4.0 内核源代码。
作者简介:
祝顺民,网名:getmoon。目前从事防火墙开发,致力于网络的研究和开发,分析linux内核。经常出没于http://www.linuxforum.net/的内核板块。希望于爱好者们共同探讨。email:getmoon@163.com
的设计与实现.files/c.gif) |