Linux網絡設備驅動框架

 /************************************************************************************html

*本文爲我的學習記錄,若有錯誤,歡迎指正。linux

*本文參考資料: 
api

*        http://www.cnblogs.com/xiaojiang1025/archive/2017/03/28/6486267.html
網絡

*        https://blog.csdn.net/zdy0_2004/article/details/79234386
數據結構

************************************************************************************/app

 1. 網絡設備驅動框架整體簡介

Linux網絡設備驅動程序體系結構分爲四層:網絡協議接口層、網絡設備接口層、提供實際功能的設備驅動層以及網絡設備與媒介層。框架

(1)網絡協議接口層ide

網絡協議接口層向網絡層協議提供統一的數據包收發接口,不論上層協議是ARP仍是IP,都經過dev_queue_xmit()函數發送數據,並經過netif_rx()函數接收數據。這一層的存在使得上層協議獨立於具體的設備。函數

(2)網絡設備接口層學習

網絡設備接口層向協議接口層提供的用於描述具體網絡設備屬性和操做的結構體net_device,該結構體是設備驅動功能層各函數的容器。

(3)設備驅動功能層

設備驅動功能層的各函數是網絡設備接口層net_device數據結構的具體成員,是驅使網絡設備硬件完成相應動做的程序,它經過nto_start_xmit()函數啓動發送操做,並經過網絡設備上的中斷觸發接收操做。

(4)網絡設備與媒介層

網絡設備與媒介層完成數據包發送和接收的物理實體,包括網絡適配器和具體的傳輸媒介,網絡適配器被設備驅動功能層中的函數在物理上驅動。

 

驅動工程師的工做:在設計具體的網絡設備驅動程序時,須要完成的主要工做是編寫設備驅動功能層的相關函數以填充net_device數據結構的內容並將net_device註冊入內核。

2. 相關數據結構

(1)struct sk_buff

sk_buff是網絡驅動框架中信息的載體, 是網絡分層模型中對數據進行層層打包以及層層解包的載體。

 427 struct sk_buff {
 428         /* These two members must be first. */
 429         struct sk_buff          *next;   //sk_buff是雙向鏈表,因此有前去後繼,這是指向後面的sk_buff結構體指針
 430         struct sk_buff          *prev;   //這是指向前一個sk_buff結構體指針 
 432         ktime_t                 tstamp;
 434         struct sock             *sk;
 435         struct net_device       *dev;    //對應的net_device
 443         char                    cb[48] __aligned(8);
 445         unsigned long           _skb_refdst;
 449         unsigned int            len,     //表示數據區的長度(tail-data)與分片結構體數據區的長度之和
 450                                 data_len;//只表示分片結構體數據區的長度,因此len=(tail - data) + data_len
 451         __u16                   mac_len, //mac報頭的長度
 452                                 hdr_len;
 473         __be16                  protocol;//包的協議類型,標識是IP包仍是ARP包仍是其餘數據包
 534         __u16                   inner_transport_header;
 535         __u16                   inner_network_header;
 536         __u16                   inner_mac_header;
 537         __u16                   transport_header; //指向傳輸包頭
 538         __u16                   network_header;   //指向傳輸層包頭
 539         __u16                   mac_header;       //指向鏈路層包頭
 540         /* These elements must be at the end, see alloc_skb() for details.  */
 541         sk_buff_data_t          tail;             //指向當前數據包的尾地址, 隨着各個網絡層的加工而變化
 542         sk_buff_data_t          end;              //數據緩衝區的結束地址
 543         unsigned char           *head,            //數據緩衝區的開始地址
 544                                 *data;            //data指向當前數據包的首地址, 隨着各個網路層的加工而變化
 545         unsigned int            truesize;
 546         atomic_t                users;
 547 };
struct sk_buff

 (2)struct net_device

Linux內核中使用 net_device 來描述一個網絡設備,net_device是設備接口層的核心, 也是編寫網絡驅動核心的對象。

1160 struct net_device {
1167         char                    name[IFNAMSIZ];//網絡設備的名稱, 網絡設備被載入後會出如今ifconfig中, 好比默認的eth0就是這個
1179         unsigned long           mem_end;        //網絡設備所使用的共享內存起始地址
1180         unsigned long           mem_start;      //網絡設備所使用的共享內存結束地址
1181         unsigned long           base_addr;      //表示網絡設備的IO基地址
1182         int                     irq;            //設備使用的中斷號
1189         unsigned long           state;
1190 
1191         struct list_head        dev_list;
1192         struct list_head        napi_list;
1193         struct list_head        unreg_list;
1194         struct list_head        close_list;
1210         netdev_features_t       features;       //用戶層能夠修改的特徵
1212         netdev_features_t       hw_features;    //用戶層不能修改的特徵
1214         netdev_features_t       wanted_features;
1243         const struct net_device_ops *netdev_ops;//網絡設備的操做方法集
1244         const struct ethtool_ops *ethtool_ops;  //ethtool的方法集
1245         const struct forwarding_accel_ops *fwd_ops;
1248         const struct header_ops *header_ops;    //協議頭操做集
1250         unsigned int            flags;  /* interface flags (a la BSD)   */
1251         unsigned int            priv_flags; /* Like 'flags' but invisible to userspace.
1252                                              * See if.h for definitions. */
1253         unsigned short          gflags;                   
1254         unsigned short          padded; /* How much padding added by alloc_netdev() */
1256         unsigned char           operstate; /* RFC2863 operstate */
1257         unsigned char           link_mode; /* mapping policy to operstate */
1259         unsigned char           if_port;        /* Selectable AUI, TP,..*/
1260         unsigned char           dma;            /* DMA channel          */
1262         unsigned int            mtu;    /* interface MTU value          */
1263         unsigned short          type;   /* interface hardware type      */
1264         unsigned short          hard_header_len;        /* hardware hdr length  */
1270         unsigned short          needed_headroom;
1271         unsigned short          needed_tailroom;
1274         unsigned char           perm_addr[MAX_ADDR_LEN]; /* permanent hw address */
1275         unsigned char           addr_assign_type; /* hw address assignment type */
1276         unsigned char           addr_len;       /* hardware address length      */
1289         struct kset             *queues_kset;
1386         int                     watchdog_timeo; /* used by dev_watchdog() */
1480 };
struct net_device

 (3)struct net_device_ops

 網絡設備的操做方法集。

1002 struct net_device_ops {
1003         int          (*ndo_init)(struct net_device *dev);
1004         void         (*ndo_uninit)(struct net_device *dev);
1005         int          (*ndo_open)(struct net_device *dev);//打開網絡接口設備,得到設備須要的I/O地址、IRQ、DMA通道等
1006         int          (*ndo_stop)(struct net_device *dev);//中止網絡接口設備,與open()函數的做用相反
1007         netdev_tx_t  (*ndo_start_xmit) (struct sk_buff *skb,struct net_device *dev);//啓動數據包的發送,當系統調用驅動程序的xmit函數時,須要向其傳入一個sk_buff結構體指針,以使得驅動程序能獲取從上層傳遞下來的數據包
1013         void         (*ndo_change_rx_flags)(struct net_device *dev,int flags);
1015         void         (*ndo_set_rx_mode)(struct net_device *dev);
1016         int          (*ndo_set_mac_address)(struct net_device *dev,void *addr);//用於設置設備的MAC地址
1018         int          (*ndo_validate_addr)(struct net_device *dev);
1019         int          (*ndo_do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);//用於進行設備特定的I/O控制
1021         int          (*ndo_set_config)(struct net_device *dev, struct ifmap *map);       //用於配置接口,也可用於改變設備的I/O地址和中斷號
1023         int          (*ndo_change_mtu)(struct net_device *dev, int new_mtu);
1025         int          (*ndo_neigh_setup)(struct net_device *dev,struct neigh_parms *);
1027         void         (*ndo_tx_timeout) (struct net_device *dev);//當數據包的發送超時時,ndo_tx_timeout()函數會被調用,該函數需採起從新啓動數據包發送過程或從新啓動硬件等措施來恢復網絡設備到正常狀態
1028 
1148 };

3. 相關API

(1)分配/釋放net_device

//linux/etherdevice.h
/**
 * 分配及初始化net_device對象()
 * @sizeof_priv - 私有數據大小(單位:字節數)
 * 返回值:失敗:NULL, 成功:net_device對象的首地址
 */
struct net_device *alloc_etherdev(int sizeof_priv);

//linux/netdevice.h
/**
 * 分配及初始化net_device對象
 * @int sizeof_priv - 私有數據大小(單位:字節數)
 * @const char *name - 物理接口名("名稱%d")
 * @unsigned char name_assign_type - NET_NAME_UNKNOWN
 * @void (*setup)(struct net_device *) - 初始化函數
 * 返回值:失敗:NULL成功:net_device對象的首地址
 */
struct net_device *alloc_netdev(int sizeof_priv, const char *name,unsigned char name_assign_type,void (*setup)(struct net_device *));


//釋放
void free_netdev(struct net_device *dev);

(2)以太網的初始化

在初始化一個以太網設備的時候應該被調用, 它的主要做用就是針對以太網標準對net_device對象進行初始化。

void ether_setup(struct net_device *dev);

(3)註冊/註銷net_device

//註冊
int register_netdev(struct net_device *dev);
//註銷
void unregister_netdev(struct net_device *dev);

 (4)開始/中止發送隊列

//開啓發送隊列
void netif_start_queue(struct net_device *dev)
//中止發送隊列
void netif_stop_queue(struct net_device *dev)

4. 網絡設備的中斷處理函數

中斷處理函數

是網絡設備媒介層相設備驅動功能層發送數據的接口, 網卡接收到數據是經過中斷的方式上報的, 因此網絡驅動中的中斷處理函數就是第一時間隊接收到的數據進行處理的地方,這個函數最終必定要調用netif_rx()將收到的數據上報到協議接口層。 

 5. 網絡設備驅動實例

轉載一篇DM9000驅動分析的文章,寫得很是詳細,感謝做者的貢獻。 Linux DM9000網卡驅動程序徹底分析

相關文章
相關標籤/搜索