linux舊的收包方式提供給驅動的接口netif_rx()
int netif_rx(struct sk_buff *skb)
{
struct softnet_data *queue;
unsigned long flags;
/*如果接收skb的時間戳沒設定,設定接收時間戳*/
if (!skb->tstamp.tv64)
{
net_timestamp(skb);
}
/*禁止本地cpu的中斷*/
local_irq_save(flags);
/*取得本地cpu的softnet_data*/
queue = &__get_cpu_var(softnet_data);
/*每個CPU都有一個統計數據,增加統計數據*/
__get_cpu_var(netdev_rx_stat).total++;
/*如果本地CPU的輸入隊列中的skb 個數小於允許的最多的個數*/
if (queue->input_pkt_queue.qlen <= netdev_max_backlog)
{
/*如果本地cpu的輸入隊列長度不爲0,表示輸入隊列已經有skb了,
並且特殊的napi backlog 已經掛入了softnet_data 的
pool_list上了*/
if (queue->input_pkt_queue.qlen)
{
enqueue:
/*把skb 放入CPU的輸入隊列 input_pkt_queue*/
__skb_queue_tail(&queue->input_pkt_queue, skb);
/*使能中斷 並 返回*/
local_irq_restore(flags);
return NET_RX_SUCCESS;
}
/*如果輸入隊列爲空,則把 特殊的napi backlog 掛到softnet_data
的 pool_list 上 並返回把skb放入輸入隊列並返回*/
napi_schedule(&queue->backlog);
goto enqueue;
}
/*如果本地cpu的輸入隊列已經滿了,則丟棄報文,
並增加丟包計數並返回*/
__get_cpu_var(netdev_rx_stat).dropped++;
local_irq_restore(flags);
kfree_skb(skb);
return NET_RX_DROP;
}
上篇博文裏我們已經分析過,Linux網絡子系統中管理的收包隊列由一個虛擬的NAPI backlog來進行處理。
驅動調用netif_rx把報文放入隊列,把虛擬的NAPI backlog加入到pool鏈表上,調度收包軟中斷。收包軟中斷會調用backlog的輪詢
函數對隊列中的報文進行處理。
該虛擬的NAPI backlog的輪詢函數在函數net_dev_init中被初始化爲process_backlog
我們看一下NAPI backlog的輪詢函數process_backlog的實現
參數:
napi : 本地cpu上softnet_data 的backlog .
quota : 一次輪詢可以處理的最多報文數。
函數詳解:
static int process_backlog(struct napi_struct *napi, int quota)
{
int work = 0;
/*取得本地CPU上的softnet_data 數據*/
struct softnet_data *queue = &__get_cpu_var(softnet_data);
/*開始計時,一旦允許時間到,就退出輪詢*/
unsigned long start_time = jiffies;
napi->weight = weight_p;
/*循環從softnet_data 的輸入隊列取報文並處理,直到隊列中沒有報文了,
或處理的報文數大於了允許的上限值了,
或輪詢函數執行時間大於一個jiffies 了
*/
do
{
struct sk_buff *skb;
/*禁用本地中斷,要存隊列中取skb,防止搶佔*/
local_irq_disable();
/*從softnet_data 的輸入隊列中取得一個skb*/
skb = __skb_dequeue(&queue->input_pkt_queue);
/*如果隊列中沒有skb,則使能中斷並退出輪詢*/
if (!skb)
{
/*把napi 從 softnet_data 的 pool_list 鏈表上摘除*/
__napi_complete(napi);
/*使能本地CPU的中斷*/
local_irq_enable();
break;
}
/*skb 已經摘下來了,使能中斷*/
local_irq_enable();
/*把skb送到協議棧相關協議模塊進行處理,詳細處理見後續章節*/
netif_receive_skb(skb);
} while (++work < quota && jiffies == start_time);
/*返回處理報文個數*/
return work;
}
Linux網絡子系統中舊的報文接收接口netif_rx
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.