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;

Reply via email to