網絡子係統21_傳輸接收軟中斷的觸發
//參考 深入理解linux網絡技術內幕
//設備接收數據的調度 //在由驅動程序提供的數據接收中斷中: // 1.非napi設備使用netif_rx向上傳遞skb // 2.napi設備使用netif_rx_schedule //設備發送數據的調度 // 調度隻針對具有隊列規則的設備,在qdisc_run中如果無法獲得xmit_lock鎖,則通過規則隊列重新入隊skb,在net_tx_action中,獲取queue_lock失敗,調度設備 // 對於不使用隊列規則的設備,直接通過dev_queue_xmit調用驅動的hard_start_xmit完成傳輸 //調度發生的路徑 // dev_queue_xmit->qdisc_run->netif_schedule // net_tx_action->netif_schedule
//調度設備發送數據,將設備鏈接到per-cpu的softnet_data->output_queue中,觸發軟中斷 1.1 static inline void netif_schedule(struct net_device *dev) { //如果設備沒有關閉傳輸 if (!test_bit(__LINK_STATE_XOFF, &dev->state)) //執行實際的調度設備操作 __netif_schedule(dev); } //netif_schedule->__netif_schedule 1.2 static inline void __netif_schedule(struct net_device *dev) { //設備沒有被調度 if (!test_and_set_bit(__LINK_STATE_SCHED, &dev->state)) { unsigned long flags; struct softnet_data *sd; //關本cpu中斷 local_irq_save(flags); sd = &__get_cpu_var(softnet_data); //將設備掛在到softnet_data的output_queue上 dev->next_sched = sd->output_queue; sd->output_queue = dev; //觸發傳輸軟中斷 raise_softirq_irqoff(NET_TX_SOFTIRQ); local_irq_restore(flags); } }
//napi、非napi接收數據時的調度區別

//非napi設備接收中斷中使用,將skb向上傳輸
2.1 int netif_rx(struct sk_buff *skb)
{
int this_cpu;
struct softnet_data *queue;
unsigned long flags;
//處理netpoll
if (skb->dev->netpoll_rx && netpoll_rx(skb)) {
kfree_skb(skb);
return NET_RX_DROP;
}
//更新數據接收到的時間戳
if (!skb->stamp.tv_sec)
net_timestamp(&skb->stamp);
//關中斷
local_irq_save(flags);
this_cpu = smp_processor_id();
queue = &__get_cpu_var(softnet_data);//獲取當前cpu的softnet_data
__get_cpu_var(netdev_rx_stat).total++;//增加收到數據包的統計變量
if (queue->input_pkt_queue.qlen <= netdev_max_backlog) {//接收隊列有空閑空間
if (queue->input_pkt_queue.qlen) {
if (queue->throttle)//隊列處於擁塞狀態
goto drop;
enqueue:
dev_hold(skb->dev);
__skb_queue_tail(&queue->input_pkt_queue, skb);//掛載skb到非NAPI設備專用的輸入隊列
local_irq_restore(flags);//開中斷
return queue->cng_level;//返回擁塞等級
}
if (queue->throttle)//輸入隊列中沒有skb,但是上次被標記為擁塞
queue->throttle = 0;//重新開啟數據接收
netif_rx_schedule(&queue->backlog_dev);//運行到此處,說明輸入隊列中的skb個數為0,調度積壓設備,入列skb
goto enqueue;
}
//當發生擁塞時,會暫停數據的接收,直到input_pkt_queue為空之後,才重新開啟數據的接收
if (!queue->throttle) {
queue->throttle = 1;
__get_cpu_var(netdev_rx_stat).throttled++;
}
drop:
__get_cpu_var(netdev_rx_stat).dropped++;
local_irq_restore(flags);
kfree_skb(skb);
return NET_RX_DROP;
}
//napi設備接收中斷中使用,鏈接設備到softnet->poll_list上
3.1 static inline void netif_rx_schedule(struct net_device *dev)
{
if (netif_rx_schedule_prep(dev))//檢測設備是否已經被調度
__netif_rx_schedule(dev);//調度設備
}
3.2 static inline void __netif_rx_schedule(struct net_device *dev)
{
unsigned long flags;
local_irq_save(flags);
dev_hold(dev);
list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);//將設備鏈接到softnet_data->poll_list上
if (dev->quota < 0)
dev->quota += dev->weight;//分配設備此次調度的配置
else
dev->quota = dev->weight;
__raise_softirq_irqoff(NET_RX_SOFTIRQ);//觸發軟中斷
local_irq_restore(flags);
}
最後更新:2017-04-03 15:22:11