2014-01-30 64 views
1

PLease告訴我的問題。我正在構建基於CentOS x86_64,Linux版本2.6.32-431.3.1.el6.x86_64的流量整形器。所以它有大約10個u32哈希表,全部有256個除數。在缺省表800中,我散列第3個八位字節並將分組指向這個表中的一個,然後將第4個八位字節和點分組散列到描述每個用戶帶寬限制的類。所以,對於每個IP地址都有一個相應的tc類。我們很容易塑造大約3000個IP地址。當我的腳本將這些IP添加到散列表中時,我得到一個錯誤:RTNETLINK的答案是:文件存在。更多代碼在這裏:Linux tc,u32過濾奇怪的錯誤

tc qdisc add dev $inet root handle 2: htb default 8000 
tc class add dev $inet parent 2: classid 2:6000 htb rate 100mbit 

#this hash-tables are for subnets 
for i in {901..912}; do 
tc filter add dev $inet parent 2: handle $i: protocol ip u32 divisor 256 
done 
#adding filters for packet classifying 
tc filter add dev $inet protocol ip parent 2: u32 ht 800:: match ip src 172.16.16.0/20 hashkey mask 0x0000ff00 at 12 link 901: 
tc filter add dev $inet protocol ip parent 2: u32 ht 901:11: match ip src 172.16.17.0/24 hashkey mask 0x000000ff at 12 link 902: 
tc filter add dev $inet protocol ip parent 2: u32 ht 901:12: match ip src 172.16.18.0/24 hashkey mask 0x000000ff at 12 link 903: 
#... 
#and so on under "link 912:" 

#creating classes for every host, place it under root class 2: (100mb for all) 
for i in {1..2815}; do tc class add dev $inet parent 2:6000 classid 2:$i htb rate 1mbit ceil 6mbit; done 

#place each host in corresponding u32 table 
for i in {1..255}; do printf -v hi "%x" "$i"; 
tc filter add dev $inet protocol ip parent 2: u32 ht 902:$hi: match ip src 172.16.17.$i flowid 2:$i 
done 
for i in {256..511}; do let j="i-256"; printf -v hi "%x" "$j"; 
tc filter add dev $inet protocol ip parent 2: u32 ht 903:$hi: match ip src 172.16.18.$j flowid 2:$i 
done 
#.... 
#and so on under 2815 hosts 

而且某處命令後結束

tc filter add dev eth0 protocol ip parent 2: u32 ht 909:dc: match ip src 172.16.24.220 flowid 2:2012 
RTNETLINK answers: File exists 
We have an error talking to the kernel 

我解決不了這個問題,我認爲有在Linux內核中的過濾器數量的限制,但有些人說我這不是真的,根本沒有限制。沒有flowid重用,並且沒有哈希表處理超限。還有什麼可以導致代碼中的這個錯誤?

回答

0

我用兩個其他內核重新創建了這個問題;現代的Ubuntu 12.04 3.5.0-39-通用的x86_64內核和舊的Fedora 2.6.33.3-85 i686內核。它們出現在它們兩個上。

一些u32過濾器文檔在這裏:http://ace-host.stuart.id.au/russell/files/tc/doc/cls_u32.txt表明過濾器句柄的最後一部分(過濾器項)應該高達十六進制0xFFF,即4096(例如901:0:0到901:0:FFF)。當您手動添加過濾器時,這是正確的。但是,當使用散列添加過濾器時,您需要指定散列表和存儲區,但過濾器ID是自動創建的。

麻煩的是,自動創建時,過濾器項從800開始,這意味着實際上只能獲得0x800到0xFFE過濾器(總共2048個)。

你可能會認爲,你可以切換哈希表每2048和過濾器可以添加,因爲你在你的例子都做了,但事實並非如此 - 它仍然會只允許你在總散列時加2048米的過濾器。我不確定這種行爲是一個錯誤,一個限制,還是設計中存在。

爲了解決這個問題,您可以手動指定過濾器項目ID,方法是將其放置在u32過濾器聲明之前,它必須具有零散列表和桶ID。這將允許您添加完整的4096過濾器,其中涵蓋了您的子網聲明。它似乎也允許爲每個哈希表添加4096個過濾器,以便通過鏈接到另一個哈希表來添加更多的過濾器。腳本的最後一部分將需要是這樣的:


#place each host in corresponding u32 table 
for i in {1..255}; do 
    printf -v hi "%x" "$i"; 
    tc filter add dev $inet protocol ip parent 2: handle ::$hi u32 ht 902:$hi: match ip src 172.16.17.$i flowid 2:$i 
done 

for i in {256..511}; do 
    let j="i-256"; 
    printf -v hi "%x" "$i"; 
    printf -v hj "%x" "$j"; 
    tc filter add dev $inet protocol ip parent 2: handle ::$hi u32 ht 903:$hj: match ip src 172.16.18.$j flowid 2:$i 
done 
#.... 
#and so on under 2815 hosts

這是我測試的代碼,這是你的一樣,但我重組它僅使用一個哈希表。它應該具有相同的效率。它僅散列到最後一個八位組中的所需存儲桶,然後按順序匹配存儲桶中的過濾器,而不是順序匹配並鏈接到子網,然後散列到存儲桶。


#!/bin/bash 

inet='eth0' 

# Delete any existing traffic shaping 
tc qdisc del dev $inet root 
tc qdisc add dev $inet root handle 2: htb default 8000 
tc class add dev $inet parent 2: classid 2:6000 htb rate 100mbit 

# Create a single hash table (901) with 256 buckets 
tc filter add dev $inet parent 2: handle 901: protocol ip u32 divisor 256 

# Direct traffic from 172.16.16.0 - 172.16.31.255 to link 901, hash on last octet of src ip 
tc filter add dev $inet protocol ip parent 2: u32 ht 800:: match ip src 172.16.16.0/20 hashkey mask 0x000000ff at 12 link 901: 

# Create classes for each host, place it under root class 2: (100mb for all) 
for i in {1..2815}; do 
    hex_handle=$(echo "obase=16; $i" | bc) 
    tc class add dev $inet parent 2:6000 classid 2:$hex_handle htb rate 1mbit ceil 6mbit || exit 1; 
done 

# Add filters for each possible host 
for y in {16..27}; do 
    for x in {1..255}; do 
     j=$(((($y - 16) * 255) + $x)); 
     hex_bucket=$(echo "obase=16; $x" | bc) 
     hex_handle=$(echo "obase=16; $j" | bc) 
     tc filter add dev $inet protocol ip parent 2: handle ::$hex_handle u32 ht 901:$hex_bucket match ip src 172.16.$y.$x flowid 2:$hex_handle || exit 1; 
    done 
done