1. 程式人生 > >Linux 網卡驅動學習(二)(網絡驅動接口小結)

Linux 網卡驅動學習(二)(網絡驅動接口小結)

-a key 頻率 網絡 上網 ren 網絡設備 ews 入口

【摘要】前文我們分析了一個虛擬硬件的網絡驅動樣例。從中我們看到了網絡設備的一些接口。事實上網絡設備驅動和塊設備驅動的功能比較相似,都是發送和接收數據包(數據請求)。

當然它們實際是有非常多不同的。

1、引言

首先塊設備在/dev文件夾下有設備節點。而網絡設備沒有這種設備入口。

read,write等常規的文件接口在網絡設備下也沒有意義。
最大的差別在於:塊設備僅僅響應內核的數據請求;而網絡設備驅動要異步地接收來自外部的數據包。簡單地說。塊設備驅動是被要求數據傳輸而網絡設備是主動請求數據傳輸。網絡設備驅動還須要支持設置地址,改動傳輸參數等等這種操作。所以網絡設備驅動的api須要提供這些接口。

本文是對上文虛擬硬件的網絡驅動樣例進行一個簡單的梳理。

(1)網絡設備註冊

頭文件:<linux/netdevice.h>
struct net_device 網絡設備結構體
struct net_device *alloc_netdev (int size_priv, const char *name, void (*setup)(struct net_device *));
int register_netdev(struct net_device *device); 註冊網絡設備
void unregitster_netdev(struct net_device *device); 註銷網絡設備

(2)打開和關閉
驅動在載入入內核後,內核會調用probe函數來探測它。在網絡接口能夠傳送數據包時,內核必須首先打開它並給它設置地址。內核打開和關閉網絡接口是由ifconfig命令觸發的。

int (*open)(struct net_device*); 打開網絡設備
int (*stop)(struct net_device*); 關閉網絡設備
void netif_start_queue(struct net_device*); 啟動網絡傳輸隊列
void netif_stop_queue(struct net_device*); 關閉網絡傳輸隊列

(3)網絡數據的發送
網絡接口最關鍵的數據是發送和接收網絡數據。

頭文件:<linux/skbuff.h> 定義了網絡驅動中傳輸的基本單元。struct sk_buff
struct netdeviceops 網絡設備驅動須要實現的接口函數
netdev_tx_t (*ndo_start_xmit) (struct sk_buff *skb, struct net_device *dev); 傳輸網絡數據包的函數
void (*ndo_tx_timeout) (struct net_device *dev); 傳輸超時函數

(4)網絡數據的接收
接收網絡數據相對於發送數據要復雜一些。由於你須要在原子上下文中把分配一個 sk_buff 並把它移交給上層處理。

數據包接收有兩種實現方式:中斷驅動和輪詢。大多數驅動都是中斷驅動的。有一些高吞吐量的驅動會使用輪詢的方式。

struct sk_buff *dev_alloc_skb(unsigned int length); 原子上下文中分配skb
printk_ratelimit() 限制printk的輸出頻率,在中斷對應函數中降低輸出

實現高吞吐量的網絡驅動,要降低網絡堵塞最好的方法是使用napi,後面會介紹

(5)中斷處理
硬件能夠中斷cpu發送兩種事件:新的數據包到來和發送的數據包已經發送完畢。

推斷並處理數據包事件
假設在其它地方臨時停止了發送隊列。應該在中斷函數中又一次啟動它

(6)NAPI
高吞吐量的網絡接口假設每一個數據包都用中斷來處理的話會給系統帶來非常大的負擔。這個時候應該使用基於輪詢的 NAPI。這樣能夠減輕系統的負擔,降低堵塞的時間。

僅僅有極少數的設備實現了NAPI,由於實現起來比中斷要復雜。並且有其它的一些條件。

在中斷處理函數中,首先禁止進一步的中斷處理,然後調度輪詢函數,進入輪詢函數後連續處理多個數據發送請求。

int (*poll)(struct net_device *dev, int *budget); 網絡驅動輪詢函數
int netif_rx_schedule(struct net_device *dev); 準備調用輪詢函數
int (*poll)(struct net_device *dev, int *budget); 輪詢函數

Linux 網卡驅動學習(二)(網絡驅動接口小結)