Kernel Source片段 -- 收包(2)软中断处理函数

kernel version:2.6.32.61


系统有资源处理软中断时,会查看软中断向量表,调用对应的handler。
网络收包时软中断处理函数是net_rx_action。是在net_dev_init中初始化的:
net/core/dev.c

5654 static int __init net_dev_init(void)
5655 {
...
5708         open_softirq(NET_TX_SOFTIRQ, net_tx_action);
5709         open_softirq(NET_RX_SOFTIRQ, net_rx_action);
...
5717 }

软中断处理函数,主要动作是轮询poll_list,然后调用poll处理。如果这个设备所有包都处理完后就将其从poll_list中移除。
这里分为两种情况,
1) 设备驱动支持NAPI
2) 设备驱动不支持NAPI
对于支持NAPI的驱动,在poll_list中的poll函数是需要设备自己实现的,设备拥有自己的队列,不需要共享CPU队列,因此不需要关闭中断。
对于不支持NAPI的驱动,poll函数就是process_backlog,设备需要共享CPU队列,而在软中断处理时是可以被中断打断的,因此对于CPU队列操作时需要关闭中断。


以下是net_rx_action的代码:
net/core/dev.c

2834 static void net_rx_action(struct softirq_action *h)
2835 {
2836         struct list_head *list = &__get_cpu_var(softnet_data).poll_list;
2837         unsigned long time_limit = jiffies + 2;
2838         int budget = netdev_budget;
2839         void *have;
2840 
2841         local_irq_disable();
2842 
// 遍历poll_list
2843         while (!list_empty(list)) {
2844                 struct napi_struct *n;
2845                 int work, weight;
2846 
2847                 /* If softirq window is exhuasted then punt.
2848                  * Allow this to run for 2 jiffies since which will allow
2849                  * an average latency of 1.5/HZ.
2850                  */
// CPU时间用完或者budget用完就要释放CPU
2851                 if (unlikely(budget <= 0 || time_after_eq(jiffies, time_limit)))
2852                         goto softnet_break;
2853 
2854                 local_irq_enable();
2855 
2856                 /* Even though interrupts have been re-enabled, this
2857                  * access is safe because interrupts can only add new
2858                  * entries to the tail of this list, and only ->poll()
2859                  * calls can remove this head entry from the list.
2860                  */
2861                 n = list_entry(list->next, struct napi_struct, poll_list);
2862 
2863                 have = netpoll_poll_lock(n);
2864 
2865                 weight = n->weight;
2866 
2867                 /* This NAPI_STATE_SCHED test is for avoiding a race
2868                  * with netpoll's poll_napi().  Only the entity which
2869                  * obtains the lock and sees NAPI_STATE_SCHED set will
2870                  * actually make the ->poll() call.  Therefore we avoid
2871                 work = 0;
2872                 if (test_bit(NAPI_STATE_SCHED, &n->state)) {
// 调用poll函数处理
2873                         work = n->poll(n, weight);
2874                         trace_napi_poll(n);
2875                 }
2876 
2877                 WARN_ON_ONCE(work > weight);
2878 
2879                 budget -= work;
2880 
2881                 local_irq_disable();
2882 
2883                 /* Drivers must not modify the NAPI state if they
2884                  * consume the entire weight.  In such cases this code
2885                  * still "owns" the NAPI instance and therefore can
2886                  * move the instance around on the list at-will.
2887                  */
2888                 if (unlikely(work == weight)) {
2889                         if (unlikely(napi_disable_pending(n))) {
2890                                 local_irq_enable();
2891                                 napi_complete(n);
2892                                 local_irq_disable();
2893                         } else
2894                                 list_move_tail(&n->poll_list, list);
2895                 }
2896 
2897                 netpoll_poll_unlock(have);
2898         }
2899 out:
2900         local_irq_enable();
2901 
2902 #ifdef CONFIG_NET_DMA
2903         /*
2904          * There may not be any more sk_buffs coming right now, so push
2905          * any pending DMA copies to hardware
2906          */
2907         dma_issue_pending_all();
2908 #endif
2909 
2910         return;
2911 
2912 softnet_break:
2913         __get_cpu_var(netdev_rx_stat).time_squeeze++;
2914         __raise_softirq_irqoff(NET_RX_SOFTIRQ);
2915         goto out;
2916 }


你可能感兴趣的:(kernel,软中断,收包)