歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> 關於Linux >> Linux bonding的初始狀態問題以及解決

Linux bonding的初始狀態問題以及解決

日期:2017/3/1 17:01:55   编辑:關於Linux
Linux bonding的初始狀態問題以及解決 問題: 啟動一個bonding網卡,往其裡面添加兩個根本就沒有插著網線的網卡,拉起該bonding後,ifconfig發現其有RUNNING標志,然後將其一個slave插上網線再拔掉,ifconfig就沒有RUNNING標志了。 分析: www.2cto.com 這個問題實際上無傷大雅,只是在第一次欺騙一下OS而已,然而卻會影響到keepalived的track_interfaces配置,進而影響基於VRRP的熱備切換,導致擁有沒有插著網線的機器的熱備組中的若干台機器一旦重啟,其熱備狀態就會混亂。沒有插線的機器無論如何也不能是MASTER,可是keepalived看到了bonding網卡的RUNNING標志,誤認為其已經可以使用,進而可能成為MASTER狀態。 解析與修正: 如果僅僅為了短平快的解決當下問題,那麼最簡單不過的就是將keepalived中基於RUNNING的判斷換成基於LOWER_UP的判斷,LOWER_UP就是標識網卡有沒有插線的(但不絕對,還可能受別的因素影響,但是大多數情況-顯然並非全部情況下可以這麼認為),事實證明這是完全可以的,問題解決了。但是卻違反了track_interfaces的初衷,因此這種改法不好! www.2cto.com 在徹底修正這個問題之前還是需要了解網卡的各種狀態以及層次。總體來講,網卡state分為管理state和操作state。 管理state:這個狀態是自上而下配置的,表示管理員的意願 操作state:這個state是網卡自身現狀,表示網卡目前是否已經准備好並且有能力為用戶服務。 現在看看Linux系統中網卡的各種state: IFF_LOWER_UP-線纜已經接好且上電 IFF_RUNNING-操作state是UP(那麼什麼時候操作state會是DOWN呢?1.在管理state為DOWN的時候,即管理員用命令down了網卡;2.網卡沒有插線 理解了這些狀態之後,即使沒有keepalived,狀態也不會,這就不是熱備切換的問題了,keepalived並沒有錯,即便是修正了keepalived,那麼bonding還是會影響到其它使用它的程序的...正是bonding驅動的bug導致了狀態判斷錯誤。 bond_open的返回值是0,因此bonding網卡默認就是START狀態的,因為在物理網卡enslave進bonding網卡的時候需要bonding網卡是IF_UP狀態的。可以在bond_enslave的最後看到一個頻繁調用的函數:bond_set_carrier。該函數判斷bonding網卡的所有slave的狀態,如果全部為DOWN,則將bonding本身也設置成DOWN。這應該是一個周期調用的函數,調用周期取決於bonding的miimon參數,另外在幾個關鍵點也會調用bond_set_carrier,比如在新的slave被bongding的時候,即調用bond_enslave的時候。基本上bond_set_carrier的邏輯是這樣的: [cpp] static int bond_set_carrier(struct bonding *bond) { struct slave *slave; int i; if (bond->slave_cnt == 0) goto down; if (bond->params.mode == BOND_MODE_8023AD) return bond_3ad_set_carrier(bond); //遍歷所有的slave,只要有一個UP,那麼bonding就UP bond_for_each_slave(bond, slave, i) { if (slave->link == BOND_LINK_UP) { if (!netif_carrier_ok(bond->dev)) { netif_carrier_on(bond->dev); return 1; } return 0; } } down: if (netif_carrier_ok(bond->dev)) { netif_carrier_off(bond->dev); return 1; } return 0; } 沒有任何問題。在周期性檢測中,會設置所有slave的狀態: [cpp] bond_for_each_slave(bond, slave, i) { slave->new_link = BOND_LINK_NOCHANGE; link_state = bond_check_dev_link(bond, slave->dev, 0); switch (slave->link) { case BOND_LINK_UP: if (link_state) continue; //將狀態設置為FAIL,此後再調用bond_set_carrier時可能會off掉bonding網卡 slave->link = BOND_LINK_FAIL; ... 到底哪裡出了問題??為何一塊物理網卡明明是沒有插線的,卻沒有調到bond_set_carrier最後面的netif_carrier_off,原因很顯然了,因為netif_carrier_ok判斷沒有通過,為何沒有通過,原因在於bonding自創建之日,其state根本就沒有涉及__LINK_STATE_NOCARRIER這個bit的初始化!什麼?這等錯誤竟然在內核裡面出現!改了它便是,在bond_open的最後,return 0之前,加上一句: [cpp] netif_carrier_on(bond->dev); 即可修正這個錯誤。另外要修改的是bond_set_carrier函數: [cpp] www.2cto.com if (bond->slave_cnt == 0) goto down; 如果slave_cnt為0,那麼就要調用netif_carrier_on將bonding拉起來,以便於後面往其加入新的slave,那麼上述語句改為: if (bond->slave_cnt == 0) { netif_carrier_on(bond->dev) goto down; } 關於這個修改,我只是為了保險起見,實質上並無必要,到底有沒有必要進行這個修改,我並沒有實測過,話說只要初始狀態正確,後面的只是按照既有的邏輯來過,不可能有任何問題,話雖如此,可我還是不信任kernel社區的這幫人,要不然怎麼會忘記初始化carrier狀態呢? www.2cto.com 插曲: 這個問題是我項目中遇到的,因為要趕工期,領導決定先把這個問題放一下,抓緊主要問題解決,我因此也和領導有了一次沖突,因為我覺得做一個產品,真的就需要完美無缺,不能有遺留問題等到用戶真的需要的時候再解決,寧可延期也要完美,這是我的邏輯,至於說我為何沒有把這事情分發下去,是因為到了產品發布的最後關頭,正如領導說的,誰熟悉什麼誰做什麼,我自認為在項目組對網絡,對kernel比較熟悉,因此這個問題只有我能快速解決,如果說我因為解決這個問題而耽誤了項目進度,那是我的錯,因此我選擇在工作時間外加班解決它,這是我回到家裡搞定的,也只能這樣才能保證產品的按期發布。關鍵問題是,到底應該以產品發布的時間點為准呢還是應該以產品的完美程度為准。我選擇後者,你們呢?
Copyright © Linux教程網 All Rights Reserved