Linux裝置驅動工程師之路——網路裝置驅動基本原理和架構

來源:互聯網
上載者:User

Linux裝置驅動工程師之路——網路裝置驅動基本原理和架構

K-Style

轉載請註明來自于衡陽師範學院08電2  K-Style  http://blog.csdn.net/ayangke,QQ:843308498 郵箱:yangkeemail@qq.com

 

1.Linux網路子系統

    Linux網路子系統的頂部是系統調用介面層。它為使用者空間提供的應用程式提供了一種訪問核心網路子系統的方法(socket)。位於其下面是一個協議無關層,它提供一種通用的方法來使用傳輸層協議。然後是具體協議的實現,在Linux中包括核心的協議TCP,UDP,當然還有IP。然後是裝置無關層,它提供了協議與裝置驅動通訊的通用介面,最下面是裝置的驅動程式。

    裝置無關介面將協議與各種網路驅動串連在一起,這一層提供一組通用函數供底層網路裝置驅動使用,讓它們可以對高層協議棧進行操作。需要從協議層向裝置發生資料,需要調用dev_queue_xmit函數,這個函數對資料進行列隊,然後交由底層驅動程式的hard_start_xmit方法最終完成傳輸。接收通常是使用netif_rx執行的。當底層裝置程式接收到一個報文(發生中斷)時,就會調用netif_rx將資料上傳至裝置無關層。

為裝置無關層到驅動層的體繫結構

2.網路裝置描述(structnet_device)

 

    每一個網路裝置都由struct net_device來描述,該結構可使用如下核心功能進行動態分配

struct net_device *alloc_net(intsizeof_priv, const char *mask, void(*setup)(struct net_deive *))

sizeof_priv是私人資料區大小;mask是裝置名稱,setup是初始化函數,在註冊該裝置時,該函數被調用。也就是net_deivce的init成員。

struct net_device *alloc_etherdev(intsizeof_priv)

這個函數和上面的函數不同之處在於核心知道會將該裝置做一個乙太網路裝置看待並做一些相關的初始化。

net_device結構可分為全域成員、硬體相關成員、介面相關成員、裝置方法成員和公用成員等五個部分

    主要全域成員

char name[INFAMSIZ]

裝置名稱,如:eh%d

unsigned long state

裝置狀態

unsigned long base_addr

I/O基地址

unsigned int irq

中斷號

 

    主要裝置方法有

int (*init)(struct net_device *dev)

初始化函數,該函數在register_netdev時被調用來完成對net_device結構的初始化

int (*open)(struct net_device *dev)

開啟介面。ifconfig啟用時,介面將被開啟

int (*stop)(struct net_deivce *dev)

停止介面,ifconfig eth% down時調用

int (*hard_start_xmit)(struct sk_buf*skb,struct net_device *dev)

資料發送函數

int (*do_ioctl)(struct net_deive *dev,struct ifreq *ifr, int cmd)

處理特定於介面的ioctl命令(sock_ioctl)進行調用。

int (*set_mac_address)(struct net_device*dev, void *addr)

改變MAC地址的函數,需要硬體支援該功能。

 

    網路裝置的註冊

網路裝置註冊方式與字元驅動不同之處在於它沒有主次裝置號,並使用下面的函數註冊

int register_netdev(struct net_deivce*dev)

網路裝置的登出

void unregister_netdev(struct net_device*dev)

 

3.網路資料包描述(sk_buff)

 

    Linux核心中每個網路資料包都由一個通訊端緩衝區結構structsk_buff描述,既每個sk_buff結構就是一個包,指向sk_buff的指標通常被稱作skb

sk_buff中重要的資料成員

struct device *dev;處理該包得裝置

__u32 sadd;r//IP元地址

__u32 daddr;//IP目的地址

__u32 raddr;//IP路由器地址

 

unsigned char *head;//分配空間的開始

unsigned char *data;//有效資料的開始

unsigned char *tail;//有效資料的結束

unsigned char *end;//分配空間的結束

unsigned long len;//有效資料的長度

sk_buff操作

struct sk_buff *alloc_skb(unsigned intlen, int priority)

分配一個sk_buff結構,供協議棧代碼使用

struct sk_buff *dev_alloc_skb(unsignedint len)

分配一個sk_buff結構。供驅動代碼使用

void kfree_skb(struct sk_buff *skb)

void dev_kfree_skb(struct sk_buff *skb)

釋放sk_buff結構

unsigned char *skb_push(struct sk_buff*skb,int len)

將data指標向前移動len長度。並返回移動之後的值。用於向skb有效資料區域前端添加資料(包頭)。

unsigned char *skb_put(struct sk_buff*skb, int len)

將taill指標向後移動len長度,並返回tail移動之前的值。用於向skb有效資料區域末尾添加資料。

4.驅動的實現

 

    1).初始化(init)

裝置探測工作在init方法中進行,一般調用一個稱之為probe方法的函數

初始化的主要工作時檢測裝置,配置和初始化硬體,最後向系統申請這些資源。此外填充該裝置的dev結構,我們調用核心提供的ether_setup方法來設定一些乙太網路預設的設定。

 

    2)開啟(open)

open這個方法在網路裝置驅動程式裡是網路裝置被啟用時被調用(即裝置狀態由down變成up)

實際上很多在初始化的工作可以放到這裡來做。比如說資源的申請,硬體的啟用。如果dev->open返回非0,則硬體狀態還是down

 

    3)關閉(stop)

stop方法做和open相反的工作

可以釋放某些資源以減少系統負擔

stop是在裝置狀態由up轉為down時被調用

 

    4)發送(hard_start_xmit)

在系統調用的驅動程式的hard_start_xmit時,發送的資料放在一個sk_buff結構中。一般的驅動程式傳給硬體發出去。也有一些特殊的裝置比如說loopback把資料群組成一個接收資料在傳送給系統或者dummy裝置直接丟棄資料。

如果發送成功,hard_start_xmit方法釋放sk_buff。如果裝置暫時無法處理,比如硬體忙,則返回1。

 

    5)接收

驅動程式並存在一個接受方法。當有資料收到時驅動程式調用netif_rx函數將skb交交給裝置無關層。

一般裝置收到資料後都會產生一個中斷,在中斷處理常式中驅動程式申請一塊sk_buff(skb)從硬體中讀取資料位元置到申請號的緩衝區裡。

接下來填充sk_buff中的一些資訊。

中斷有可能是收到資料產生也可能是發送完成產生,中斷處理常式要對中斷類型進行判斷,如果是收到資料中斷則開始接收資料,如果是發送完成中斷,則處理髮送完成後的一些操作,比如說重啟發送隊列。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.