1.Linux網(wǎng)絡(luò)子系統(tǒng)
Linux網(wǎng)絡(luò)子系統(tǒng)的頂部是系統(tǒng)調(diào)用接口層。它為用戶空間提供的應(yīng)用程序提供了一種訪問內(nèi)核網(wǎng)絡(luò)子系統(tǒng)的方法(socket)。位于其下面是一個協(xié)議無關(guān)層,它提供一種通用的方法來使用傳輸層協(xié)議。然后是具體協(xié)議的實現(xiàn),在Linux中包括內(nèi)核的協(xié)議TCP,UDP,當(dāng)然還有IP。然后是設(shè)備無關(guān)層,它提供了協(xié)議與設(shè)備驅(qū)動通信的通用接口,最下面是設(shè)備的驅(qū)動程序。
設(shè)備無關(guān)接口將協(xié)議與各種網(wǎng)絡(luò)驅(qū)動連接在一起,這一層提供一組通用函數(shù)供底層網(wǎng)絡(luò)設(shè)備驅(qū)動使用,讓它們可以對高層協(xié)議棧進行操作。需要從協(xié)議層向設(shè)備發(fā)生數(shù)據(jù),需要調(diào)用dev_queue_xmit函數(shù),這個函數(shù)對數(shù)據(jù)進行列隊,然后交由底層驅(qū)動程序的hard_start_xmit方法最終完成傳輸。接收通常是使用netif_rx執(zhí)行的。當(dāng)?shù)讓釉O(shè)備程序接收到一個報文(發(fā)生中斷)時,就會調(diào)用netif_rx將數(shù)據(jù)上傳至設(shè)備無關(guān)層。
下圖為設(shè)備無關(guān)層到驅(qū)動層的體系結(jié)構(gòu)
2.網(wǎng)絡(luò)設(shè)備描述(structnet_device)
每一個網(wǎng)絡(luò)設(shè)備都由struct net_device來描述,該結(jié)構(gòu)可使用如下內(nèi)核函數(shù)進行動態(tài)分配
struct net_device *alloc_net(intsizeof_priv, const char *mask, void(*setup)(struct net_deive *))
sizeof_priv是私有數(shù)據(jù)區(qū)大??;mask是設(shè)備名,setup是初始化函數(shù),在注冊該設(shè)備時,該函數(shù)被調(diào)用。也就是net_deivce的init成員。
struct net_device *alloc_etherdev(intsizeof_priv)
這個函數(shù)和上面的函數(shù)不同之處在于內(nèi)核知道會將該設(shè)備做一個以太網(wǎng)設(shè)備看待并做一些相關(guān)的初始化。
net_device結(jié)構(gòu)可分為全局成員、硬件相關(guān)成員、接口相關(guān)成員、設(shè)備方法成員和公用成員等五個部分
主要全局成員
char name[INFAMSIZ]
設(shè)備名,如:eh%d
unsigned long state
設(shè)備狀態(tài)
unsigned long base_addr
I/O基地址
unsigned int irq
中斷號
主要設(shè)備方法有
int (*init)(struct net_device *dev)
初始化函數(shù),該函數(shù)在register_netdev時被調(diào)用來完成對net_device結(jié)構(gòu)的初始化
int (*open)(struct net_device *dev)
打開接口。ifconfig激活時,接口將被打開
int (*stop)(struct net_deivce *dev)
停止接口,ifconfig eth% down時調(diào)用
int (*hard_start_xmit)(struct sk_buf*skb,struct net_device *dev)
數(shù)據(jù)發(fā)送函數(shù)
int (*do_ioctl)(struct net_deive *dev,struct ifreq *ifr, int cmd)
處理特定于接口的ioctl命令(sock_ioctl)進行調(diào)用。
int (*set_mac_address)(struct net_device*dev, void *addr)
改變MAC地址的函數(shù),需要硬件支持該功能。
網(wǎng)絡(luò)設(shè)備的注冊
網(wǎng)絡(luò)設(shè)備注冊方式與字符驅(qū)動不同之處在于它沒有主次設(shè)備號,并使用下面的函數(shù)注冊
int register_netdev(struct net_deivce*dev)
網(wǎng)絡(luò)設(shè)備的注銷
void unregister_netdev(struct net_device*dev)
3.網(wǎng)絡(luò)數(shù)據(jù)包描述(sk_buff)
Linux內(nèi)核中每個網(wǎng)絡(luò)數(shù)據(jù)包都由一個套接字緩沖區(qū)結(jié)構(gòu)structsk_buff描述,既每個sk_buff結(jié)構(gòu)就是一個包,指向sk_buff的指針通常被稱作skb
sk_buff中重要的數(shù)據(jù)成員
struct device *dev;處理該包得設(shè)備
__u32 sadd;r//IP元地址
__u32 daddr;//IP目的地址
__u32 raddr;//IP路由器地址
unsigned char *head;//分配空間的開始
unsigned char *data;//有效數(shù)據(jù)的開始
unsigned char *tail;//有效數(shù)據(jù)的結(jié)束
unsigned char *end;//分配空間的結(jié)束
unsigned long len;//有效數(shù)據(jù)的長度
sk_buff操作
struct sk_buff *alloc_skb(unsigned intlen, int priority)
分配一個sk_buff結(jié)構(gòu),供協(xié)議棧代碼使用
struct sk_buff *dev_alloc_skb(unsignedint len)
分配一個sk_buff結(jié)構(gòu)。供驅(qū)動代碼使用
void kfree_skb(struct sk_buff *skb)
void dev_kfree_skb(struct sk_buff *skb)
釋放sk_buff結(jié)構(gòu)
unsigned char *skb_push(struct sk_buff*skb,int len)
將data指針向前移動len長度。并返回移動之后的值。用于向skb有效數(shù)據(jù)區(qū)域前端添加數(shù)據(jù)(包頭)。
unsigned char *skb_put(struct sk_buff*skb, int len)
將taill指針向后移動len長度,并返回tail移動之前的值。用于向skb有效數(shù)據(jù)區(qū)域末尾添加數(shù)據(jù)。
4.驅(qū)動的實現(xiàn)
1).初始化(init)
設(shè)備探測工作在init方法中進行,一般調(diào)用一個稱之為probe方法的函數(shù)
初始化的主要工作時檢測設(shè)備,配置和初始化硬件,最后向系統(tǒng)申請這些資源。此外填充該設(shè)備的dev結(jié)構(gòu),我們調(diào)用內(nèi)核提供的ether_setup方法來設(shè)置一些以太網(wǎng)默認的設(shè)置。
2)打開(open)
open這個方法在網(wǎng)絡(luò)設(shè)備驅(qū)動程序里是網(wǎng)絡(luò)設(shè)備被激活時被調(diào)用(即設(shè)備狀態(tài)由down變成up)
實際上很多在初始化的工作可以放到這里來做。比如說資源的申請,硬件的激活。如果dev->open返回非0,則硬件狀態(tài)還是down
3)關(guān)閉(stop)
stop方法做和open相反的工作
可以釋放某些資源以減少系統(tǒng)負擔(dān)
stop是在設(shè)備狀態(tài)由up轉(zhuǎn)為down時被調(diào)用
4)發(fā)送(hard_start_xmit)
在系統(tǒng)調(diào)用的驅(qū)動程序的hard_start_xmit時,發(fā)送的數(shù)據(jù)放在一個sk_buff結(jié)構(gòu)中。一般的驅(qū)動程序傳給硬件發(fā)出去。也有一些特殊的設(shè)備比如說loopback把數(shù)據(jù)組成一個接收數(shù)據(jù)在傳送給系統(tǒng)或者dummy設(shè)備直接丟棄數(shù)據(jù)。
如果發(fā)送成功,hard_start_xmit方法釋放sk_buff。如果設(shè)備暫時無法處理,比如硬件忙,則返回1。
5)接收
驅(qū)動程序并存在一個接受方法。當(dāng)有數(shù)據(jù)收到時驅(qū)動程序調(diào)用netif_rx函數(shù)將skb交交給設(shè)備無關(guān)層。
一般設(shè)備收到數(shù)據(jù)后都會產(chǎn)生一個中斷,在中斷處理程序中驅(qū)動程序申請一塊sk_buff(skb)從硬件中讀取數(shù)據(jù)位置到申請?zhí)柕木彌_區(qū)里。
接下來填充sk_buff中的一些信息。
中斷有可能是收到數(shù)據(jù)產(chǎn)生也可能是發(fā)送完成產(chǎn)生,中斷處理程序要對中斷類型進行判斷,如果是收到數(shù)據(jù)中斷則開始接收數(shù)據(jù),如果是發(fā)送完成中斷,則處理發(fā)送完成后的一些操作,比如說重啟發(fā)送隊列。
?
評論
查看更多