Description: Fan driver support v3
 Fan driver support v3
Author: Jay Vosburgh <jay.vosburgh@canonical.com>
Index: iproute2-4.1.1/include/linux/if_tunnel.h
===================================================================
--- iproute2-4.1.1.orig/include/linux/if_tunnel.h
+++ iproute2-4.1.1/include/linux/if_tunnel.h
@@ -59,6 +59,7 @@ enum {
 	IFLA_IPTUN_ENCAP_DPORT,
 
 	IFLA_IPTUN_FAN_UNDERLAY = 32,
+	IFLA_IPTUN_FAN_MAP = 33,
 
 	__IFLA_IPTUN_MAX,
 };
@@ -134,4 +135,20 @@ enum {
 };
 
 #define IFLA_VTI_MAX	(__IFLA_VTI_MAX - 1)
+
+enum {
+	IFLA_FAN_UNSPEC,
+	IFLA_FAN_MAPPING,
+	__IFLA_FAN_MAX,
+};
+
+#define IFLA_FAN_MAX (__IFLA_FAN_MAX - 1)
+
+struct ip_tunnel_fan_map {
+	__be32		underlay;
+	__be32		overlay;
+	__u16		underlay_prefix;
+	__u16		overlay_prefix;
+};
+
 #endif /* _IF_TUNNEL_H_ */
Index: iproute2-4.1.1/ip/link_iptnl.c
===================================================================
--- iproute2-4.1.1.orig/ip/link_iptnl.c
+++ iproute2-4.1.1/ip/link_iptnl.c
@@ -49,6 +49,42 @@ static void usage(int sit)
 	print_usage(stderr, sit);
 	exit(-1);
 }
+static int fan_parse_map(int *argcp, char ***argvp, struct nlmsghdr *n)
+{
+	inet_prefix underlay, overlay;
+	struct ip_tunnel_fan_map map;
+	struct rtattr *nest;
+	char **argv = *argvp;
+	int argc = *argcp;
+
+	nest = addattr_nest(n, 1024, IFLA_IPTUN_FAN_MAP);
+	while (argc > 0) {
+		char *colon = strchr(*argv, ':');
+
+		if (!colon)
+			break;
+		*colon = '\0';
+
+		if (get_prefix(&overlay, *argv, AF_INET))
+			invarg("invalid fan-map overlay", *argv);
+		if (get_prefix(&underlay, colon + 1, AF_INET))
+			invarg("invalid fan-map underlay", colon + 1);
+		
+		memcpy(&map.underlay, underlay.data, 4);
+		map.underlay_prefix = underlay.bitlen;
+		memcpy(&map.overlay, overlay.data, 4);
+		map.overlay_prefix = overlay.bitlen;
+
+		argc--, argv++;
+
+		addattr_l(n, 1024, IFLA_FAN_MAPPING, &map, sizeof(map));
+	}
+	addattr_nest_end(n, nest);
+
+	*argcp = argc;
+	*argvp = argv;
+	return 0;
+}
 
 static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv,
 			      struct nlmsghdr *n)
@@ -178,6 +214,10 @@ get_failed:
 		} else if (strcmp(*argv, "underlay") == 0) {
 			NEXT_ARG();
 			underlay = get_addr32(*argv);
+		} else if (strcmp(*argv, "fan-map") == 0) {
+			NEXT_ARG();
+			if (fan_parse_map(&argc, &argv, n))
+				invarg("invalid fan-map", *argv);
 		} else if (strcmp(*argv, "local") == 0) {
 			NEXT_ARG();
 			if (strcmp(*argv, "any"))
@@ -328,6 +368,28 @@ get_failed:
 	return 0;
 }
 
+static void fan_print_map(FILE *f, struct rtattr *attr)
+{
+	char b1[INET_ADDRSTRLEN], b2[INET_ADDRSTRLEN];
+	struct ip_tunnel_fan_map *m;
+	struct rtattr *i;
+	int rem;
+	int p;
+
+	fprintf(f, "fan-map ");
+
+	rem = RTA_PAYLOAD(attr);
+	for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+		p = RTA_PAYLOAD(i);
+		m = RTA_DATA(i);
+		fprintf(f, "%s/%d:%s/%d ",
+			rt_addr_n2a(AF_INET, p, &m->overlay, b1, INET_ADDRSTRLEN),
+			m->overlay_prefix,
+			rt_addr_n2a(AF_INET, p, &m->underlay, b2, INET_ADDRSTRLEN),
+			m->underlay_prefix);
+	}
+}
+
 static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 {
 	char s1[1024];
@@ -364,6 +426,9 @@ static void iptunnel_print_opt(struct li
 				format_host(AF_INET, 4, &addr, s1, sizeof(s1)));
 	}
 
+	if (tb[IFLA_IPTUN_FAN_MAP])
+		fan_print_map(f, tb[IFLA_IPTUN_FAN_MAP]);
+
 	if (tb[IFLA_IPTUN_LINK] && rta_getattr_u32(tb[IFLA_IPTUN_LINK])) {
 		unsigned link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]);
 		const char *n = if_indextoname(link, s2);
