RPSの挙動、キュー周りをもう一度確認

NICのドライバはパケットを受信してnetif_receive_skbnapi_gro_receiveを呼ぶ。

napi_gro_receiveの場合はGRO処理をパケットに施した後に結合済みパケットをnetif_receive_skbを呼ぶ。

netif_receive_skbenqueue_to_backlogをコール。

ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail);

enqueue_to_backlogではsoftnet_datainput_pkt_queueへキューしてsoftnet_dataに対して____napi_schedule

__skb_queue_tail(&sd->input_pkt_queue, skb);
____napi_schedule(sd, &sd->backlog);

このnapiに関連付けられているポーリング関数はprocess_backlog

sd->backlog.poll = process_backlog;

process_queueにパケットがあるならデキューして__netif_receive_skbプロトコルスタックを呼び出して処理するようになっているが、この時点ではprocess_queueにキューしていないので処理が行われない。

その後、もしinput_pkt_queueにパケットがあるなら、skb_queue_splice_tail_initinput_pkt_queueの上のキューをprocess_queueへ移動、もう一回ループで戻ってきて今度はprocess_queueにパケットが移動されてるからプロトコルスタックで処理される。

while (work < quota) {
        struct sk_buff *skb;
        unsigned int qlen;

        while ((skb = __skb_dequeue(&sd->process_queue))) {
                local_irq_enable();
                __netif_receive_skb(skb);
                local_irq_disable();
                input_queue_head_incr(sd);
                if (++work >= quota) {
                        local_irq_enable();
                        return work;
                }
        }

        rps_lock(sd);
        qlen = skb_queue_len(&sd->input_pkt_queue);
        if (qlen)
                skb_queue_splice_tail_init(&sd->input_pkt_queue,
                                           &sd->process_queue);