使用 ethtool 時需要指定一個網絡接口名稱,這個名字究竟是在哪裏被使用的呢?
ethtool 命令中對網絡設備名的使用
ethtool 程序會將用戶指定的網絡設備名拷貝到一個 ctx 中,這個 ctx 被用來構建 ioctl 執行的環境。從 ctx.devname ----> ctx.ifr.ifr_name。
ctx.ifr 最終作爲 ioctl 系統調用的參數傳遞給內核。
ifr_name 在內核中的什麼地方被使用呢
在 dev_ioctl 中有如下代碼:
case SIOCETHTOOL:
dev_load(net, ifr->ifr_name);
rtnl_lock();
ret = dev_ethtool(net, ifr);
rtnl_unlock();
if (colon)
*colon = ':';
return ret;
ethtool 調用的 ioctl 最終是在上述代碼中執行的。在上面的代碼中 dev_load
首先使用 ifr_name 在網絡設備接口不存在的情況下加載相應的模塊,只有當用
戶具有需要的權限之後才能加載成功。
這之後 ifr_name 在 dev_ethtool 中被再次使用。相關的代碼如下:
struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
這裏通過 ifr_name 來檢索到對應的 netdev 設備。成功則會獲取到一個 net_device 結構。
net_device 結構中的 ethtool_ops 成員
在 net_device 結構中我們可以發現如下的成員:
const struct ethtool_ops *ethtool_ops;
ethtool_ops 是 ethtool 類的虛函數表,ethtool 命令最終就是通過調用這個虛函數表中的函數來工作的。
ethtool 與面向對象
這裏也是面向對象思想的一個應用。
ethtool 可以看作一個超類,ethool_ops 這個虛函數表中定義了子類能夠重載的函數集合。不同的 netdev 設備使用不同的驅動,驅動中實現自己的 ethtool 相關函數並填充到一個虛函數表中。在設備初始化的過程中通過 SET_ETHTOOL_OPS 這個宏來綁定不同的虛函數表,完成對 ethtool 子類的實例化。
net/core/ethtoo.c
內核源碼 net/core/ethtool.c 中提供了一個適配層,實現了一系列 ethtool_xxx 函數,這些函數統一了 ethtool 的調用方式,它們並不關心 dev->ethtool_ops 到底被誰實現,只需要在函數指針存在的情況下調用即可,這樣便屏蔽了不同 netdev 中 ethtool_ops 的區別,實現了類似 c++ 中的重載功能。