RPSの挙動、キュー周りをもう一度確認
NICのドライバはパケットを受信してnetif_receive_skbかnapi_gro_receiveを呼ぶ。
napi_gro_receiveの場合はGRO処理をパケットに施した後に結合済みパケットをnetif_receive_skbを呼ぶ。
netif_receive_skbでenqueue_to_backlogをコール。
ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail);
enqueue_to_backlogではsoftnet_dataのinput_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_initでinput_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);