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