Linux網絡設備驅動程序體系結構
--------------------------------------
| 數據包發送 | 數據包接收 | ----->網絡協議接口層
| dev_queue_xmit() | netif_rx() |
|--------------------------------------
| 結構體 net_device | ----->網絡設備接 口層
--------------------------------------
| 數據包發送 | 中斷處理 | ----->網絡驅動功能層
| hard_start_xmit() | 數據包接收 |
|--------------------------------------
| 網絡設備媒介(物理層) | ----->網絡設備與媒介層
--------------------------------------
硬件相關的驅動程序(要提供hard_start_xmit, 有數據時要用netif_rx上報)
5.sk_buff套接字緩沖區,用於linux中各層之間傳輸數據。當要發送數據包的時候,內核必須建立一個包含傳輸數據的sk_buff
然後將sk_buff交給下層,各層在sk_buff遞交給下一層,各層在sk_buff中添加不同的協議貞頭,直到交給網絡設備發送。接收原理相同。
struct sk_buff {
/* These two members must be first. */
struct sk_buff *next;
struct sk_buff *prev;
/*網絡設備接口層中的net_devive結構體*/
struct net_device *dev;
....
/*控制緩沖區 ,每個層都可以使用它,用於存放私有數據*/
char cb[48];
unsigned int len, //數據真實長度
data_len,//數據長度
mac_len; //鏈接層幀頭的長度
/*鉤子函數 垃圾回收*/
void (*destructor)(struct sk_buff *skb);
sk_buff_data_t transport_header;
sk_buff_data_t network_header;
sk_buff_data_t mac_header;
/* These elements must be at the end, see alloc_skb() for details. */
sk_buff_data_t tail;
sk_buff_data_t end;
unsigned char *head,
*data;
unsigned int truesize;
atomic_t users;
};
5.1、sk_buff結構:
----------- ---->*head
| 頭部 |
|------------ ---->*data
| 數據 |
| 緩存 |
|----------- ---->*tail
| 尾部 |
----------- ---->*end
5.2、分配:
分配套接字緩沖區:以GFP_ATOMIC優先級進行skb的分配,因為該函數經常在設備驅動中被調用
static inline struct sk_buff *dev_alloc_skb(unsigned int length)
分配一個套接字緩沖區和一個數據緩沖區,參數len為數據緩沖區的大小,ARM通常32位對齊,參數priority為內存分配的優先級。
static inline struct sk_buff *alloc_skb(unsigned int size,gfp_t priority)
5.3、釋放:
//用於釋放dev_alloc_skb的內存,用於非中斷上下文中
void dev_kfree_skb(struct sk_buff *skb)
//用於中斷上下文中
static inline void dev_kfree_skb_irq(struct sk_buff *skb)
//中斷和非中斷都可以用 any,其實就是做了一個判斷
void dev_kfree_skb_any(struct sk_buff *skb)
{
if (in_irq() || irqs_disabled())
dev_kfree_skb_irq(skb);
else
dev_kfree_skb(skb);
}
5.4、變更:
緩沖區尾部增加數據 skb
static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
skb->tail += len;
skb->len += len;
緩沖區開頭增加數據
static inline unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
skb->data -= len;
skb->len += len;
緩沖區開頭移除數據
static inline unsigned char *skb_pull(struct sk_buff *skb, unsigned int len)
skb->len -= len;
return skb->data += len;
調節緩沖區頭部
static inline void skb_reserve(struct sk_buff *skb, int len)
skb->data += len;
skb->tail += len;
6.net_device結構體
struct net_device
{
/*網絡設備名稱*/
char name[IFNAMSIZ];
unsigned long mem_end; /* 共享內存結束地址 */
unsigned long mem_start; /* 共享內存開始地址 */
unsigned long base_addr; /* I/O設備的基地址 */
unsigned int irq; /* 設備中斷號 */
unsigned char if_port; /* 多端口設備使用哪一個端口*/
unsigned char dma; /* DMA channel
/*設備初始化函數,只被調用一次 */
int (*init)(struct net_device *dev);
/*用於獲取網絡設備的狀態信息*/
struct net_device_stats* (*get_stats)(struct net_device *dev);
/*存放詳細的網絡設備流量統計信息*/
struct net_device_stats stats;
.......................
unsigned mtu; /* interface MTU(最大傳輸單元) value*/
unsigned short type; /* 硬件接口類型 */
unsigned short hard_header_len; /* 硬件頭的長度 */
/*MAC地址*/
unsigned char dev_addr[MAX_ADDR_LEN];
/*私有數據,用於存放私有的數據,netdev_priv()*/
void *priv;
/*啟動數據包的發送*/
int (*hard_start_xmit) (struct sk_buff *skb,struct net_device *dev);
/*開始發送數據時候的時間戳 格式為:jiffies */
unsigned long trans_start;
/* 最後一次接受數據包的長度 */
unsigned long last_rx;
/* open用於打開網絡設備,獲取所需的IO地址和中斷號.stop()用於停止網絡設備 */
int (*open)(struct net_device *dev);
int (*stop)(struct net_device *dev);
/*用於設置設備的MAC地址*/
int (*set_mac_address)(struct net_device *dev,void *addr);
/*進行特定的IO控制*/
int (*do_ioctl)(struct net_device *dev,
struct ifreq *ifr, int cmd);
/*用於配置接口,可以用來改變設備的IO地址和中斷號*/
int (*set_config)(struct net_device *dev,struct ifmap *map);
/*數據包發送超時時候會被調用,可以用來重啟網卡*/
void (*tx_timeout) (struct net_device *dev);
/*linux4.0才有的一個結構體,linux2.6沒有,操作硬件的集合*/
struct net_device_ops {
.....
};
};