在linux中執行ifconfig XYZ命令會得到一大堆資訊,唯獨沒有XYZ網路介面的速率,雙工狀態等資訊,這合理嗎?如果用慣了windows,那麼就會覺得這個命令的輸出確實少了一些什麼,可是windows的ipconfig能得到這些資訊嗎?同樣的也不能,windows網卡的速率雙工資訊是在“控制台->網路連接”中選擇具體網卡然後雙擊後看到的,並且此時只能看到速率,要查看雙工資訊則必須點擊“屬性”然後點擊最上面網卡名稱旁邊的“配置”,之後點擊“進階”選項卡,然後慢慢找吧,看起來很混亂,實際上也很混亂,速率/雙工資訊到底是網卡的配置屬性還是內秉屬性?本地串連狀態下面的屬性中包含有網卡的內秉屬性和配置屬性兩種,內秉屬性可以理解成是鏈路層和物理層的屬性,而配置屬性可以理解成網路層的屬性,看起來很合理,這麼說來,linux的ifconfig輸出倒是有點亂了,既有網卡物理地址資訊又存在ip地址資訊,還有一些別的資訊,確實,linux的ifconfig就是有點亂,如果你在一個網卡上配置了多個ip地址,那麼用ifconfig命令是看不到的,而只能看到你最後配置的那個主ip地址,因此ifconfig命令的輸出並不是很合理,如果想得到更合理的輸出,請使用ip命令。我感覺ifconfig命令就是一個大雜燴,它幾乎是萬能的,卻又極其不容易使用,現在的問題很明確,那就是設定一下網卡的速率和雙工模式,請問用ifconfig怎麼設定,很搞笑的是,ifconfig雖然預設不顯示這些和網卡mac並列的內秉資訊,但是卻可以設定它們,比如用media選項,參數分別是10base2,10baseT,AUI等等,不像在windows中直接點擊網卡的配置,然後點擊進階選項卡,之後就可以自由設定這些參數了。linux的ifconfig雖然不太適合設定這些參數,但是它卻擁有一個強大的工具來搞定這一切,這就是mii-tool和ethtool,這裡並不區分這二者,它們實現的功能是很類似的。
MII的全稱是Media Independent Interface,字面意思上就是媒體無關的介面,因此它是獨立於具體裝置的,仔細想想標準化的東西都是獨立於具體裝置的。雖然如此,很多乙太網路卡裝置並不支援這些參數的配置,因此當你執行mii-tool的時候,會得到Operation not supported的提示,這是很合理的,因為這些參數的設定以極其功能並不是軟體意義上的,而是硬體意義上,如果網卡上根本就沒有相關的寄存器換句話說網卡根本就沒有智能到支援自動協商雙工模式的地步,你又如何去設定雙工模式呢,或者你如何能讓兩個人同時渡過獨木橋呢?實際上諸如雙工模式的設定這種功能並不是必須的,因此對於軟體來講如果硬體沒有實現那麼完全不必去用軟演算法類比之,對於上層應用來講,底層的雙工模式以及速率是完全透明的,這些概念只是功能意義上的,而不是介面意義上的。並不是所有的介面都能讓你去隨意設定速率和雙工模式。可以這麼認為,MII是一些比較智能的高速乙太網路卡為了彼此相容或者說為了相容弱者而設定的一個自協商機制。
可不要被上面說的嚇壞以為mii-tool的代碼有多麼複雜,事實上它卻很簡單,該工具的源碼很大的份額是在處理使用者選項以及組合這些選項,除此之外就沒有別的邏輯了,最終設定的時候i就是一個ioctl,核心會用vfs將這個ioctl路由到最終的裝置,如果裝置不支援mii,那麼就直接返回一個“不支援”錯誤,然後返回,更簡單的是,核心原始碼本身的ioctl架構中就有一個SIOCETHTOOL標誌來直接支援諸如速率和雙工模式的協商方式配置,具體到裝置的話就是簡單的對特定的寄存器進行read和write操作,十分簡單,既然如此,你就不要指望在核心源碼的net_device結構體當中找到關於這些參數的欄位了,它們不可能在這個如此抽象又如此重要的結構體中的,畢竟很多網路裝置是沒有這些概念的,因此它們最佳的位置應該在net_device的private欄位中,我的意思是說它們在private中並不一定就是在private所代表的結構中,還很有可能藏在更加隱形結構體的包含結構體之中,討論這個已經沒什麼意義了。
想虛擬網卡之類的驅動程式有必要實現這些配置嗎?根本就沒有必要,因為虛擬網卡進出的資料根本就不是在“線路”上跑的,既然沒有真正的“線路”那麼這些關於線路的配置當然就是不需要的了,實際上速率和雙工模式都是關於線路的配置,速率和模式和線路介質的導電性,訊號衰減率,抗幹擾係數都有關係,本機進出的虛擬網卡設定這些有意義嗎?再次重申,這些東西不是“介面”意義上的,而是功能配置意義上的,它們也不是標準化的必須實現的,它們的存在是為了也僅僅是為了使得物理層更加有效率,在調用介面上完全和上面的N個層次戛然分離。
在OpenVPN中有一個--txqueuelen n重要的參數,它可以被理解成速率,只是它不是線路的速率而是和介面發送相關的,核心中的net_device中有一個tx_queue_len欄位,表示在發送前,發送隊列可以積壓多少資料包,如果該值過於小,那麼應用程式層發送過快的話,資料就會被drop掉,這也是值得關注的。還是以linux的tun裝置為例,tun_net_xmit中有下列程式碼片段:
if (!(tun->flags & TUN_ONE_QUEUE)) {
if (skb_queue_len(&tun->readq) >= TUN_READQ_SIZE)
netif_stop_queue(dev);
} else {
if (skb_queue_len(&tun->readq) >= dev->tx_queue_len)
goto drop;
}
skb_queue_tail(&tun->readq, skb);