linux kernel 工程师
全部博文(99)
分类: LINUX
2014-02-10 15:51:12
网络接收软中断的注册
static int __init net_dev_init(void)
{
....
open_softirq(NET_RX_SOFTIRQ, net_rx_action);
}
网络接收软中断的处理思路是,轮询softnet_data的poll_list, 然后执行其上napi节点的poll函数。
static void net_rx_action(struct softirq_action *h)
{
struct softnet_data *sd = &__get_cpu_var(softnet_data);
unsigned long time_limit = jiffies + 2;
int budget = netdev_budget;
//netdev_budget。该值默认为300,但是可以在/proc/sys/net/core/netdev_budget中设置, echo或sysctl
//netdev_budget 用来控制本次sotirq执行的时间
//napi_struct->weight用来控制对一个设备的poll时间,保持多设备之间的平衡
void *have;
local_irq_disable();
while (!list_empty(&sd->poll_list)) { //list_empty可以在关闭中断情况下执行
struct napi_struct *n;
int work, weight;
/* If softirq window is exhuasted then punt.
* Allow this to run for 2 jiffies since which will allow
* an average latency of 1.5/HZ.
*/
if (unlikely(budget <= 0 || time_after(jiffies, time_limit))) //budget用完或超时,结束本次softirq,防止softirq执行超级长的时间
goto softnet_break;
local_irq_enable();
/* Even though interrupts have been re-enabled, this
* access is safe because interrupts can only add new
* entries to the tail of this list, and only ->poll()
* calls can remove this head entry from the list.
*/
n = list_first_entry(&sd->poll_list, struct napi_struct, poll_list); //list_first_entry可以在中断打开情况下执行
have = netpoll_poll_lock(n);
weight = n->weight;
/* This NAPI_STATE_SCHED test is for avoiding a race
* with netpoll's poll_napi(). Only the entity which
* obtains the lock and sees NAPI_STATE_SCHED set will
* actually make the ->poll() call. Therefore we avoid
* accidentally calling ->poll() when NAPI is not scheduled.
*/
work = 0;
if (test_bit(NAPI_STATE_SCHED, &n->state)) {
trace_net_napi_poll(n);
work = n->poll(n, weight); /* 调用napi的poll函数 */
trace_napi_poll(n);
}
WARN_ON_ONCE(work > weight); //work 必须满足 <= weight
budget -= work; //轮询完一个设备,更新budget
local_irq_disable();
/* Drivers must not modify the NAPI state if they
* consume the entire weight. In such cases this code
* still "owns" the NAPI instance and therefore can
* move the instance around on the list at-will.
*/
//如果一次就把weight消耗光了,说明可能还需要继续轮询这个设备,所以把这个napi放到poll_list的末尾
if (unlikely(work == weight)) {
if (unlikely(napi_disable_pending(n))) {
local_irq_enable();
napi_complete(n);
local_irq_disable();
} else
list_move_tail(&n->poll_list, &sd->poll_list);
}
netpoll_poll_unlock(have);
}
out:
net_rps_action_and_irq_enable(sd);
#ifdef CONFIG_NET_DMA
/*
* There may not be any more sk_buffs coming right now, so push
* any pending DMA copies to hardware
*/
dma_issue_pending_all();
#endif
return;
softnet_break:
sd->time_squeeze++;
__raise_softirq_irqoff(NET_RX_SOFTIRQ); /* 如果budget用完或者超时,跳转到这里,等待下次softirq的执行 */
goto out;
}
一个问题是,如果设备一次收到报文为100个,而weight只有64,softirq一次不能这100包处理完,等待下次进入do_irq来处理剩下的36包。这时如果网口没有包了或网口中断被禁止了,那谁来触发do_irq,进而会执行softirq呢?
难道要靠jiffies时钟中断吗?