?? (ldd) ch14-網絡驅動程序(下)(轉載).txt
字號:
除了使用標準的調用,每個接口可以定義它自己的ioctl命令。例如plip接口允許通過io
ctl修改其內部超時值。套接字的ioctl實現將16個命令看作對接口是私有的:從SIOCDEV
PRIVATE到SIOCDEVPRIVATE+15。
當這些命令中的一個被認識時,dev->do_ioctl在相關的接口驅動程序里被調用。這個函
數接收與通用目的的ioctl函數使用的一樣的ifreq*指針。
Int (*do_ioctl)(struct device *dev, struct ifreq *ifr, int cmd);
Ifr指針指向核心空間的一個地址,放有被用戶傳來結構的一個拷貝。在do_ioctl返回后
,這個結構又被拷貝回用戶空間;這樣,驅動程序可以使用私有命令來接收和返回數據
。
設備特定的命令可以選擇使用結構ifreq中的域,但它們已經帶有標準的含義,驅動程序
不太可能根據自己的需要適配這個結構。域ifr_data是個caddr_t項(一個指針),用于
設備特定的需要。驅動程序和調用ioctl命令的程序應在ifr_data的使用上取得一致。例
如,pppstats使用設備特定的命令來從ppp接口驅動程序中獲取信息。
在這里不值得給出do_ioctl的一個實現,但根據本章的信息和核心的例子,你應能在需
在這里不值得給出do_ioctl的一個實現,但根據本章的信息和核心的例子,你應能在需
要的時候寫出一個。不過注意,plip實現不正確地使用了ifr_data,不應做為ioctl實現
的一個例子。
統計信息
一個驅動程序需要的最后一個方法是get_stats。這個方法返回指向設備統計信息的一個
指針。它的實現相當容易:
(代碼335)
返回有意義的統計信息所需的實際工作散布在驅動程序中,不同的域分別被更新。下表
給出enet_statistics結構中最有趣的幾個域。
int rx_packets;
int tx_packets;
這兩個域含有接口成功傳送的進來和外出包的總數。
這兩個域含有接口成功傳送的進來和外出包的總數。
int rx_errors;
int tx_errors;
出錯的接收和發送的數目。接收錯可能是錯誤的校驗和、錯誤的包大小,以及其它問題
的結果。發送錯誤不太常見,一般都是線纜的問題。
int rx_dropped;
int tx_dropped;
在接收和發送時被丟棄的包的個數。當包數據沒有可用內存時,包便被丟棄了。tx_drop
ped很少使用。
這個結構還有幾個域,可以用來細分發送和接收時發生的錯誤。感興趣的讀者可以看<li
nux/if_ether.h>中結構的定義。
選播
“選播”包是指一個網絡包,它將要被多于一個,但又不是全部的主機接收。
這個功能是通過給一組主機賦以特殊的硬件地址來獲得的。指向這些特殊地址中的一個
的包將被這個組中所有的主機收到。在以太網的情況下,一個選播地址是將目的地址中
第一個八元組的最低位設置而得到,而所有的設備板子都在其硬件地址中將這一位清除
。
處理主機組以及硬件地址的棘手部分都有應用或核心完成了,接口驅動程序并不需要處
理這些問題。
選播包的發送很簡單,與其它包完全一樣。接口在傳輸介質上發送它們,根本不管目的
地址。核心必須設置一個正確的硬件目的地址;rebuild_header設備方法(如果被定義
)并不需要查看它整理的數據。
而另一方面,接收選播包需要設備的一些合作。當一個“有趣的”選播包被收到時(也
就是一個包的目的地址確定一組主機,其中包含了這個接口),硬件應該通知操作系統
。這意味著硬件過濾器應被設計為能夠區別不同的選播地址。這個過濾器在接口的一般
操作中,將網絡包的地址與其自己的硬件地址進行匹配。
操作中,將網絡包的地址與其自己的硬件地址進行匹配。
典型地,在考慮選播的情況下,硬件可分為一下三類:
l 不能處理選播的接口。這類接口要么接收指向自己硬件地址的包(包括播送
包),要么節收所有的包。它們接收選播包是通過接收所有的包實現的,這樣,操作系
統中會充斥著大量“無意義”的包。一般我們不認為這類接口為支持選播的,驅動程序
不在dev->flags中置IFF_MULTICAST。
點到點接口是一種特殊情況,它們通常接收所有的包,根本不進行任何硬件過濾。
l 能區別選播包和其它包(主機到主機或播送)的接口。這類接口可以被要求
接收所有的選播包,然后用軟件來判斷自己是否是有效的接收者。這種情形引入的開銷
是可以接收的,因為一個典型的網絡中選播包的數量都很少。
l 能夠進行選播地址硬件檢測的接口。可以給這類接口一組需要接收的選播地
址,它們會忽略其它的選播包。這對核心來說是最優化的情況,因為不會浪費處理器事
件去丟棄接口收到的“無意義”的包。
核心試圖利用高級接口的能力,能最好地支持第三類接口(用途最廣)。因此,當有效
的選播地址被改變時核心應通知驅動程序,它把新的一組地址傳給驅動程序,這樣它可
以按照新的信息更新硬件過濾器。
以按照新的信息更新硬件過濾器。
核心對選播的支持
下面是與驅動程序的選播能力相關的數據結構和函數的概括:
void (*dev->set_multicast_list)(struct device *dev)
當與設備相關的機器地址表改變時調用這個設備方法。當dev->flags被修改時它也被調
用,因為有些標志也要求你重新配置硬件過濾器。這個方法接收一個指向device結構的
指針作為參數,返回void。對實現這個方法不感興趣的驅動程序可以留域為NULL。
struct dev_mc_list *dev->mc_list
這是域設備相關的所有選播地址的鏈表。這個結構的實際定義在本節結束時介紹。
int dev->mc_count
鏈表項數。這個信息有點冗余,但檢查mc_count是否為0是優于列表檢查的一個有用的快
捷方式。
IFF_MULTICAST
除非驅動程序在dev->flags中設置了這個標志,接口將不必處理選播包。當dev->flags
改變時,至少set_multicast_list會被調用。
IFF_ALLMULTI
dev->flags中的這個標志被網絡軟件設置以告訴驅動程序從網絡中抽取所有播送包。這
在multicast-routing被使用時發生。如果這個標志被置位,dev->mc_list將不再使用去
過濾選播包。
IFF_PROMISC
當接口被置為雜亂模式時,dev->flags中的這個標志被設置。所有的包都被接口抽取,
不考慮dev->mc_list。
驅動程序開發者需要的最后一點信息是結構dev_mc_list的定義,它居于<linux/netdevi
ce.h>中。
(代碼337)
(代碼337)
由于選播和硬件地址與包的實際發送無關,這個結構可在不同的網絡實現上移植,每個
地址由一串八元組和一個長度確定,就象dev->dev_addr。
一個典型的實現
描述set_multicast_list設計的最號辦法是給出一些偽代碼。
下面的函數是這個函數在一個全特征(ff)驅動程序中的一個典型實現。說這個驅動程序
是全特征的是因為它控制的接口有一個復雜的硬件包過濾器,它可以存放一個由本機接
收的選播地址表。這個表的最大尺寸是FF_TABLE_SIZE。
所由帶有前綴ff_的函數是放置硬件特定操作的地方。
(代碼338)
如果這個接口不能在硬件過濾器中存儲到來包的選播表,那么這個實現還可以簡化。在
這種情況下,FF_TABLE_SIZE減為0,代碼的最后四行也不需要了。
現在,接口板一般不能存儲選播表。不過,這并不是一個大問題,因為網絡代碼的高層
現在,接口板一般不能存儲選播表。不過,這并不是一個大問題,因為網絡代碼的高層
會負責將不需要的包丟棄。
如我前面建議的,即使不能處理選播包的接口也需要實現set_multicast_list方法,這
樣當dev->flags發生改變時可以被通知。我稱這個為“無特征”(nf)的實現。它非常簡
單,如下面所示:
(代碼339)
處理IFF_PROMISC是很重要的,因為不然的話,用戶將無法運行tcpdump或其它一些網絡
分析工具。另一方面,如果接口運行一個點到點的連接,則沒有任何實現set_multicast
_list的必要,因為它們接收所有的包。
快速參考
本節提供在本章中介紹的概念的參考。它也解釋了驅動程序應包含的每個頭文件的作用
。不過,device和sk_buff的每個域的列表,就不再重復了。
#include <linux/netdevice.h>
#include <linux/netdevice.h>
這個頭文件含有struct device的定義,還包含了網絡驅動程序需要的幾個其它頭文件。
void netif_rx(struct sk_buff *skb);
這個函數在中斷時可以被調用通知核心一個包被收到了,并且封裝在一個套接字緩沖區
中。
#include <linux/if.h>
被netdevice.h包含,這個文件聲明接口標志(IFF_macros)和結構ifmap,它在網絡驅動
程序的ioctl實現中用重要的作用。
#include <linux/if_ether.h>
ETH_ALEN
ETH_P_IP
struct ethhdr;
struct enet_statistics;
被netdevice.h包含,if_ether.h定義所有的ETH_macros,用來表示八元組長度(象地址
長度)和網絡協議(象IP)。它也定義了結構ethhdr和enet_statistics。注意,不要看
enet_statistics的名字和包含它的頭文件,事實上,所有的接口都要用到它,不僅僅是
以太網。
#include <linux/skbuff.h>
結構sk_buff和一些相關結構的定義,以及在緩沖區上操作的線入函數。這個頭文件包含
在netdevice.h中。
#include <linux/etherdevice.h>
void ether_setup(struct device *dev);
這個函數為以太網驅動程序設置大多數設備方法為通用目的的實現。它同樣設置dev->fl
ags,并且在名字中的第一個字符是空格或空字符時,將下一個可用的ethx名賦給dev->n
ame。
unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev)
unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev)
當以太網接口收到一個包,這個函數將被調用來設置skb->pkt_type。返回值是一個協議
號,通常被存在skb->protocol中。
#include <linux/sockios.h>
SIOCDEVPRIVATE
這是16個ioctl命令的第一個,可以被每個驅動程序實現以供私用。所有的網絡ioctl命
令都在sockios.h中定義。
--
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -