linux內(nèi)核包轉(zhuǎn)發(fā)過程--NIC幀接收分析
每一個(gè)cpu都有隊(duì)列來處理接收到的幀。都有其數(shù)據(jù)結(jié)構(gòu)來處理入口和出口流量,因此。不同cpu之間沒有必要使用上鎖機(jī)制。。
此隊(duì)列數(shù)據(jù)結(jié)構(gòu)為softnet_data(定義在include/linux/netdevice.h中):
非NAPI設(shè)備驅(qū)動會為其所接收的每個(gè)幀產(chǎn)生一個(gè)中斷事件,在高流量負(fù)載下,會花掉大量時(shí)間處理中斷事件,造成資源浪費(fèi)。
而NAPI驅(qū)動混合了中斷事件和輪詢。在高流量負(fù)載下其性能會比舊方法要好。 NAPI主要思想是混合使用中斷事件和輪詢。而不是只使用中斷事件驅(qū)動模型。當(dāng)收到新的幀時(shí)。關(guān)中斷。再一次處理全然部入口隊(duì)列。
從內(nèi)核觀點(diǎn)來看。NAPI方法由于中斷事件少了。降低了cpu負(fù)載。
【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個(gè)人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦!?。。ê曨l教程、電子書、實(shí)戰(zhàn)項(xiàng)目及代碼)? ?


使用非NAPI的驅(qū)動程序的xx_rx()函數(shù)一般例如以下:
第一步是分配一個(gè)緩存區(qū)來保存報(bào)文。
注意緩存分配函數(shù) (dev_alloc_skb) 須要知道數(shù)據(jù)長度。
第二步將報(bào)文數(shù)據(jù)被復(fù)制到緩存區(qū); skb_put 函數(shù)更新緩存中的數(shù)據(jù)末尾指針并返回指向新建空間的指針。
第三步提取協(xié)議標(biāo)識及獲取其它信息。
最后調(diào)用netif_rx(skb)做進(jìn)一步處理。該函數(shù)一般定義在net/core/dev.c中。
至此中斷的上半部完畢,其它的工作交由下半部來實(shí)現(xiàn)。napi_schedule(&queue->backlog)函數(shù)將有等待的接收數(shù)據(jù)包的NIC鏈入softnet_data的poll_list隊(duì)列。然后觸發(fā)軟中斷,讓下半部去完畢數(shù)據(jù)的處理工作。 而是用NAPI設(shè)備的接受數(shù)據(jù)時(shí)直接觸發(fā)軟中斷,不須要通過netif_rx()函數(shù)設(shè)置好接收隊(duì)列再觸發(fā)軟中斷。
比方e100硬中斷處理函數(shù)為:
在前面我們已經(jīng)知道在net_dev_init()函數(shù)中注冊了收報(bào)軟中斷函數(shù)net_rx_action(),當(dāng)軟中斷被觸發(fā)之后。該函數(shù)將被調(diào)用。
net_rx_action()函數(shù)為:
對NAPI設(shè)備來的說,驅(qū)動程序必須提供一個(gè)poll方法,poll 方法有以下原型: int (*poll)(struct napi_struct *dev, int *budget); 在初始化時(shí)須要加入該方法: netif_napi_add(netdev, &nic->napi, xx_poll, XX_NAPI_WEIGHT);
NAPI驅(qū)動 的 poll 方法實(shí)現(xiàn)一般例如以下(借用《Linux設(shè)備驅(qū)動程序》中代碼,內(nèi)核有點(diǎn)沒對上,懶得去寫了):
NAPI驅(qū)動提供自己的poll函數(shù)和私有隊(duì)列。 無論是非NAPI或NAPI,他們的poll函數(shù)最后都會調(diào)用netif_receive_skb(skb)來處理接收到的幀。
該函數(shù)會想各個(gè)已注冊的協(xié)議例程發(fā)送一個(gè)skb。之后數(shù)據(jù)進(jìn)入Linux內(nèi)核協(xié)議棧處理。
