網路裝置(network device)
網路卡是裝置中的異類:你不會像對檔案那樣透過 /dev 對它 read() 或 write(),也沒有 /dev/eth0 可開。取而代之,它是封包進出機器的一道門。網路裝置是核心對網路介面的模型——一個 struct net_device——而它的驅動程式整個工作是在硬體與核心網路堆疊之間搬移封包,而不是在應用程式與檔案之間搬移位元組。
驅動程式向核心註冊一個 net_device,並提供如 ndo_open、ndo_stop、ndo_start_xmit(傳送)等操作。在傳送端,當 IP 堆疊有封包要送出時,它以一個 sk_buff(socket buffer,核心的封包容器)呼叫驅動程式的傳送函式;驅動程式把該緩衝區的資料交給網卡,通常是透過設定一個 DMA 描述符。在接收端,封包到達時網卡發出中斷;驅動程式(今日通常透過 NAPI)從網卡的接收環取出封包、把每個包進一個 sk_buff,再用如 netif_receive_skb 的呼叫往上推進堆疊。應用程式從不直接碰裝置——它們用通訊端,而核心的 TCP/IP 程式碼夾在中間。
網路裝置之所以重要,是因為它是對效能最敏感的驅動程式類別:一張快卡每秒可遞送數百萬個封包,所以接收路徑被大幅最佳化(這正是 NAPI 存在的原因)。一個常見的誤解是以為你像對字元裝置那樣對網卡溝通;其實不然。沒有位元組串流的檔案介面——抽象是封包進、封包出,而驅動程式對網路子系統溝通,透過 ip、ethtool 等工具設定,而非透過裝置節點。
static const struct net_device_ops my_ops = { .ndo_open = my_open, // 把介面拉起 .ndo_stop = my_stop, // 把它關閉 .ndo_start_xmit = my_xmit, // 送出一個 sk_buff }; // 沒有 /dev 節點;透過下列設定: $ ip link set eth0 up
網路驅動程式提供的是封包操作,而非檔案 read/write;它沒有裝置節點,透過 ip/ethtool 設定。
網卡沒有 /dev 節點,也沒有位元組串流的檔案介面;你不會對它 read()/write()。它的模型是透過 sk_buff 封包進、封包出,與網路堆疊溝通,而非與 VFS 溝通。