2014-01-30 45 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