📄 linux 2_4_x 网络协议栈qos模块(tc)的设计与实现.htm
字号:
<P>在网卡down掉的时候,通过调用dev_close ->
dev_deactivate重新使设备的qdisc为noop_qdisc,停止发送数据包。</P>
<P>Linux中的所有的QoS策略最终都是通过上面这个方法来安装的。在sch_api.c中,对dev_graft_qdisc函数又封装了一层函数(register_qdisc),供模块来安装新的Qdisc。如RED(早期随即检测队列)模块,就调用register_qdisc来安装RED对象(net/sched/sch_red.c->init_module())。</P>
<P><A name=3><SPAN class=atitle2>3.
Linux缺省策略对象pfifo_fast_ops分析</SPAN></A></P>
<P>
<CENTER><IMG height=318 alt=""
src="Linux 2_4_x 网络协议栈QoS模块(TC)的设计与实现.files/image004.gif" width=545
border=0> <BR></CENTER>
<P></P>
<P>在Linux中,如果设备启动之后,没有配置特定的QoS策略,内核对每个设备采用缺省的策略,pfifo_fast_ops。下面的pfifo_fast_ops进行详细的分析。</P>
<P>上图中的信息可以对应于pfifo_fast_ops结构体的每个部分:</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
static struct Qdisc_ops pfifo_fast_ops =
{
NULL,
NULL,
"pfifo_fast", /*ops名称*/
3 * sizeof(struct sk_buff_head), /*数据包skb队列*/
pfifo_fast_enqueue, /*入队列函数*/
pfifo_fast_dequeue, /*出队列函数*/
pfifo_fast_requeue, /*重新压入队列函数*/
NULL,
pfifo_fast_init, /*队列管理初始化函数*/
pfifo_fast_reset, /*队列管理重置函数*/
};
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>在注册pfifo_fast_ops的时候首先会调用pfifo_fast_init来初始化队列管理,见qdisc_create_dflt函数。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
static int pfifo_fast_init(struct Qdisc *qdisc, struct rtattr *opt)
{
………
for (i=0; i<3; i++)
skb_queue_head_init(list+i); /*初始化3个优先级队列*/
……….
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>init函数的作用就是初始化3个队列。</P>
<P>在注销一个Qdisc的时候都会调用Qdisc的ops的reset函数。见dev_graft_qdisc函数。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
static void
pfifo_fast_reset(struct Qdisc* qdisc)
{
…………..
for (prio=0; prio < 3; prio++)
skb_queue_purge(list+prio); /*释放3个优先级队列中的所有数据包*/
…………..
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>在数据包发送的时候会调用Qdisc->enqueue函数(在qdisc_create_dflt函数中已经将Qdisc_ops的enqueue,dequeue,requeue函数分别赋值于Qdisc分别对应的函数指针)。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
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;
}
……………
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>入队列函数pfifo_fast_enqueue:</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
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;
}
……………..
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>在数据包放入队列之后,调用qdisc_run来发送数据包。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
static inline void qdisc_run(struct net_device *dev)
{
while (!netif_queue_stopped(dev) &&
qdisc_restart(dev)<0)
/* NOTHING */;
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>在qdisc_restart函数中,首先从队列中取出一个数据包(调用函数pfifo_fast_dequeue)。然后调用网卡驱动的发送函数(dev->hard_start_xmit)发送数据包,如果发送失败,则需要将这个数据包重新压入队列(pfifo_fast_requeue),然后启动协议栈的发送软中断进行再次的发送。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
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;
}
}
……………….
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<P>从dequeue函数中可以看出,pfifo的策略是:从高优先级队列中取出数据包,只有高优先级的队列为空,才会对下一优先级的队列进行处理。</P>
<P>requeue函数重新将数据包压入相应优先级队列的头部。</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>
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;
}
</CODE></PRE></TD></TR></TBODY></TABLE>
<P><A name=4><SPAN class=atitle2>总结:</SPAN></A></P>
<P>QoS是当前一个非常热门的话题,几乎所有高端的网络设备都支持QoS功能,并且这个功能也是当前网络设备之间竞争的一个关键技术。Linux为了在在高端服务器能够占有一席之地,从2.2.x内核开始就支持了QoS。本文在linux
2.4.0的代码基础上对Linux如何支持QoS进行了分析。并且分析了Linux内核的缺省队列处理方法PFIFO的实现。</P>
<P><A name=resources><SPAN class=atitle2>参考文献:</SPAN></A></P>
<P>(1) linux 2.4.0 内核源代码。</P>
<P><A name=author1><SPAN class=atitle2>作者简介:</SPAN></A></P>
<P>祝顺民,网名:getmoon。目前从事防火墙开发,致力于网络的研究和开发,分析linux内核。经常出没于<A
href="http://www.linuxforum.net/">http://www.linuxforum.net/</A>的内核板块。希望于爱好者们共同探讨。email:<A
href="mailto:getmoon@163.com">getmoon@163.com</A></P><!-- END PAPER BODY--></TD>
<TD width=10><IMG height=1 alt=""
src="Linux 2_4_x 网络协议栈QoS模块(TC)的设计与实现.files/c.gif" width=10
border=0></TD></TR></TBODY></TABLE><BR clear=all><IMG height=10 alt=""
src="Linux 2_4_x 网络协议栈QoS模块(TC)的设计与实现.files/c.gif" width=100 border=0><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD align=right width="100%"><A
href="http://www-900.ibm.com/developerWorks/cn/linux/kernel/l-qos/index.shtml#top">到页首</A></TD>
<TD width=5><IMG height=1 alt=""
src="Linux 2_4_x 网络协议栈QoS模块(TC)的设计与实现.files/c.gif" width=5 border=0></TD></TR>
<TR vAlign=top>
<TD bgColor=#000000 colSpan=2><IMG height=1 alt=""
src="Linux 2_4_x 网络协议栈QoS模块(TC)的设计与实现.files/c.gif" width=100
border=0></TD></TR>
<TR vAlign=top>
<TD bgColor=#ffffff colSpan=2><IMG height=8 alt=""
src="Linux 2_4_x 网络协议栈QoS模块(TC)的设计与实现.files/c.gif" width=100
border=0></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=10 width="100%" border=0>
<TBODY>
<TR vAlign=top>
<TD>
<FORM action=/developerWorks/cn/cnratings.nsf/RateArticle?CreateDocument
method=post><INPUT type=hidden value="Linux 2.4.x 网络协议栈QoS模块(TC)的设计与实现"
name=ArticleTitle> <INPUT type=hidden value=linux name=Zone> <INPUT
type=hidden value=/developerWorks/cn/thankyou/feedback-linux.html
name=RedirectURL> <A name=rating><B>您对这篇文章的看法如何?</B></A>
<TABLE cellSpacing=0 cellPadding=0 width=600 border=0>
<TBODY>
<TR>
<TD colSpan=5><IMG height=8 alt=""
src="Linux 2_4_x 网络协议栈QoS模块(TC)的设计与实现.files/c.gif" width=100
border=0></TD></TR>
<TR vAlign=top>
<TD width="16%"><INPUT type=radio value=5 name=Rating>真棒!(5)</TD>
<TD width="20%"><INPUT type=radio value=4 name=Rating>好材料 (4)</TD>
<TD width="24%"><INPUT type=radio value=3 name=Rating>一般;尚可 (3)</TD>
<TD width="22%"><INPUT type=radio value=2 name=Rating>需提高 (2)</TD>
<TD width="18%"><INPUT type=radio value=1 name=Rating>太差!
(1)</TD></TR></TBODY></TABLE><BR><B>建议?</B><BR><TEXTAREA name=Comments rows=5 wrap=virtual cols=60></TEXTAREA><BR><BR><INPUT type=submit value=提交反馈意见></FORM></TD></TR>
<TR vAlign=top>
<TD bgColor=#ffffff><IMG height=8 alt=""
src="Linux 2_4_x 网络协议栈QoS模块(TC)的设计与实现.files/c.gif" width=100
border=0></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD align=right>(c) Copyright IBM Corp. 2001, (c) Copyright IBM China
2001, All Right Reserved</TD></TR>
<TR vAlign=top>
<TD class=bbg height=21> <A class=mainlink
href="http://www-900.ibm.com/developerWorks/cn/cgi-bin/click.cgi?url=www-900.ibm.com/cn/ibm/index.shtml&origin=dwhead">关于
IBM</A><SPAN class=divider> | </SPAN><A
class=mainlink
href="http://www-900.ibm.com/developerWorks/cn/cgi-bin/click.cgi?url=www-900.ibm.com/cn/ibm/privacy/index.shtml&origin=dwhead">隐私条约</A><SPAN
class=divider> | </SPAN><A class=mainlink
href="http://www-900.ibm.com/developerWorks/cn/cgi-bin/click.cgi?url=www-900.ibm.com/cn/ibm/legal/index.shtml&origin=dwhead">使用条款</A><SPAN
class=divider> | </SPAN><A class=mainlink
href="http://www-900.ibm.com/developerWorks/cn/cgi-bin/click.cgi?url=www-900.ibm.com/cn/ibm/contact/index.shtml&origin=dwhead">联系
IBM</A></TD></TR></TBODY></TABLE>
<SCRIPT language=JavaScript1.2
src="Linux 2_4_x 网络协议栈QoS模块(TC)的设计与实现.files/stats.js"
type=text/javascript></SCRIPT>
<NOSCRIPT><IMG height=1 alt="" src="" width=1 border=0></NOSCRIPT>
</A></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -