Linux核心程式碼筆記6----網路模型
- 應用層 (TELNET、FTP、DNS)
- 傳輸層(TCP、UDP)
- Internet(IP)
- 網路介面物理層(PPP/SLIP、LAN)
網路裝置驅動程式功能:
- 傳送資料
當緩衝區被傳送到硬體以後,硬體應答訊號標識傳輸已經完畢,驅動程式必須呼叫dev_kfree_skb(skb, FREE_WRITE)函式釋放緩衝區,一旦該呼叫結束,緩衝區就會很自然地消失,這樣,驅動程式就不能再涉及緩衝區了。sk_buff是被鎖住的(locked),確保其他程式不會存取它。
資料幀在傳送之前先要排成對列,在加入佇列之前,還要在每個資料幀的開始新增硬體幀頭,這項工作對於資料傳送非常必要。網路裝置驅動程式提供了一個dev->hard_header()例程,來完成新增硬體幀頭的工作。協議層在傳送資料之前會在緩衝區的開始留下至少 dev->hard_header_len
- 接收資料
PACKET_BROADCAST 連結層廣播地址
PACKET_MULTICAST 連結層多路地址
PACKET_SELF 發給自己的資料幀
PACKET_OTHERHOST 發向另一個主機的資料幀 (監聽模式時會有到)
最後,裝置驅動程式呼叫netif_rx()把緩衝區向上傳遞給協議層。netif_rx()將資料放入處理佇列後返回,真正的處理是在中斷返回後,可以減少中斷時間。一旦netif_rx( )被呼叫,緩衝區就不在屬裝置驅動程式所有,它不能被修改,而且裝置驅動程式也不能再涉及它了。
在協議層,接收資料包的流程控制分兩個層次: 首先,netif_rx()函式限制了從物理層到協議層的資料幀的數量。第二,每一個套接字都有一個佇列,限制從協議層到套接字層的資料幀的數量。在傳輸方面,驅動程式的dev->tx_queue_len 引數用來限制佇列的長度。佇列的長度通常是100幀,在進行大量資料傳輸的高速連線中,它足以容納下所有等待傳輸的緩衝區,不會出現大量緩衝區阻塞的情況。在低速連線中,例如Slip 連線,佇列的長度長設為10幀左右,因為傳輸10幀的資料就要花費數秒的時間排列資料。
相關函式 初始化int (*init)(struct net_device *dev);裝置初始化和註冊時呼叫,執行的是底層的確認和檢查工作,對硬體資源的配置。 開啟裝置
int (*open)(struct net_device *dev);網路裝置啟用的時候呼叫(裝置狀態down->up)。主要功能:資源申請、硬體啟用等。若驅動作為模組裝入,open()裡呼叫MOD_INC_USE_COUNT,將引用計數器加1。 在使用者態執行ifconfig eth0 up命令時,要執行兩個任務。首先,它通過ioctl(SIOCSIFADDR)(Socket I/O Control Set Interface Address)賦予地址,然後通過ioctl(SIOCSIFFLAGS)(Socket I/O Control Set Interface Flags)設定dev->flag中的IFF_UP標誌以開啟介面。這個呼叫會使得裝置的open方法得到呼叫。類似的,在介面關閉時,ifconfig使用ioctl(SIOCSIFFLAGS)來清理IFF_UP標誌,然後呼叫stop函式。 關閉裝置
int (*stop)(struct net_device *dev);關閉時呼叫(裝置狀態up->down)。若驅動作為模組裝入,stop()中需呼叫MOD_DEC_USE_COUNT。 分配緩衝區
struct sk_buff *alloc_skb(unsigned int len, int priority);
struct sk_buff *dev_alloc_skb(unsigned int len);
分配一個緩衝區。alloc_skb函式分配一個緩衝區並初始化skb->data和skb->tail為skb->head。引數len為資料緩衝區的空間大小,通常以L1_CACHE_BYTES位元組(對ARM為32)對齊,引數priority為記憶體分配的優先順序。dev_alloc_skb()函式以GFP_ATOMIC優先順序進行skb的分配。
釋放緩衝區
void kfree_skb(struct sk_buff *skb); void dev_kfree_skb(struct sk_buff *skb);sk_buff結構中幾個資料指標指向如圖:
對sk_buff操作的幾個函式:
unsigned char *skb_put(struct sk_buff *skb, int len); unsigned char *skb_push(struct sk_buff *skb, int len); unsigned char *skb_pull(struct sk_buff *skb, int len); void skb_reserve(struct sk_buff ×skb, int len);操作函式
int (*hard_header)(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len);根據先前檢索到的源和目的硬體地址建立硬體頭
int (*rebuild_header)(struct sk_buff *skb);乙太網的mac地址是固定的,為了高效,第一個包去詢問mac地址,得到對應的mac地址後就會作為cache把mac地址儲存起來。以後每次發包不用詢問了,直接把包的地址拷貝出來。
void (*tx_timeout)(struct net_device *dev);資料包傳送超時失敗時呼叫。
struct net_device_stats *(*get_stats)(struct net_device *dev);統計裝置資訊。
int (*do_ioctl)(struct net_device *dev, struct ifmap *map);事先自定義的ioctl命令。 reference 1、深入分析Linux核心原始碼 2、Linux驅動程式開發例項 3、Linux驅動修煉之道