linux内核数据包转发流程(二)中断
【版权声明:转载请保留出处:blog.csdn.net/gentleliu。邮箱:shallnew*163.com】
内核在处理2层数据包之前,必须先处理中断系统,设立中断系统,才有可能每秒处理成千的帧。
当收到一个帧时,驱动程序会代表内核指示设备产生一个硬件中断,内核将中断其他的活动,然后调用一个驱动程序所注册的处理函数,以满足设备的需要。当事件是接收到一个帧时,处理函数就会把该帧排入队列某处,然后通知内核。使用轮询技术会轻易浪费掉很多系统资源,因为内核会持续去读取检查是否有有帧的到来。但使用中断会在每接收到一帧时都强制产生中断,会让cpu处理中断浪费许多时间,在高流量负载下,中断代码会持续抢占正在处理的代码,到某一时刻,输入队列会满,导致旧的帧没办法处理,新的帧又无法排入队列,出现receive-livelock。
中断优点就是帧的接受及其处理之间延时很短,缺点就是在高负载下无法良好运行。
当cpu接收一个中断通知信息时,会调用与该中断事件关联的处理函数,这种关联性有编号表示。在该处理函数执行期间,内核处于中断上下文(interrupt context)中,服务于该中断事件的cpu会被关闭中断功能,即此时不能服务其他中断事件,也不能执行其它进程,cpu完全属于该中断处理函数,不能被抢占。简而言之,中断处理函数是非抢占的,且非可再进入的(reentrant)。这可以降低竞争情况的可能性,但是这对性能有潜在的严重影响。
因此,中断处理函数所做工作应该尽快完成, 中断事件可以先对cpu抢占,这是因为如果操作系统让硬件等太久,可能会遗失数据,另一方面,如果内核或用户空间进程必须被延迟或被抢占,则没有数据会遗失。所以,现在中断处理函数分为上半部和下半部。一般(1)任务对时间敏感或(2)和任务相关或(3)需要保证不被其他中断打断放在上半部执行,可以推迟不太紧急的任务放在下半部执行。下半部分为主要分为软中断,tasklet,工作队列。
下半部的基础架构为:1、把下半部分类成适当类型。2、注册下半部类型及其处理函数间的关联关系。3、为下半部函数调度,以准备执行。4、通知内核有已调度的BH存在。
内核(linux-2.6.32)下半部类型有:(定义在include/linux/interrupt.h)
enum { HI_SOFTIRQ=0, TIMER_SOFTIRQ, NET_TX_SOFTIRQ, NET_RX_SOFTIRQ, BLOCK_SOFTIRQ, BLOCK_IOPOLL_SOFTIRQ, TASKLET_SOFTIRQ, SCHED_SOFTIRQ, HRTIMER_SOFTIRQ, RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */ NR_SOFTIRQS };
软IRQ一般会在相关联的子系统内注册。
内核初始化期间,softirq_init会注册TASKLET_SOFTIRQ以及HI_SOFTIRQ相关联的处理函数。
void __init softirq_init(void) { ...... open_softirq(TASKLET_SOFTIRQ, tasklet_action); open_softirq(HI_SOFTIRQ, tasklet_hi_action); }网络子系统分两种soft IRQ。NET_TX_SOFTIRQ和NET_RX_SOFTIRQ,分别处理发送数据包和接收数据包。这两个soft IRQ在net_dev_init函数(net/core/dev.c)中注册:
open_softirq(NET_TX_SOFTIRQ, net_tx_action); open_softirq(NET_RX_SOFTIRQ, net_rx_action);收发数据包的软中断处理函数被注册为net_rx_action和net_tx_action。
其中open_softirq实现为:
void open_softirq(int nr, void (*action)(struct softirq_action *)) { softirq_vec[nr].action = action; }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。