這次遇到的 VQ issue 頗為棘手 … …
As title, 進行 P2P傳輸的過程中, VQ 會變得較差
如何處理此問題 …
大致上的想法, 流程:
a. 確認哪個版本就會有相同問題 (發現…舊版也有問題)
b. 從 log, packet, abacus 找線索 (Abacus細節: ex: 間隔一段時間會發生VQ變差)
c. kill process (看能否縮小範圍, 看是被哪個 process 影響, ex: tr69 …)
d. 鎖定 process > 確認是哪段 code 造成影響
Learning and Reviewing on this Issue:
a. nf_conntrack
a-1. 打開 BitComet 可以發現 connection count 遽增, 然後可以看到 VQ 變差, delay 變大
a-2. 從這個線索, 想到透過 iptables rule 限制 connection count 遽增 的情況
a-2-1. 方法, 如下 iptables command
Osix_syscmd("iptables -N limit-conntrack");
Osix_syscmd("iptables -A limit-conntrack -p udp -m conntrack --ctstate NEW -m limit --limit 100/s --limit-burst 100 -j RETURN");
Osix_syscmd("iptables -A limit-conntrack -p udp -m conntrack --ctstate NEW -j DROP");
Osix_syscmd("iptables -I FORWARD -p udp -m conntrack --ctstate NEW -j limit-conntrack");
a-2-2. -N: 創建新的Chain -A: Append rule to Chain -p: protocol
a-3. script to monitor nf_conntrack_count
while true; do cat /proc/sys/net/net_filter/nf_conntrack_count; sleep 1; done
b. 如何在 C code 判斷判斷 iptables rule 已經存在
b-1.
Osix_syscmd("iptables-save | grep -- \"limit-conntrack\"; echo $? > /tmp/check_limit_conntrack");
char ret_check_limit_conntrack;
int val_check_limit_conntrack;
FILE *fp;
fp = fopen("/tmp/check_limit_conntrack", "r+");
if (fp == NULL)
{
fprintf(stderr, "open check_limit_conntrack fail\n");
return NULL; // no such file?
}
else
{
ret_check_limit_conntrack = getc(fp);
if(ret_check_limit_conntrack != EOF)
{
val_check_limit_conntrack = ret_check_limit_conntrack - '0';
printf("---[JEDBUG] val_check_limit_conntrack=%d \r\n", val_check_limit_conntrack);
if(val_check_limit_conntrack == 1)
{
printf("---[JEDBUG] val_check_limit_conntrack=%d \r\n", val_check_limit_conntrack);
Osix_syscmd("iptables -N limit-conntrack");
Osix_syscmd("iptables -A limit-conntrack -p udp -m conntrack --ctstate NEW -m limit --limit 100/s --limit-burst 100 -j RETURN");
Osix_syscmd("iptables -A limit-conntrack -p udp -m conntrack --ctstate NEW -j DROP");
Osix_syscmd("iptables -I FORWARD -p udp -m conntrack --ctstate NEW -j limit-conntrack");
}else if (val_check_limit_conntrack == 0){
printf("---[JEDBUG] val_check_limit_conntrack=%d Exists!! \r\n", val_check_limit_conntrack);
}
}
fclose(fp);
}
Note:
1. iptables -N limit-conntrack
// 新建立一條 Chain "limit-conntrack"
2. iptables -A limit-conntrack -p udp -m conntrack --ctstate NEW -m limit --limit 100/s --limit-burst 100 -j RETURN"
a. -m conntrack: 載入 conntrack module
b. --ctstate > ct: Connection Track
c. -m limit --limit 100/s > 1秒可以允許100 connection
d. --limit-burst 100 > 一開始的 100 個 connection 可以被允許, 後面的就要依照 limit 的限制
3. iptables -A limit-conntrack -p udp -m conntrack --ctstate NEW -j DROP"
> 加這條 rule 是因為 … 如果上面的限制已經上限了, 其它的封包怎麼處理, 如果沒有 DROP, 這樣就沒有達到限制的效果了!
b-2. 因為上面的方法, 讀取 /tmp/check_limit_conntrack 的值會是 $, 不符合預期, 所以換個方法
Osix_syscmd("iptables-save | grep -- limit-conntrack > /tmp/check_limit_conntrack");
FILE *fp = NULL;
fp = fopen("/tmp/check_limit_conntrack", "r+");
if (fp == NULL)
{
fprintf(stderr, "open check_limit_conntrack fail\n");
}
else
{
char buffer[256];
char *ret = NULL;
buffer[0] = 0;
fread(buffer, sizeof(buffer), 1, fp);
ret = strstr(buffer, "limit-conntrack");
if(ret == NULL)
{
Osix_syscmd("iptables -N limit-conntrack");
Osix_syscmd("iptables -A limit-conntrack -p udp -m conntrack --ctstate NEW -m limit --limit 100/s --limit-burst 100 -j RETURN");
Osix_syscmd("iptables -A limit-conntrack -p udp -m conntrack --ctstate NEW -j DROP");
Osix_syscmd("iptables -I FORWARD -p udp -m conntrack --ctstate NEW -j limit-conntrack");
}
fclose(fp);
}
Osix_syscmd("rm /tmp/check_limit_conntrack");