iptables: Resource temporarily unavailable.問題
執行iptables規則時失敗,出現錯誤提示 iptables: Resource temporarily unavailable.
問題
出現此種怪問題,第一反應就是:“發生了什麼?我什麼都沒改。沒道理呀。”
Resource temporarily unavailable.的錯誤列印對應錯誤碼EAGAIN,就出叫你出現這個錯了在試一遍的意思。我的感覺是,iptables規則作為系統全域性共享元件,在設定時,核心肯定會有鎖機制來解決併發問題。既然如此,那就寫個指令碼併發iptables試一試看有問題沒。
測試指令碼
#!/bin/sh iptables -t filter -N TESTTTTTTTT1 &iptables -t filter -N TESTTTTTTTT2 & iptables -t filter -N TESTTTTTTTT3 & iptables -t filter -N TESTTTTTTTT4 & iptables -t filter -N TESTTTTTTTT5 & iptables -t filter -N TESTTTTTTTT6 & iptables -t filter -X TESTTTTTTTT1 & iptables -t filter -X TESTTTTTTTT2 & iptables -t filter -X TESTTTTTTTT3 &iptables -t filter -X TESTTTTTTTT4 & iptables -t filter -X TESTTTTTTTT5 & iptables -t filter -X TESTTTTTTTT6 &
指令碼很簡單,建立鏈,然後刪除鏈。每條規則都放後臺執行,執行幾遍就能復現iptables: Resource temporarily unavailable.
的問題。
板子上跑起來有問題,想著虛擬機器跑下試試,虛擬機器跑也有問題,不過虛擬機器會有讓加-w引數的提示:
Another app is currently holding the xtables lock. Perhaps you want to use the -w option? Another app is currently holding the xtables lock. Perhaps you want to use the -w option? Another app is currently holding the xtables lock. Perhaps you want to use the -w option?
這裡已經很明顯的告訴我們,多個程序爭奪xtables lock,iptables執行失敗,可以通過-w引數來讓程序在失敗時wait一下。
修改方法
檢視虛擬機器裡面的iptables版本為1.4.21, 板子裡面的iptables版本為1.4.4,然後下載了1.4.21的原始碼下來
1.4.21的鎖機制
通過建立unix域套接字然後bind來實現,但是我本地測試這段程式碼卻有問題。原因在於:域套接字在程序退出後不會銷燬該套接字對應的檔案,下次bind就會失敗,如果呼叫unlink來處理,套接字檔案又會裡面被清掉,bind總是成功,無法起到鎖的作用。(所以這裡不懂1.4.21這一版的原理究竟是啥)
想來想去,沒什麼好辦法,又下載了最新的iptables原始碼
1.6.1的鎖機制
通過flock實現。查了下flock,發現這就是我需要的。flock鎖的銷燬會隨著檔案描述符銷燬而銷燬,所以即便程序意外退出了,也不用擔心會有鎖殘留的問題。於是可以寫出iptables應用層加鎖的程式碼來:
void xtables_try_lock(void) { int fd; int i = 0; int sleep_time_ms = 50; int wait_time_sec = 10; int wait_cnt = wait_time_sec*1000 / sleep_time_ms; fd = open(XT_LOCK_NAME, O_CREAT, 0600); if (fd < 0) return; for(i = 0; i < wait_cnt; i++) { if(!flock(fd, LOCK_EX | LOCK_NB)) return; usleep(sleep_time_ms * 1000); } printf("## BUG! Another app is currently holding the xtables lock long time!\n"); return; }
把這個鎖放在iptables就ok了。