summaryrefslogtreecommitdiffstats
path: root/tc/f_u32.c
diff options
context:
space:
mode:
authorshemminger <shemminger>2006-03-14 19:36:31 +0000
committershemminger <shemminger>2006-03-14 19:36:31 +0000
commit3925ad811940c391dee973dd2f842c7b322556ef (patch)
treea9dce770e62dff040000a3ad57de1832abd5fdda /tc/f_u32.c
parent40b6c62c6373a4dd4191078fdc6a2994792b2cb6 (diff)
Fixes for tc hash sample.
Diffstat (limited to 'tc/f_u32.c')
-rw-r--r--tc/f_u32.c33
1 files changed, 28 insertions, 5 deletions
diff --git a/tc/f_u32.c b/tc/f_u32.c
index eedb0928..8af8e900 100644
--- a/tc/f_u32.c
+++ b/tc/f_u32.c
@@ -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>
@@ -34,7 +35,7 @@ static void explain(void)
fprintf(stderr, "or u32 divisor DIVISOR\n");
fprintf(stderr, "\n");
fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n");
- fprintf(stderr, " SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark } SAMPLE_ARGS\n");
+ fprintf(stderr, " SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark } SAMPLE_ARGS [divisor DIVISOR]\n");
fprintf(stderr, " FILTERID := X:Y:Z\n");
}
@@ -834,7 +835,7 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char **
unsigned divisor;
NEXT_ARG();
if (get_unsigned(&divisor, *argv, 0) || divisor == 0 ||
- divisor > 0x100) {
+ divisor > 0x100 || (divisor - 1 & divisor)) {
fprintf(stderr, "Illegal \"divisor\"\n");
return -1;
}
@@ -874,6 +875,8 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char **
htid = (handle&0xFFFFF000);
} else if (strcmp(*argv, "sample") == 0) {
__u32 hash;
+ unsigned divisor = 0x100;
+ struct utsname utsname;
struct {
struct tc_u32_sel sel;
struct tc_u32_key keys[4];
@@ -888,10 +891,30 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char **
fprintf(stderr, "\"sample\" must contain exactly ONE key.\n");
return -1;
}
+ if (*argv != 0 && strcmp(*argv, "divisor") == 0) {
+ NEXT_ARG();
+ if (get_unsigned(&divisor, *argv, 0) || divisor == 0 ||
+ divisor > 0x100 || (divisor - 1 & divisor)) {
+ fprintf(stderr, "Illegal sample \"divisor\"\n");
+ return -1;
+ }
+ NEXT_ARG();
+ }
hash = sel2.sel.keys[0].val&sel2.sel.keys[0].mask;
- hash ^= hash>>16;
- hash ^= hash>>8;
- htid = ((hash<<12)&0xFF000)|(htid&0xFFF00000);
+ 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%divisor)<<12)|(htid&0xFFF00000);
sample_ok = 1;
continue;
} else if (strcmp(*argv, "indev") == 0) {