/* 查看队列中的 skb 数量是否达到上限 */
if (queue->input_pkt_queue.qlen <= netdev_max_backlog) {
if (queue->input_pkt_queue.qlen) {
/* 如果队列中已经有 skb */
enqueue:
__skb_queue_tail(&queue->input_pkt_queue, skb);
return NET_RX_SUCCESS;
}
napi_schedule(&queue->backlog);
goto enqueue;
}
/* 队列中的 skb 已经达到上限, 直接丢弃 */
kfree_skb(skb);
return NET_RX_DROP;
}
至此网卡的硬件中断全部结束, 进入到软中断收包过程。 查看 napi_schedule,
napi_schedule 直 接 调 用 __napi_schedule 将 当 前 CPU 下 softnet_data.backlog 插 入 到
softnet_data.poll_list 下(比较奇怪), 并触发软中断 NET_RX_SOFTIRQ:
static inline void napi_schedule(struct napi_struct *n)
{
__napi_schedule(n);
}
void __napi_schedule(struct napi_struct *n)
{
list_add_tail(&n->poll_list, &__get_cpu_var(softnet_data).poll_list);
__raise_softirq_irqoff(NET_RX_SOFTIRQ);
}
软中断 NET_RX_SOFTIRQ 的处理函数在系统启动期间通过 net_dev_init 注册:
static int __init net_dev_init(void)
{
open_softirq(NET_TX_SOFTIRQ, net_tx_action);
open_softirq(NET_RX_SOFTIRQ, net_rx_action);
}
即网卡硬件中断结束后由 net_rx_action 继续网络协议栈的处理, net_rx_action 通过在
一个大循环中调用 n->poll 来接收 skb, 并在大循环中通过 budget 和 time_limit 来控制软中
断的生命周期:
static void net_rx_action(struct softirq_action *h)
{
while (!list_empty(list)) {
if (unlikely(budget <= 0 || time_after(jiffies, time_limit))) {
/* 如果接收到一定数量的包或超时 */
评论2
最新资源