Linux網路卡驅動程式分析(NE2000為例)

來源:互聯網
上載者:User
1
Linux網路卡驅動程式 : 追蹤與效能分析
投稿領域:網路軟體
陳一瑋 林盈達
國立交通大學資訊科學系
新竹市大學路1001號
TEL:(03)5712121 EXT. 56667
E-MAIL:iwchen@cis.nctu.edu.tw , ydlin@cis.nctu.edu.tw
主要聯絡人:陳一瑋TEL:0927308032
摘要
一部電腦的網路元件可分成硬體和軟體兩部分,硬體方面有網路卡,網路線等,軟體方面有網
路卡驅動程式( Adapter driver ),協定驅動程式( protocol driver )及應用軟體,其中網路卡驅
動程式負責銜接硬體與軟體,本文解說裝置驅動程式運作的流程,找出撰寫裝置驅動程式的重點與
要領,以 Linux網路卡驅動程式為例說明,並對它做一些測試與分析.分析之後發現到在不考慮網
路傳輸時間(propagation time)的條件下,封包處理上較花時間的順序為: (1) 網路卡發送
(transmit),接受(receive)封包 ,(2) DMA(直接存取記憶體)封包,(3) 網路卡驅動程式(CPU執行
時間),三者所花的時間比例大約為250 : 30 : 1,這是以封包大小1028byte來測試的結果,封包
愈大三者的比例會愈懸殊,可見發送(或接收)及DMA封包是時間瓶頸所在;除此之外,也瞭解在
中斷處理時"新封包來到"的情形比"封包傳送完畢"要花多一點時間.
關鍵字: Linux,協定驅動程式,網路卡驅動程式,ISR,IRQ,I/O port,DMA.
1. 簡介
2
作業系統的主要功能之一就是控制電腦周邊裝置的輸入,輸出.而用來控制的軟體主要可以分
為四個部分,請參考圖一.我們可以看出驅動程式( Driver )在現今的電腦實作架構中處於一個相
當重要的地位,它要能 "吃軟" 也要能 "吃硬".通常中斷處理常式可以視為是驅動程式的一部
分.
相對於網路卡驅動程式( Adapter driver )而言,它所要吃的 "軟" 就是上層的協定驅動程
式( Protocol driver),也就TCP/IP protocol stack;而它所要吃的 "硬"就是下層的網路卡,
說得更詳細點,便是要和網路卡上的MAC Controller溝通,透過MAC Controller上的registers
來交換訊息,以達到網路卡驅動程式的主要工作之一:將封包傳送給網路卡或者是從網路卡上抓取
已經到達的封包;而另一項主要的工作,是將從網路卡上抓取到的封包傳遞給上層的協定驅動程式,
或者是將從協定驅動程式收到的封包傳遞給網路卡,請參考圖二.
使用者行程
Device-independent軟體
驅動程式
中斷處理常式
硬體
I/O call , spooling
Naming , protection , allocation
Setup device registers , check status
Wakeup driver when I/O completed
Perform I/O operations
I/O 請求 I/O 回覆
圖一:I/O系統中的分層以及各層的主要函式
I/O 函式
核心 網路卡驅動程式 網路卡
出境封包
入境封包
出境封包
入境封包
圖二:網路卡驅動程式的主要工作
3
2. 撰寫驅動程式
如何正確地在 Linux作業系統中撰寫一個驅動程式呢 以下我們將分為探測硬體 (probe
hardware),中斷處理 (interrupt handling),使用I/O埠 (Using I/O ports) 讀取及寫入資料這三
大部分來一一解說.
2.1 探測硬體(probe hardware)
在一個驅動程式可以和裝置做溝通前,必須要做的一些初始化工作包括:探測裝置的I/O
ports和IRQ number.有了I/O ports才可以和裝置上的某些暫存器(register)溝通,有了IRQ
number才能正確地將中斷處理常式註冊到核心之中.探測硬體的方法和匯流排(bus)的種類
有關,PCI介面的裝置是在開機時(boot)就自動會將所用的I/O ports及IRQ number存在其某
些暫存器上,而驅動程式只需去讀取這些暫存器就可以了,並不需要真正的去探測裝置,
但ISA介面的裝置驅動程式就必須要實際地去做探測的工作.
在PCI介面方面, Linux核心2.4版更進一步地將I/O ports及IRQ number整合在系統資
源中 (pci_dev structure),因此在驅動程式中就不必直接由裝置上的暫存器來獲得I/O ports
和IRQ number,而只需呼叫下列函式即可由系統資源取得:
int pci_enable_device (struct pci_dev *dev);
unsigned long pci_resource_start(struct pci_dev *dev, int bar);
struct resource *request_region (unsigned long start , unsigned long len , char*
name);
void release_region (unsigned long start , unsigned long len);
想要取得I/O ports和IRQ number以前,一定要呼叫pci_enable_device( )來啟動
這個PCI裝置,接下來若是要IRQ number,就可從dev->irq中獲得,若是要
I/O ports就呼叫pci_resource_start( ) 來取得基底位址( base address ),然後呼叫
request_region( )向系統宣告要用某一段的I/O ports即可使用,最後若沒有要用
時要記得呼叫release_region( )來釋放這段I/O ports.
至於ISA介面的裝置就麻煩許多,在探測I/O ports方面所用的機制( mechanism )是去
"掃瞄"( scan )所有可能的I/O ports,只有與裝置串連的I/O ports才會有正確的回應,
4
以下是大概的流程:
1. int check_region (unsigned long start , unsigned long len );
這個函式是用來檢查這一段I/O ports是否可以拿來使用.
2. 實際去探測硬體,察看此裝置是否存在,在此必須盡量必免"寫入"的動作,因為不小心
的寫入會讓系統出現很多問題.
3. 呼叫request_region( ) 來向核心要求所要用的I/O ports.
4. 當沒有要用到某段I/O ports時,要呼叫release_region( )來釋放出系統資源.
在探測IRQ number方面所用到的機制是讓裝置產生一個中斷( interrupt ),然
後去查看一些相關資訊以得知裝置所用的IRQ是多少,這裡要注意的是:驅動
程式是要知道裝置所用的IRQ是多少,而不是要分配IRQ給裝置,以下是
可以用到的函式:
unsigned long probe_irq_on(void);
int probe_irq_off (unsigned long);
probe_irq_on( )會回傳一個位元遮罩(bitmask),此遮罩可以用來判斷還有哪些中
斷還沒被用到,而驅動程式必須儲存此遮罩,因為等一下必須將此遮罩當成參
數傳給probe_irq_off( ).在probe_irq_on( )執行完後,驅動程式應該要促使裝置
產生一個中斷,之後再呼叫probe_irq_off( bitmask ),如此一來probe_irq_off( )
就會傳回此裝置所用的IRQ number了.
2.2 中斷處理(interrupt handling)
當資料在核心與裝置間傳輸時難免會有一些的延遲(delay),因此驅動程式就必須將資料
先暫存起來,放到緩衝區中等待資料的完整與正確傳送時刻的到
來,而我們常見的一個較好的緩衝機製為"interrupt-driver I/O",此方法中輸
入緩衝區(input buffer)在中斷處理時被填入資料,再被需要這些資料的程式
(process)所取出; 輸出緩衝區(output buffer)被某個程式填入資料後,在中斷處
5
理時再將資料送給裝置,而所謂中斷處理的部分就是交給中斷處理常式來負
責.通常的情況下,一個驅動程式只會為其裝置向核心註冊一個中斷處理常式,
以下的函式可以用來註冊及登出中斷處理常式:
int request_irq(unsigned int irq, void(*handler) (int, void *, struct pt_regs *) ,
unsigned long flags, const char *dev_name ,void *dev_id);
void free_irq (unsigned int irq, void *dev_id);
request_irq可以用來註冊中斷處理常式,而free_irq則用來登出它.
2.2.1 中斷處理大綱
當有中斷產生時系統其實是 "軟硬兼施" 的,請參考表一.
1. 硬體儲存程式計數器(programm conuter)等
2. 硬體載入新的程式計數器
3. 組語程式儲存暫儲器值
4. 組語程式設定新的堆疊
5. C程式處理實際中斷事務,喚醒行程,可能呼叫
schedule( ),最後跳回到組語程式
6. 組語程式啟動目前該執行的行程
Interrupt service routine(ISR)的整個過程為3 ~ 6,而驅動程式就是實作於第
5項.
2.2.2 "快速"與"慢速"處理常式
在舊版的 Linux核心中花了很大的工夫來區別"快速"和"慢速"中斷,所
謂 "快","慢"的中斷其差別就在於所需的處理時間長短,若一中斷只需很
短的時間就可處理完畢即為快速中斷,相反地,若一中斷需要很長的時間
來完成就是慢速中斷.相對於中斷處理常式而言,在處理中斷時,處理器
是否還會接受其它的中斷回報( interrupt reporting ),會的話則此中斷處置常
表一:中斷處理大綱
6
式就為Slow ( 因為處理器必須兼顧其它中斷 ),反之則為Fast ( 因處理器
完全被此中斷處理常式佔住 ).兩者有一個相同的地方,無論是Fast或是
Slow的中斷處置式,當其在為某個中斷服務期間,此中斷在中斷控制器
( interrupt controller )中是失效( disable )的.在request_irq( )中的flags參數
若被設成SA_INTERRUPT便是代表要註冊一快速中斷處理常式,而在現
代的核心中,快速和慢速中斷已經被視為幾乎是同樣的了,表二為兩者的
比較:
在中斷期間使其
它中斷失效
在中斷期間使目前
服務的中斷失效
服務結束後是否會呼

ret_from_sys_call
快速處置常式 是 是 否
慢速處置常式 否 是 是
2.2.3 撰寫中斷處理常式
在製作中斷處置常式時所必須要考慮到的工作如表四所列.
表四中最後一項所寫
到的後續常式我們將在下一小節中作介紹.
中斷處理常式由於是在中斷期間所執行,因此其執行時受到了許多的限制,
判斷中斷的原因,e.g. 網路卡中斷處理常式要判斷中斷是因封包
的到來,離去或是錯誤的發生.
叫醒在等待中斷完成的事件之行程.
若需要較長的執行時間,則使用後續常式( bottom half )來完成.
表二:快速與慢速中斷處置常式的比較
表四:中斷處置常式所要做的工作
7
例如: 它不能和使用者空間互相傳遞資料,它不能做任何會讓自己進人睡
眠狀態的事情.在實作中斷處理常式過程中我們可以使用的資源即為所傳
入的三個參數,這三個參數分別為int irq,void* dev_id,struct pt_regs* regs.
irq可以用在記錄檔中,dev_id是此裝置的指標,當我們使用共用中斷時(e.g.
兩個中斷處理常式共用一個IRQ number),中斷處理常式可以利用dev_id
辨別某個中斷是否屬於自己要處理的,而最後一個參數regs很少被使用到,
regs會儲存著處理器在進入中斷處理常式前一時刻的內容,因此regs便可
做為監控,除錯之用.
2.2.4 後續處理常式(bottom half)
處理中斷時所面對的主要問題之一,就是如何讓處置常式順利執行較
為耗時的工作而又不會遺漏掉接下來的中斷, Linux對此所提出的解決之
道,就是將中斷處置常式分為兩個部分,一為 "先行常式"( top half ),另
一個部分是 "後續常式"( bottom half ).先行常式就是之前我們提到過,用
request_irq所註冊的處置常式,其負責將後續常式排班到作業系統中,作
業系統等到可以執行的安全時間(所謂安全是指對執行時間的要求不會嚴
苛)便會去執行後續常式. Linux核心中有兩種機制來實作後續常式: BH(
也被稱作bottom half)和tasklets.BH為較舊的方法,在核心2.4後實際上
也是用tasklets來實作,而tasklets是從2.3系列才發展出來的,其為目前
較常被使用的後續常式實作方法,但由於tasklets無法在較舊的核心上使
用,因此若考慮portability的問題話,用BH的方法較為妥當.先來看看
若要以tasklets的方法實作後續常式,有哪些函式可以使用:
DECLARE_TASKLET(name, function, data);
tasklet_schedule(struct tasklet_struct *t);
要如何使用這些函式呢 舉例而言,若你寫了一個函式 func( )要用來作為
後續常式,第一步是要向系統宣告一個tasklet : DECLARE_TASKLET(task,
8
func, 0),task是代表此tasklet的名字,接下來再呼叫tasklet_schedule(&task)
來將此task排班到作業系統中,等到作業系統方便時就會去執行它.而在
BH的方法中,若是想要將一個後續常式排班到系統中,可用下列函式:
void mark_bh(int nr);
其中nr是代表某個bottom-half routine,在舊版的核心中mark_bh( )會在一
個bitmask中設定某位元,讓這位元所對應到的中斷處理常式可以順利地
被執行通常核心都會提供幾個後續常式讓程式設計者使用,表三列出驅動
程式能使用的部分:
然而在新版的核心(2.4)中,mark_bh( )實際上是去呼叫tasklet_hi_schedule( )
(類似tasklet_schedule( ) )來將所要執行的bottom-half routine排班到核心之中.
2.2.5 競爭狀態 (race condition)
由於interrupt-driver I/O的原因,因而引進了某一類的問題: 對於一群行程間若有共
享的資料,該如何解決好幾個行程同時要存取該共用資料的同步問題,而這類問題我們
稱之為競爭狀態 (race condition).由於在在驅動程式的任何一個執行點都有可能會發生
中斷,因此只要是和中斷有互動的驅動程式(大部分都會有)都必須要注意競爭狀態.在
Linux核心裡支援好幾種技術來必避資料的敗壞( data corruption ),而我們將介紹最常使
用的方式: 使用spinlocks來達到行程之間兩兩互斥( mutual exclusion),如此即可避免競
爭狀態的發生,說明白點,就是不論中斷處理常式或驅動程式要存
取共用資料時,要先能拿到( lock )一把鎖,然後才進行共用資料的存取,最後不用時再
把這把鎖歸還( unlock ),讓別的行程能夠也藉由同樣的方法來存取共用資料.
Spinlocks在 Linux中的型別為spinlock_t,而以下是一些可以運作在spinlocks上的函式:
IMMEDIATE_BH TQUEUE_BH TIMER_BH
表三:核心宣告的後續常式
9
void spin_lock(spinlock_t *lock);
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);
void spin_lock_irq(spinlock_t *lock);
void spin_lock_bh(spinlock_t *lock);
void spin_unlock(spinlock_t *lock);
void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);
void spin_unlock_irq(spinlock_t *lock);
void spin_unlock_bh(spinlock_t *lock);
spin_lock( )以busy-wait的方式取得所想要的一把鎖 (lock),等到
spin_lock( )函式返回時,呼叫它的行程便可以獲得此把鎖.
spin_lock_irqsave( )也是以同樣的方法取得一把鎖,除此之外它會使中斷
無效,並且把目前的中斷情況記錄到flags參數中,而spin_lock_irq( )除了
不會將目前中斷的情形記錄下來以外,其餘的動作都spin_lock_irqsave( )一樣,至於
spin_lock_bh( ),它和前三者都是一樣會用busy-wait的方式來取得一把鎖,然而它還
不準後續常式被執行.以上四個函式可以獲得一把鎖,相反地,接下來的四個相對應的
函式會將鎖歸還,spin_unlock( )就只是單純地把之前所獲得的鎖歸還,
spin_unlock_irqrestore( )會把鎖歸還並且根據flags的值來使得一些中斷變有效,
spin_unlock_irq( )除了把鎖歸還,還會把所有的中斷變得有效,而spin_unlock_bh( )會
將鎖歸還,且讓後續常式可以被執行.在使用這些函式時有兩點要特別注意,第一是要

定取得( lock )鎖的函式比歸還( unlock )鎖的函式早出現,第二是要這些函式是兩兩成對
來使用的.
2.3 使用I/O埠讀取及寫入資料
在探測硬體階段之後,驅動程式便可獲得硬體所使用的I/O ports.大部分
的硬體會將I/O ports的寬度分成8位元,16位元,以及32位元,因此驅動程
10
式就必須針對不同寬度的I/O ports來呼叫不同的函式存取I/O ports,在 Linux
核心中定義以下的函式可以用來存取I/O ports.
unsigned inb (unsigned port);
void outb (unsigned char bye, unsigned port);
inb( )讀取寬度8位元的ports,而outb( )寫入寬度8位元的ports.
unsigned inw (unsigned port);
void outw (unsigned char bye, unsigned port);
inw( )讀取寬度16位元的ports,而outw( )寫入寬度16位元的ports.
unsigned inl (unsigned port);
void outl (unsigned char bye, unsigned port);
inl( )讀取寬度32位元的ports,而outl( )寫入寬度32位元的ports.
除了以上單一讀取的方式外, Linux還支援了字串的操作:
void insb (unsigned port, void *addr, unsigned long count);
void outsb (unsigned port, void *addr, unsigned long count);
insb( )從8位元的ports讀取count位元組的資料, 然後將這些資料儲存到記憶
體位址為addr的地方,而outsb( )將記憶體位址為addr的資料,寫入count位
元組到8位元的ports.
void insw (unsigned port, void *addr, unsigned long count);
void outsw (unsigned port, void *addr, unsigned long count);
這兩個函作的運作和以上兩個很類似,除了說它們是針對寬度為16位元的
ports所設計的.
void insl (unsigned port, void *addr, unsigned long count);
void outsl (unsigned port, void *addr, unsigned long count);
這兩個函作的運作和以上兩個很類似,除了說它們是針對寬度為32位元的
ports所設計的.
11
3. Linux網路卡驅動程式執行個體
在眾家網路卡驅動程式中,我們挑選其中相容性最高的NE2000,PCI介面網
路卡的 Linux版驅動程式來進行追蹤,如此更有實際應用的意義.
3.1 重要資料結構(data structure )
Linux系統中,網路卡驅動程式常用到的資料結構有兩種:sk_buff以及
net_device.圖四顯示出這兩種資料結構是位於系統的哪些位置,也就
是有誰會去存取它們.
簡單說明一四:圖中skb是指sk_buff形態的指標變數,dev是指
net_device形態的指標變數.網路卡驅動程式從網路卡上抓取到封包(此時
稱作frame)後,會去配置一塊sk_buff記憶體,將frame塞進skb中的data
欄位,以後封包在系統中就是以sk_buff的形式表現.而net_device中的許
多欄位值都是在網路卡驅動程式裡填好的,圖中local是指dev中的大部分的
欄位值都是在網路卡驅動程式裡產生然後填入net_device欄位的,以後網路
卡在系統中就是以net_device的形式表現,接著就來詳細介紹這兩個資料結
的主要欄位.
核心
skb
dev
網路卡驅動程式
skb frame
dev local
網路卡
圖四:skb_buff及net_device於系統中的位置
12
3.1.1 sk_buff
此資料結構定義在中,表五列出其主要欄位,與欄
位所代表的意義.
3.1.2 net_device
此資料結構定義在中,表六列出其主要欄位,與
欄位所代表的意義.
3.2 初始化
初始化的工作可分為"註冊中斷處理常式"以及"探測硬體",註冊中斷
處理常就是用之前說過的request_irq( )函式來完成,而探測硬體方面由於是
PCI介面的網路卡,因此只需用我們之前所教的方法就可取得I/O ports及IRQ
number,而不用實際地去探測網路卡.
欄位名 意義
Name 裝置名稱
base_addr I/O埠的基底位址
Irq 中斷編號
dev_addr 網路卡硬體位址
Mtu 最大傳輸單位
hard_start_xmit 裝置功能函式之一
欄位名 意義 欄位名 意義
head 指向sk_buff的起點 len 資料本身的長度
data 指向"真正資料"的起點 pkt_type 幫包的類型
tail 指向"真正資料"的終點 saddr 來源位址
end 指向sk_buff的終點 daddr 目的位址
dev 封包到達或離開的裝置 raddr 路由器位址
表五:sk_buff的重要欄位
表六:net_device的重要欄位
13
3.3 封包的發送
圖五顯示出此網路卡驅動程式的封包發送流程,有陰影的部分為驅動程式.
在此以文字簡單解說圖五:核心要傳送封包而呼dev->hard_start_xmit( ),
在此驅動程式中實作出的函式為ei_start_xmit( ),在ei_start_xmit( )中會呼
ne2k_pci_block_output( )將封包搬到網路卡上,接著呼叫
NS8390_trigger_send( )以觸發(trigger)網路卡將封包送出,等到封包送完,
網路卡會以中斷來通知核心,於是核心就去呼叫對應的中斷處理常式,在此驅
動程式中是ei_interrupt( ),ei_interrupt( )會先判斷是屬於哪一種中斷,
發現是封包傳送完所發出的中斷後,它會呼叫ei_tx_intr( )來處理,ei_tx_intr( )
會先呼叫NS8390_trigger_send( )來觸發網路卡上的另一個封包傳送(若有的
話),接著呼叫netif_wake_queue( )讓核心知道封包已傳遞完畢可以進行下一項
工作.
核心
(處置常式)
ei_interrupt
(TX)
ei_start_xmit
(RX)
ei_receive
ei_tx_intr
網路卡
1. dev->hard_start_xmit
2. ne2k_pci_block_output
3. NS8390_trigger_send
4. 中斷產生
5.
6.
7. NS8390_trigger_send
8. netif_wake_queue
圖五:封包發送流程
14
3.4 封包的接收
圖六顯示出此網路卡驅動程式的封包接收流程.
在此以文字簡單解說圖六:當網路卡接收到封包時它會以中斷來通知核心,於
是核心就去呼叫對應的中斷處理常式,在此驅動程式中是ei_interrupt( ),
ei_interrupt( )會先判斷是屬於哪一種中斷,發現是有封包到來因而發出的中
斷後,它會呼叫ei_receive( )來處理,在ei_receive( )中會呼叫
ne2k_pci_block_input( )將封包從網路卡搬到系統記憶體中,然後將封包塞入
sk_buff的結構中並且以netif_rx( )函式將此封包丟往上層處理,而netif_rx( )
所做的事情即是我們之前所討論的後續常式所該做的事.
4. 效能分析
在此我們將會做兩個有趣的效能分析,一個名為"封包的一生",另一個名為"中斷處理的時
間".第一個測試可以讓我們瞭解,一個出境以及入境封包在系統的各個部分所停留的時間,如此
便可知道封包處理(packet processing)將時間花在哪些地方;第二個測試可以讓我們知道,網路
卡驅動程式的不同中斷處理常式所花的時間是完全不同的,而且中斷的類別不同(傳送完畢,接收
到新的封包)也有不同的處理方式,我們可依據這個測試結果來做為判斷網路卡和驅路卡驅動程式
搭配的好壞與否的因素之一,因為網路卡與網路卡驅動程式搭配的愈好,在中斷處理所花的平均時
核心
(處置常式)
ei_interrupt
(TX)
ei_start_xmit
(RX)
ei_receive
ei_tx_intr
網路卡
1. Interrupt occurs
2. 3.
4. ne2k_pci_block_input 5. netif_rx
圖六:封包接受流程
15
間就愈短.
4.1 封包的一生
我們將封包的一生分成三個階段:網路卡階段,DMA階段,以及網路卡驅
動程式階段(不包括DMA部分),會去測量出境及入境封包分別在這三個階段待了多久的時
間.量測的方法是先定出每個階段的起訖點然後再使用rdtscll(定義在)來抓
取時間,表七是我們做此測試所用到的硬體,軟體:
CPU:Celeron 567.007 MHz
網路卡:PCI Realtek 10Mbps乙太網路卡
作業系統核心: Linux kernel 2.2.19
網路卡驅動程式:ne2k-pci
接下來的表八就是這個測試所得到的結果,時間單位為CPU clock cycle數,
而由於我們的CPU速度為567.007MHz,所以一個clock = 1.8 nanosecond.
在網路卡階段,入境封包和出境封包所存在的時間和封包大小成正比,這是因
封包類別 大小(byte) 網路卡階段 DMA階段 網路卡驅動程式階段
ICMP (28 + 1)
ICMP (28 + 100)
ICMP (28 + 1000)
入境 出境
62000 12000
102000 52000
512000 462000
入境及出境
7000
11000
66000
入境 出境
1300 3000
1300 3000
1300 3000
UDP (28 + 1)
UDP (28 + 100)
UDP (28 + 1000)
62000 12000
102000 52000
512000 462000
7000
11000
66000
1300 3000
1300 3000
1300 3000
ARP (28) 62000 12000 7000 1300 3000
表七:測試一之軟,硬體裝置
16
為網路卡在傳送封包到網路上,以及從網路上接收封包所花費的時間是和封包
的大小成正比;而入境封包會比出境封包在網路卡階段待得久的原因是:
入境封包:接收時間 + 組合語言中斷處理時間 + C語言中斷處理時間.
出境封包:傳送時間 + 部份C語言中斷處理時間.
由於入境封包多花了組合語言中斷處理的時間,再加上其C語言中斷處理的部
分較出境封包久,所以入境封包在網路卡上所待的時間較出境封包久.在DMA
階段中,封包所待的時間很明顯的只和封包大小有關,不論是要入境還是要出
境的封包.而封包在網路卡驅動程式階段中所待的時間是最短的,尤其是入境
封包,這是因為當入境封包DMA上網路卡驅動程式後,網路卡驅動程式會立
刻呼中netif_rx將封包交給後續常式來處理.
4.2 中斷處理的時間
在這個測試中,我們找了兩張網路卡及其對應的網路卡驅動程式,測試兩
個驅動程式在中斷處理上所花的時間,當然這也是分成封包傳送完畢以及新封
包來到這兩種類型的中斷,表九是此測試所用到的軟,硬體.
CPU:Celeron 567.007 MHz
網路卡:PCI Realtek RTL-8029 (AS)
10Mbps乙太網路卡
網路卡驅動程式:ne2k-pci
網路卡:PCI Intel GD82559 100Mbps
乙太網路卡
網路卡驅動程式:eepro100
作業系統核心: Linux kernel 2.2.19
表九:測試二之軟,硬體裝置
17
而表十就是這個測試的結果,時間的單位為CPU clock數.
中斷類型
封包大小(byte)
新封包來到
eepro100 ne2k-pci
封包傳送完畢
eepro100 ne2k-pci
28 + 1 8500 29000 6000 8500
28 + 100 8500 34000 6000 8500
28 + 1000 8500 90000 6000 8500
由此結果可看出eepro100與Intel網路卡的組合在中斷處理上所花的平均時
間較ne2k-pci與Realtek 網路卡的組合來得少,所以可以說eepro100與
Intel網路卡的組合較ne2k-pci與Realtek網路卡的組合來得好;另外我們
可發現"新封包到來"所需要的時間比"封包傳送完畢"要來得多,這是因為
處理新封包到來時必須先將封包從網路卡DMA上系統記憶體,之後再塞入
sk_buff中,並且將其往上層傳遞,而處理"封包傳送完畢"時只是在做些統
計工作,例如將傳送的封包數目加一等.
5. 結論
網路卡驅動程式在系統中扮演著重要的角色,由於它必須要與下層網路卡及上層核心溝通,所
以要做的事情就變得很多樣化,很複雜,若想要學習寫網路卡驅動程式最好的方式就是找一個範例
來改寫.在第二節所介紹的方法是很通用的,不只是網路卡驅動程式適用而已,其它裝置驅動程式
的作法也是大同小異.第四節中我們做了兩個很有趣的測試,從這些測試裡面,可以更瞭解封包傳
遞與網路卡驅動程式間的關係,從"封包的一生"測試中可以知道在處理封包時,DMA及發送(或接
收)封包是個時間上的瓶頸,如此一來或許就可以設計某種方式來加快處理封包的速度.
6. 參考文獻
[1] Alessandro Rubini, " Linux Device Drivers", first edition, O'Reilly & Associates,
1998.
表十:測試二之結果
18
[2] Alessandro Rubini & Jonathan Corbet, " Linux Device Drivers", 2nd edition, O'Reilly
& Associates, June 2001.
[3] Andrew S.Tanenbaum, "Modern Operating Systems", Prentice Hall, 1996
[4] W. Richard Stevens, "TCP/IP Illustrated, Volume1&2", Addison Wesley , 1994
[5] 林盈達, "電腦網路實驗", 維科出版社, 1999.
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.