open_softirq建立类型与handler的对应关系。
void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)
{
softirq_vec[nr].data = data;
softirq_vec[nr].action = action;
}
netif_rx将收到的包放到softnet_data的input_pkt_queue中,之后调用netif_rx_schedule(&queue->backlog_dev)将设备加入poll_list队列。netif_rx_schedule中调用设置软中断对应标志位。
do_irq中断处理结束处,调用irq_exit(),其中判断当cpu没有处理中断,并且存在要执行的bh时(检查之前设置的标记),调用invoke_softirq。invoke_softirq就是do_softirq。do_softirq检查存在挂起的软中断,则调用__do_softirq。其中调用open_softirq中注册的action函数处理,在处理过程中可以有新的软中断被设置,这些软中断也会被处理,直到处理完或者超过规定的次数,如果超过了次数而还有未处理的软中断,则会启动ksoftirqd进程处理剩余的软中断。
接收数据的软中断处理函数为net_rx_action(),回调用poll_list队列中注册的poll函数,对于收包来说是process_backlog(在net_dev_init中注册)。
queue->backlog_dev.poll = process_backlog;
process_backlog从queue->input_pkt_queue中取出skb并调用netif_receive_skb(skb)。
存在两个链表
static struct list_head ptype_base[16]; /* 16 way hashed list */
static struct list_head ptype_all; /* Taps */
协议调用dev_add_pack时会将packet_type加入相应队列。在netif_receive_skb中会遍历这两个队列,调用deliver_skb。deliver_skb()调用packet_type中指定的函数通知相应协议处理skb。对于ip4,这个函数就是ip_rcv。
对于NAPI,不使用softnet_data中的input_pkt_queue,而是使用设备维护的私有队列。netrx_if也是针对非NAPI。NAPI方式中poll_list是设备链表,poll函数由各设备提供。对于非NAPI,poll_list中只有一个设备,就是softnet_data中的backlog_dev,也被称为伪设备,它的poll函数是process_backlog。l