作業系統:Debian 3(核心2.6.8-2-686-smp)
網卡:四塊網卡,驅動程式為e1000(e1000.ko)
應用程式:在其中一塊或者多塊網卡上啟動heartbeat(向多點傳播位址發包)
現象:heartbeat綁在ethx發送多點傳播,然而ethx沒有插網線,網卡口本身狀态up,此時modprobe ip_conntrack,然後rmmod ip_conntrack,rmmod将會阻塞,通過ps檢視它是running狀态,發送SIGKILL給它也不行,此時隻需要在ethx插上網線或者ifdown ethx,rmmod方可傳回(此中ethx可以代表多個網卡口,若代表多個網卡,那麼必須這幾個網卡都插上線或者都ifdown了才可以);
分析過程:使用别的網卡是沒有這個現象的,我的意思是說在别的不使用e1000驅動的網卡的機器上是沒有這個問題的,另外不啟動多點傳播也是沒有問題的,是以問題肯定在網卡驅動群組播。
核心代碼情況:在ip_conntrack_core.c中有ip_conntrack_cleanup函數,肯定是在該函數中死循環了,因為/proc/net/ip_conntrack檔案已經沒有了,故而proc_net_remove("ip_conntrack")調用是成功的,按照下面的序列:
cleanup_proc:
proc_net_remove("ip_conntrack");
cleanup_init:
ip_conntrack_cleanup();
cleanup_nothing:
return ret;
則肯定是ip_conntrack_cleanup的問題:
void ip_conntrack_cleanup(void)
{
ip_ct_attach = NULL;
synchronize_net();
i_see_dead_people:
ip_ct_selective_cleanup(kill_all, NULL);
if (atomic_read(&ip_conntrack_count) != 0) { //1
schedule();
goto i_see_dead_people;
}
while (atomic_read(&ip_conntrack_untracked.ct_general.use) > 1) //2
kmem_cache_destroy(ip_conntrack_cachep);
vfree(ip_conntrack_hash);
nf_unregister_sockopt(&so_getorigdst);
}
該函數中有兩個循環,一個是1處,一個是2處,經調試是1處死循環了,結果是ip_conntrack_count這個計數器一直是1,然而ip_ct_selective_cleanup中的:
while ((h = get_next_corpse(kill, data, &bucket)) != NULL)
其h傳回卻是NULL,進一步跟蹤發現get_next_corpse是從ip_conntrack_hash中找資料的,而ip_conntrack_hash中的資料是在ip_confirm被加入的,也就是說在一個資料包必須離開核心的時候才會将其ip_conntrack加入到ip_conntrack_hash,然而ip_conntrack_count計數器卻是在init_conntrack中被遞增的,也就是在資料包剛進入核心的時候被遞增的,這就在ip_conntrack_hash的更新和ip_conntrack_count的更新之間留下了一個時間段,不過這個時間段不要緊,核心并不保證ip_ct_selective_cleanup中的ip_conntrack_hash周遊的數目一定要和ip_conntrack_count完全一緻,也就是說,一個ip_conntrack可以已經由于它的存在遞增了ip_conntrack_count,但是它可以不加入ip_conntrack_hash哈希表,這樣不會有任何問題,這是因為在ip_ct_selective_cleanup中周遊ip_conntrack_hash表,然後依次調用ip_conntrack_put來降之destroy掉,如果哈希表中沒有的ip_conntrack則可以在别的核心路徑調用ip_conntrack_put來destroy掉,進而在destroy中遞減ip_conntrack_count這個計數器,最終肯定在ip_conntrack_cleanup中會得到計數器ip_conntrack_count成為0的資訊,最終從i_see_dead_people這個不吉利的循環中出來。
現在的問題就是為何在使用e1000驅動并且沒有插網線發送多點傳播的情況下(資料肯定發不出去),解除安裝ip_conntrack子產品的時候沒有任何核心路徑調用ip_conntrack_put來釋放這個遊離的ip_conntrack,另外為何會有一個遊離的ip_conntrack沒有加入到ip_conntrack_hash哈希表卻已經存在了,也即是它還沒有準備從核心出去!此時,隻要一插網線(在多點傳播相關的所有網卡上插一下網線,哪怕插一下再拔下也行)或者ifdown所有的多點傳播相關的網卡,一個ip_conntrack_put将被調用釋放掉最後的那個遊離ip_conntrack結構,遞減掉最後的那個1,最終解除安裝ip_conntrack子產品完成。
目前沒有時間來調試e1000的驅動,我覺得問題十有八九出在這個驅動裡面,可能需要網卡工具對網卡設定一下什麼的。
本文轉自 dog250 51CTO部落格,原文連結:http://blog.51cto.com/dog250/1271145