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