網絡子係統19_積壓設備
// 1.積壓設備的目的:
// napi設備,非napi設備同一處理接口,linux為所有不使用napi的驅動程序,提供了一個虛擬設備,叫做積壓設備。
// 2.與積壓設備有關的數據結構:
// 2.1 每個cpu都有一個積壓設備,保存在softnet_data->backlog_dev
// 2.2 每個cpu都有一個積壓設備的輸入隊列,保存在softnet_data->input_pkt_queue,所有非napi設備的入口skb,均掛載到此隊列。
// 2.3 內核為積壓設備的提供poll函數,process_backlog
// 積壓設備的poll函數
// 調用路徑:net_rx_action->process_backlog
// 參數:
// backlog_dev,積壓設備
// budget,函數此次運行可以處理的skb配額
// 返回值:
// <0 , 表明設備還有待處理的入口幀,此時設備仍然在poll_list中,且設備處於關中斷狀態
// =0 , 表明設備已經處理完所有的入口幀,此時設備已經從poll_list中刪除,可接收重新調度,設備中斷已開啟
// 函數主要任務:
// 1.函數運行不能超過1個jiffies,處理的skb不能超過配額
// 2.在關中斷的情況下,從softnet->input_pkt_queue取下入口skb,後開中斷
// 2.1 如果有入口skb
// 2.1.1 通過netif_receive_skb向上層協議傳遞skb
// 2.1.2 遞減入口設備的引用計數
// 2.2 如果在運行時間不足1個jiffies,並且沒有超過配額的情況下,處理完了入口隊列的所有skb
// 2.2.1 更新設備的可用配額
// 2.2.2 由於已經沒有入口數據,因此將擠壓設備從調度隊列poll_list上取下來
// 2.2.3 清除積壓設備的調度標誌,表示設備可以接收下一次調度
// 2.2.4 如果之前入口隊列滿,被設置了throttle,則在入口隊列為空時,清除throttle
// 注:在入口隊列滿,設置了throttle,之後的入口數據都會被丟棄,直到入口隊列為空,清除throttle之後,才開始重新接收入口數據。
1.1 static int process_backlog(struct net_device *backlog_dev, int *budget)
{
int work = 0;
//此次調用可以處理的skb為 設備剩餘配額,傳入的配置中的較小者
int quota = min(backlog_dev->quota, *budget);
struct softnet_data *queue = &__get_cpu_var(softnet_data);
unsigned long start_time = jiffies;
for (;;) {
struct sk_buff *skb;
struct net_device *dev;
//關閉本cpu中斷,因為input_pkt_queue可能會在中斷中被修改
local_irq_disable();
//從input_pkt_queue上退出一個skb
skb = __skb_dequeue(&queue->input_pkt_queue);
if (!skb)
goto job_done;
//開中斷
local_irq_enable();
dev = skb->dev;
//將skb向上傳遞
netif_receive_skb(skb);
//遞減接收此skb的dev的引用計數
dev_put(dev);
//消費流量個數-1
work++;
//此函數運行時間應該 < 1 jiffies
if (work >= quota || jiffies - start_time > 1)
break;
}
//將設備的配額減去實際消費的流量個數
backlog_dev->quota -= work;
//將打算讓設備消費的流量個數中減去實際消費的流量個數
*budget -= work;
return -1;
//表示接收隊列為空
job_done:
backlog_dev->quota -= work;
*budget -= work;
//將積壓設備從poll_list上刪除
list_del(&backlog_dev->poll_list);
smp_mb__before_clear_bit();
//清除積壓設備__LINK_STATE_RX_SCHED標識,表示積壓設備重新可以接收調度
netif_poll_enable(backlog_dev);
//如果此cpu的輸入隊列已經關閉,開啟輸入隊列
if (queue->throttle)
queue->throttle = 0;
//開本cpu中斷
local_irq_enable();
return 0;
}
// 對積壓設備的調度
// 調用路徑 : 非napi設備的接收中斷->netif_rx
2.1 int netif_rx(struct sk_buff *skb)
{
...
netif_rx_schedule(&queue->backlog_dev);
...
}
最後更新:2017-04-03 15:22:09