手机端
or

欢迎您加入我爱方案网QQ群

1.智能产品外包服务群(311606115)
2.嵌入式项目开发群(491609563)

基于Linux的家庭网关优化

张郭军; 赵薇| 网关,Linux,轮询,中断| 2010-11-29
1225 收藏
分享到: 
每日精选
热门推荐

【中心议题】

  • 提出了一种改善家庭网关性能的思路
  • 给出了关键代码

【解决方案】

  • Linux内核相应报文处理函数做以修改
  • 使报文处理流程处于中断和轮询相互切换的工作模式

随着社会信息化和家庭网络化的飞速发展,越来越多的家庭建立了家庭网络。家庭网关是整个家庭网络的核心,它主要实现Internet接入、远程控制以及连接家庭内部异构子网的功能。家庭网关类似于服务器的功能,集中控制家庭网络中的家电设备,如信息家电、安防系统、报警系统等。在基于Linux网络中,通过Linux驱动程序的形式连接各个模块和操作系统,完成整个软件的构架, CPU总控模块负责初始化和协调各个模块的操作,是整个系统的大脑,事务控制模块支持并发控制,主要保证传递过程中的可靠性和高效性。

1 数据报文处理过程及其缺陷

当网络适配器正确接收到一个数据包时,会触发一个中断,其驱动程序中的中断服务程序将调用确定的接收函数来处理,将收到的网络包放到网络接收队列上,并设置相应状态寄存器,系统会在中断处理返回时,处理发生的软中断,如图1所示。根据状态寄存器就会判断是否接收到了新包、是否完成了传输或是否发生了错误。如果接收到了包,就会调用net_rx()中断处理函数,处理接收包的驱动程序方法负责请求套接字缓冲区并把接收到的包填充到包数据空间中。随后, netif_rx()可以将套接字缓冲区放入输入队列中,最后网络设备的统计信息被更新,并且中断处理程序可以继续处理下一个收到的包也可以终止中断处理。

 

当网络适配器驱动程序执行到netif_rx(),将收到的网络包放到网络接收对列上,同时设置相应中断标志,系统在中断处理返回时,根据标志位信息处理发生的中断,调用对应注册过的net_rx_ac-tion()函数取下网络包,进一步调用对应的处理函数ip_rcv(),对网络包进行路由并转发,最后由dev_queue_xmit()负责将包从对应的出口设备上发送出去,或者在队列忙时将包放入设备发送队列并设置相应网络发送中断,等待中断处理机制推迟发送网络包。

基于Linux网关中转发报文流程执行比较频繁,对系统的效率影响最大。工作在中断模式下的网络适配器,在网络负载比较大的情况下,网络部分的接口会频繁地中断系统,从而造成非常大的系统负载。当网络流量非常大时,在中断级别上处理网络请求的操作系统将会陷入中断影响之中,最终导致报文吞吐率急剧下降。当带宽占用率相同,全部传输短报文的情况下,由于中断非常频繁,系统的峰值处理能力将达到最低限度。

2 基于中断和轮询自动切换的传输机制

为了解决中断驱动模式带来的负面影响,现在提出一种中断和轮询自动切换的报文处理模式。在网络负载较低的情况下,报文到达时间是不可预测的,所以由于报文到达的随机性会产生系统延迟,此时利用中断处理机制能够很好地避免大量延迟产生;但是当网络负载比较高时,报文的输入速率会达到一个基本的稳定状态,如果采用中断处理机制,由于高负荷的网络会带来频繁的中断发生,从而降低系统效率,此时采用轮询机制反而会充分发挥其优势,保证系统的高吞吐率。

具体工作过程如下(工作流程如图2所示):

(1)当报文首次到达时,系统处于开中断状态,此时通过修改标志寄存器的中断允许位使系统处于关中断状态,从而进入轮询模式,同时给滑动窗口W配置一个用于判断每次轮询所接收到的数据报文的个数n;

(2)n<W,报文输入速率达到或接近系统的饱和状态,此时继续处于关中断状态,系统任然保持轮询机制;

(3)nW,报文输入速率比较低,系统有可能进入空轮询状态,为了降低系统开销,修改标志寄存器相应位,使系统由关中断进入开中断状态,重新打开中断,以中断的方式处理报文;

(4)当前报文处理完毕,接收到下一个报文时,

 

重复(1)(2)(3)。如果接收队列未满但系统资源耗尽后,进入初始化状态,释放所有资源。

在轮询工作模式下,为了避免引发外部中断,需要屏蔽“接收成功”、“发送成功”等内部中断,同时不断查询这些中断状态位的情况,发现需要处理的内部中断时做以相应处理,当中断工作模式回复后,相应要重新恢复刚才屏蔽掉的“接收成功”、“发送成功”等内部中断。

当网络适配器进入轮询状态时,软件中断NET_RX_SOFTIRQ的处理例程net_rx_action()最终将调用dev_queue_xmit()发送函数, dev_queue_xmit()的调用流程是: dev_queue_xmit()-->qdisc_run()-->qdisc_restart(),调用方法qbisc_restart()以启动网络设备数据包的传输,而此时它有可能在设备发送队列繁忙时引发网络发送中断:

在数据包放入队列之后,调用qdisc_run()来发送数据包:

static inline void qdisc_run(structnet_device* dev)

{

 while (! netif_queue_stopped(dev) &&

    qdisc_restart(dev)<0)

  /* NOTHING* /;

}

qdisc_restart()函数中,首先调用函数pfifo_fast_dequeue()从队列中取出一个数据包,然后调用网络适配器驱动的发送函数dev->hard_start_xmit()发送数据包,如果发送失败,则需要将这个数据包重新压入队列pfifo_fast_requeue,然后启动协议栈的发送软中断进行再次的发送,从而引发软处理中断。

为了保证轮询工作正常进行,需要做以修改。linux-2. 6. 14. 1qdisc( )函数部分源码如下。

int qdisc_restart(structnet_device* dev)

{

 structQdisc* q = dev->qdisc;

 struct sk_buff* skb;

requeue:

  q->ops->requeue(skb, q);

  netif_schedule(dev);

  return 1;

 }

 BUG_ON(( int) q->q. qlen < 0);

 return q->q. qlen;

}

以下是修改后的函数部分代码:

int qdisc_restart(structnet_device* dev)

{

    If(! config_polling_on)

  netif_schedule(dev);

}

其中config_polling_on指示当前是否是轮询工作模式,/proc下保留了设置它的接口,方便动态地设置。

修改后,当打开轮询内核设置后, qdisc_restart()就不再进行网络层的发送软中断调度,从而保证了轮询正常进行。

3 总结

综上所述,通过编写简单的控制程序,Linux内核相应报文处理函数做以修改,就可以使报文处理流程处于中断和轮询相互切换的工作模式,大大提高了系统的处理能力。

深圳市中电网络技术有限公司 Copyright© www.52solution.com 粤ICP备10202284号