Package: iproute Version: 20051007-2.1 Severity: important Tags: patch The hashing algorithm for u32 buckets changed in the kernel between 2.4 and 2.6. In 2.4 it was an xor of all bytes of the hash value. In 2.6 the hash is just least significant 8 bits of the hashed value. cf. the function u32_hash_fold in kernel-source.x.y.z/net/sched/cls_u32.c. It implements the hashing function.
The "sample" clause of tc is meant to calculate this hash value for you. However it only calculates the 2.4 version, not the 2.6 one. Consequently, any u32 filter installed using the tc "sample" clause on 2.6 doesn't work. The attached patch fixes the problem so tc will work in both 2.4 and 2.6. The bug is present in cvs upstream. (Are you sending the patches upstream? If not let me know and I will.) -- System Information: Debian Release: 3.1 Architecture: i386 (i686) Kernel: Linux 2.6.15-3.1-lube-686-smp Locale: LANG=en_AU, LC_CTYPE=en_AU (charmap=ISO-8859-1) Versions of packages iproute depends on: ii libatm1 2.4.1-17 shared library for ATM (Asynchrono ii libc6 2.3.2.ds1-22 GNU C Library: Shared libraries an -- no debconf information
diff -Nur iproute-20051007.keep/tc/f_u32.c iproute-20051007/tc/f_u32.c --- iproute-20051007.keep/tc/f_u32.c 2006-01-12 17:34:37.000000000 +1000 +++ iproute-20051007/tc/f_u32.c 2006-02-07 17:10:29.000000000 +1000 @@ -17,6 +17,7 @@ #include <syslog.h> #include <fcntl.h> #include <sys/socket.h> +#include <sys/utsname.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> @@ -874,6 +875,7 @@ htid = (handle&0xFFFFF000); } else if (strcmp(*argv, "sample") == 0) { __u32 hash; + struct utsname utsname; struct { struct tc_u32_sel sel; struct tc_u32_key keys[4]; @@ -889,8 +891,19 @@ return -1; } hash = sel2.sel.keys[0].val&sel2.sel.keys[0].mask; - hash ^= hash>>16; - hash ^= hash>>8; + uname(&utsname); + if (strncmp(utsname.release, "2.4.", 4) == 0) { + hash ^= hash>>16; + hash ^= hash>>8; + } + else { + __u32 mask = sel2.sel.keys[0].mask; + while (mask && !(mask & 1)) { + mask >>= 1; + hash >>= 1; + } + hash &= 0xFF; + } htid = ((hash<<12)&0xFF000)|(htid&0xFFF00000); sample_ok = 1; continue;