add decode of match rules

Show ip address etc when decoding output of tc filter show

Signed-off-by: Stephen Hemminger <stephen.hemminger@vyatta.com>
diff --git a/include/utils.h b/include/utils.h
index 7223a10..5daed6b 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -74,6 +74,7 @@
 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 8494851..d99deac 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -47,27 +47,18 @@
 	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)
+	/* 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 @@
 		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;
diff --git a/tc/f_u32.c b/tc/f_u32.c
index 1ac671b..91f2838 100644
--- a/tc/f_u32.c
+++ b/tc/f_u32.c
@@ -473,7 +473,7 @@
 	*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 @@
 	return res;
 }
 
+
 static int parse_icmp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
 {
 	int res = -1;
@@ -771,7 +772,47 @@
 	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 @@
 	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 @@
 	}
 
 	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]);
 			}
 		}