diff options
-rw-r--r-- | include/utils.h | 1 | ||||
-rw-r--r-- | lib/utils.c | 35 | ||||
-rw-r--r-- | tc/f_u32.c | 61 |
3 files changed, 64 insertions, 33 deletions
diff --git a/include/utils.h b/include/utils.h index 7223a10d..5daed6b3 100644 --- a/include/utils.h +++ b/include/utils.h @@ -74,6 +74,7 @@ extern int get_addr_1(inet_prefix *dst, const char *arg, int family); extern int get_prefix_1(inet_prefix *dst, char *arg, int family); extern int get_addr(inet_prefix *dst, const char *arg, int family); extern int get_prefix(inet_prefix *dst, char *arg, int family); +extern int mask2bits(__u32 netmask); extern int get_integer(int *val, const char *arg, int base); extern int get_unsigned(unsigned *val, const char *arg, int base); diff --git a/lib/utils.c b/lib/utils.c index 84948513..d99deacd 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -47,27 +47,18 @@ int get_integer(int *val, const char *arg, int base) return 0; } -/* a valid netmask must be 2^n - 1 */ -static int is_valid_netmask(const inet_prefix *addr) -{ - uint32_t host; - - if (addr->family != AF_INET) - return 0; - - host = ~ntohl(addr->data[0]); - - return (host & (host + 1)) == 0; -} - -static unsigned cidr(const inet_prefix *addr) +int mask2bits(__u32 netmask) { unsigned bits = 0; - u_int32_t mask; + __u32 mask = ntohl(netmask); + __u32 host = ~mask; - for (mask = ntohl(addr->data[0]); mask; mask <<= 1) - ++bits; + /* a valid netmask must be 2^n - 1 */ + if ((host & (host + 1)) != 0) + return -1; + for (; mask; mask <<= 1) + ++bits; return bits; } @@ -79,11 +70,13 @@ static int get_netmask(unsigned *val, const char *arg, int base) return 0; /* try coverting dotted quad to CIDR */ - if (!get_addr_1(&addr, arg, AF_INET)) { - if (is_valid_netmask(&addr)) + if (!get_addr_1(&addr, arg, AF_INET) && addr.family == AF_INET) { + int b = mask2bits(addr.data[0]); + + if (b >= 0) { + *val = b; return 0; - - *val = cidr(&addr); + } } return -1; @@ -473,7 +473,7 @@ done: *argv_p = argv; return res; } - + static int parse_ip6(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) { int res = -1; @@ -564,6 +564,7 @@ done: return res; } + static int parse_icmp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) { int res = -1; @@ -771,7 +772,47 @@ static int parse_hashkey(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) return 0; } -static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n) +static void show_key(FILE *f, const struct tc_u32_key *key) +{ + char abuf[256]; + + if (show_raw) + goto raw; + + switch (key->off) { + case 12: + case 16: { + int bits = mask2bits(key->mask); + if (bits >= 0) { + fprintf(f, "\n %s %s/%d\n", + key->off == 12 ? "src" : "dst", + inet_ntop(AF_INET, &key->val, abuf, sizeof(abuf)), + bits); + return; + } + } + break; + + case 20: + case 22: + if (key->mask == ntohl(0xffff)) { + fprintf(f, "\n %s %u\n", + key->off == 20 ? "sport" : "dport", + (unsigned short) ntohl(key->val)); + return; + } + } + +raw: + fprintf(f, "\n match %08x/%08x at %s%d", + (unsigned int)ntohl(key->val), + (unsigned int)ntohl(key->mask), + key->offmask ? "nexthdr+" : "", + key->off); +} + +static int u32_parse_opt(struct filter_util *qu, char *handle, + int argc, char **argv, struct nlmsghdr *n) { struct { struct tc_u32_sel sel; @@ -966,7 +1007,8 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, int argc, char ** return 0; } -static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 handle) +static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, + __u32 handle) { struct rtattr *tb[TCA_U32_MAX+1]; struct tc_u32_sel *sel = NULL; @@ -1037,17 +1079,12 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __ } if (sel) { - int i; - struct tc_u32_key *key = sel->keys; if (sel->nkeys) { - for (i=0; i<sel->nkeys; i++, key++) { - fprintf(f, "\n match %08x/%08x at %s%d", - (unsigned int)ntohl(key->val), - (unsigned int)ntohl(key->mask), - key->offmask ? "nexthdr+" : "", - key->off); + int i; + for (i=0; i<sel->nkeys; i++) { + show_key(f, sel->keys + i); if (show_stats && NULL != pf) - fprintf(f, " (success %lld ) ", + fprintf(f, " (success %llu ) ", (unsigned long long) pf->kcnts[i]); } } |