网络设备驱动学习
網(wǎng)絡(luò)設(shè)備驅(qū)動學(xué)習(xí)
概述:本周主要學(xué)習(xí)了網(wǎng)絡(luò)驅(qū)動層面的一些知識,最主要的學(xué)習(xí)目標(biāo)是基本弄清包的發(fā)送與接收的過程,這不僅涉及到了高層的協(xié)議與機制,底層的驅(qū)動與硬件,更要理解數(shù)據(jù)包的封裝與包格式。我們主要是圍繞著設(shè)備驅(qū)動開發(fā)的第十六章來學(xué)習(xí)這些內(nèi)容。
問題:對十六章進(jìn)行細(xì)化后發(fā)現(xiàn)主要可以歸結(jié)成對幾個問題的把握,包括數(shù)據(jù)包的承載問題,加包頭與去包頭的實現(xiàn),網(wǎng)絡(luò)的框架結(jié)構(gòu),網(wǎng)絡(luò)設(shè)備的注冊與注銷,數(shù)據(jù)的發(fā)送與接收流程。
正文:
一、數(shù)據(jù)包的承載問題
這個問題落到了結(jié)構(gòu)體sk_buff上,也就是套接字緩沖區(qū),根本上來講就是內(nèi)存中存放傳輸數(shù)據(jù)包的一塊內(nèi)存區(qū)域。此結(jié)構(gòu)體流動于各協(xié)議層之間,發(fā)送和接收時,用于添加協(xié)議頭與剝?nèi)f(xié)議頭,這兩個操作就是通過sk_buff里的四個指針域來實現(xiàn)的。下面來簡述這個關(guān)鍵結(jié)構(gòu)體的一些成員:
(1) .sk_buff中的各層協(xié)議頭:
采用了聯(lián)合體來描述各層的協(xié)議頭,分別描述了傳輸層h、網(wǎng)絡(luò)層nh和鏈路層mac中的各個協(xié)議頭,其中包括的成員主要就是各層的協(xié)議頭,還有指向所在層頭部的指針*raw。
(2) .sk_buff中4個數(shù)據(jù)指針:
head/end:套接字緩沖區(qū)的起始地址/終止地址
data/tail:協(xié)議數(shù)據(jù)區(qū)起始地址/終止地址
只要明白這四個指針是四個邊界就很好理解數(shù)據(jù)緩沖區(qū)的構(gòu)成了,尤其要知道data/tail之間存放的是有效數(shù)據(jù),這里可以理解成協(xié)議頭和用戶數(shù)據(jù)。
(3) .三個長度信息
len:協(xié)議數(shù)據(jù)包長度
data_len:記錄分片的數(shù)據(jù)長度
truesize:數(shù)據(jù)緩沖區(qū)的實際長度
由于數(shù)據(jù)鏈路層有最大傳輸單元MTU的限制,這就引入了分片的機制,這里主要是在網(wǎng)絡(luò)層由IP協(xié)議來實現(xiàn),其中有一個字段就是片偏移指針。相應(yīng)的在套接字緩沖區(qū)末尾有一個skb_shared_info結(jié)構(gòu)體,用于記錄分片的一些信息,frags即為分片數(shù)組,每一個分片長度的上限是一頁,即4KB大小,再配合長度信息data_len,這樣對于分片機制就比較理解了。
二、加包頭與去包頭
這個問題主要就是通過移動sk_buff里的四個指針域來實現(xiàn)的,這里不得不提的就是套接字緩沖區(qū)提供的四個指針移動函數(shù)。
這四個函數(shù)分別是put(放置)、push(推)、pull(拉)、reserve(保留), put函數(shù)用于將tail指針向后移動,主要是完成存放數(shù)據(jù)包的操作,push函數(shù)用于將data指針向前移動,主要是完成加協(xié)議頭的操作,
pull函數(shù)用于將data指針向后移動,主要是完成去協(xié)議頭的操作,
reserve函數(shù)用于將data和tail指針同時后移,主要用于在存儲空間的頭部預(yù)留一部分空間,用時是用于協(xié)議頭對齊。
?????? 下面主要簡述一下接收包的過程:
?????? (1)、網(wǎng)卡收到一個數(shù)據(jù)包后,驅(qū)動程序創(chuàng)建一個sk_buff結(jié)構(gòu)體,在緩沖區(qū)頭部預(yù)留2個字節(jié)的空間用于協(xié)議頭的對齊,接著將收到的數(shù)據(jù)全部復(fù)制到data指向的空間,并將skb->mac.raw指向data。
(2)、數(shù)據(jù)鏈路層調(diào)用skb_pull()函數(shù)剝掉以頭網(wǎng)協(xié)議頭(data指針下移一個以太網(wǎng)頭部的長度sizeof(ethhdr),len減去一個以太網(wǎng)頭部的長度,skb->nh.raw指向data位置),向網(wǎng)絡(luò)層傳遞數(shù)據(jù)包。
(3)、網(wǎng)絡(luò)層通過skb_pull()函數(shù)剝掉IP頭,向傳輸層傳遞數(shù)據(jù)包。去包頭過程于(2)類似,主要還是data指針和傳輸層包頭指針的下移。
(4)、應(yīng)用程序調(diào)用接收套接字接收數(shù)據(jù),并將數(shù)據(jù)復(fù)制到應(yīng)用層緩沖區(qū),接收的數(shù)據(jù)包括傳輸層包頭和負(fù)載,由此可見傳輸層包頭并不會被剝離。
三、體系架構(gòu)的理解
?? 在架構(gòu)的上面是四層網(wǎng)絡(luò)協(xié)議,下面是四個底層,包括網(wǎng)絡(luò)協(xié)議接口層、網(wǎng)絡(luò)設(shè)備接口層、設(shè)備驅(qū)動功能層、網(wǎng)絡(luò)設(shè)備與媒介層。sk_buff流動于四個協(xié)議層,用于數(shù)據(jù)包的承載。在網(wǎng)絡(luò)協(xié)議接口層有兩個函數(shù),分別用于數(shù)據(jù)包的發(fā)送dev_queue_xmit()函數(shù),數(shù)據(jù)包的接收netif_rx()函數(shù)。在網(wǎng)絡(luò)設(shè)備接口層有一個底層最關(guān)鍵的數(shù)據(jù)結(jié)構(gòu)net_device,這是個用于描述網(wǎng)絡(luò)設(shè)備屬性和操作接口的數(shù)據(jù)結(jié)構(gòu)。設(shè)備驅(qū)動功能層則提供了一些底層的操作,包括數(shù)據(jù)包發(fā)送hard_start_xmit(),中斷處理(數(shù)據(jù)包接收)等等,這些操作提供的接口都在net_device中存放著。網(wǎng)絡(luò)設(shè)備與媒介層則提供數(shù)據(jù)的遠(yuǎn)距離傳輸。底層框架如下圖:
net_device包括的信息主要有:
(1)、全局信息:設(shè)備名稱name,網(wǎng)絡(luò)設(shè)備初始化函數(shù)init()。
(2)、硬件信息:共享內(nèi)在的起止地址mem_start、men_end,I/O基地址base_addr,設(shè)備中斷號irq,多端口設(shè)備支持if_port,DMA通道dma。
(3)、接口信息:硬件頭長度hard_header_len,硬件類型type,最大傳輸單元mtu,硬件地址dev_addr,廣播地址broadcast,網(wǎng)絡(luò)接口標(biāo)志flags。
(4)、設(shè)備操作函數(shù):open、stop、do_ioctl、tx_timeout、poll等等。
(5)、輔助成員:發(fā)送時間戳trans_start,接收時間戳last_rx,私有信息指針*priv(存放設(shè)備的一些私有信息),自旋鎖xmit_lock。
四、網(wǎng)絡(luò)設(shè)備的注冊與注銷
網(wǎng)絡(luò)設(shè)備的注冊與注銷是兩個相反的過程,我們只要明白了注冊的過程那么注銷過程自然也就能明白了。網(wǎng)絡(luò)設(shè)備的注冊與注銷是使用register_netdev()和unregister_netdev()這兩個函數(shù)實現(xiàn)的,這兩個函數(shù)接收的參數(shù)只有一個net_device結(jié)構(gòu)體變量,由此也可見這個結(jié)構(gòu)體就可以簡單理解成網(wǎng)絡(luò)設(shè)備,分配函數(shù)如下: alloc_netdev(sizeof(struct xxx_priv),*name,*xxx_init),三個參數(shù)分別為,私有信息結(jié)構(gòu)體的大小,設(shè)備名稱,設(shè)備初始化函數(shù)。進(jìn)一步追蹤注冊過程就是弄懂這個結(jié)構(gòu)體變量的由來,也就是分配結(jié)構(gòu)體并填充里面的成員,這就是xxx_init函數(shù)的問題了。
xxx_init函數(shù)主要完成的工作有創(chuàng)建設(shè)備的私有信息結(jié)構(gòu)體,設(shè)置設(shè)備的硬件資源(進(jìn)行硬件上的準(zhǔn)備工作),初始化設(shè)備net_device的公用成員(進(jìn)行軟件接口上的準(zhǔn)備工作),設(shè)置成員的函數(shù)指針,最后進(jìn)行私有信息的初始化。設(shè)置設(shè)備的硬件資源包括探測網(wǎng)絡(luò)設(shè)備是否存在,探測設(shè)備的具體硬件配置,申請設(shè)備所需要的硬件資源,如I/O端口,irq,DMA通道等,這個過程也可以放到設(shè)備的打開函數(shù)中來完成。
當(dāng)net_device結(jié)構(gòu)體分配并填充完后就可以調(diào)用注冊函數(shù)來注冊設(shè)備了,注銷的過程就是先調(diào)用注銷函數(shù),再釋放掉這個結(jié)構(gòu)體就行了。
五、數(shù)據(jù)的發(fā)送與接收
驅(qū)動程序調(diào)用hard_start_transmit()函數(shù)來發(fā)送數(shù)據(jù)包,這個函數(shù)在設(shè)備初始化的時候被指向了設(shè)備的xxx_tx()函數(shù)。數(shù)據(jù)的發(fā)送流程大致如下:
(1)、網(wǎng)絡(luò)設(shè)備驅(qū)動程序從上層協(xié)議傳遞來的sk_buff結(jié)構(gòu)中獲取數(shù)據(jù)包的有效數(shù)據(jù)和長度,將有效數(shù)據(jù)放入臨時緩沖區(qū)。
(2)、將有效數(shù)據(jù)的長度與以太網(wǎng)數(shù)據(jù)幀的最小長度進(jìn)行比較,如果有效長度小于最小幀長,則給緩沖區(qū)末尾填充0。
(3)、設(shè)置硬件的寄存器,發(fā)送時間戳,進(jìn)行數(shù)據(jù)發(fā)送的操作。
驅(qū)動的接收數(shù)據(jù)過程要依賴于中斷處理函數(shù),首先判斷中斷類型是否為接收中斷,如果是才進(jìn)行下一步接收操作。數(shù)據(jù)的接收流程大致如下:
(1)、判斷中斷類型為接收中斷后調(diào)用接收函數(shù)。
(2)、調(diào)用函數(shù)從硬件上讀取數(shù)據(jù)包長度,分配套接字緩沖區(qū)并完成協(xié)議頭的對齊操作。
(3)、讀取硬件上接收到的數(shù)據(jù),并獲取上層協(xié)議類型,將數(shù)據(jù)包遞交給上層,記錄接收時間戳,遞交上層后的操作就可以轉(zhuǎn)到去協(xié)議頭流程了。
總結(jié)
- 上一篇: textfield观察UIControl
- 下一篇: 智能手环guard日志获取-兔盯云