ip6vti: Add fwmark API

This is a new option that was added in Linux v4.12.

Signed-off-by: Thomas Winter <Thomas.Winter@alliedtelesis.co.nz>
diff --git a/doc/route.txt b/doc/route.txt
index 7802060..4e287f6 100644
--- a/doc/route.txt
+++ b/doc/route.txt
@@ -1366,6 +1366,9 @@
 extern int rtnl_link_ip6vti_set_remote(struct rtnl_link *link, struct in6_addr *remote);
 extern int rtnl_link_ip6vti_get_remote(struct rtnl_link *link, struct in6_addr *remote);
 
+extern int rtnl_link_ip6vti_set_fwmark(struct rtnl_link *link, uint32_t fwmark);
+extern int rtnl_link_ip6vti_get_fwmark(struct rtnl_link *link, uint32_t *fwmark);
+
 +----
 +
 .Example: Add a ip6vti tunnel device
diff --git a/include/netlink/route/link/ip6vti.h b/include/netlink/route/link/ip6vti.h
index f858a13..1da573e 100644
--- a/include/netlink/route/link/ip6vti.h
+++ b/include/netlink/route/link/ip6vti.h
@@ -37,6 +37,9 @@
 	extern int rtnl_link_ip6vti_set_remote(struct rtnl_link *link, struct in6_addr *remote);
 	extern int rtnl_link_ip6vti_get_remote(struct rtnl_link *link, struct in6_addr *remote);
 
+	extern int rtnl_link_ip6vti_set_fwmark(struct rtnl_link *link, uint32_t fwmark);
+	extern int rtnl_link_ip6vti_get_fwmark(struct rtnl_link *link, uint32_t *fwmark);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/route/link/ip6vti.c b/lib/route/link/ip6vti.c
index 56f4485..d2582ae 100644
--- a/lib/route/link/ip6vti.c
+++ b/lib/route/link/ip6vti.c
@@ -35,6 +35,7 @@
 #define IP6VTI_ATTR_OKEY      (1 << 2)
 #define IP6VTI_ATTR_LOCAL     (1 << 3)
 #define IP6VTI_ATTR_REMOTE    (1 << 4)
+#define IP6VTI_ATTR_FWMARK    (1 << 5)
 
 struct ip6vti_info
 {
@@ -43,6 +44,7 @@
 	uint32_t            okey;
 	struct in6_addr     local;
 	struct in6_addr     remote;
+	uint32_t            fwmark;
 	uint32_t            ip6vti_mask;
 };
 
@@ -52,6 +54,7 @@
 	[IFLA_VTI_OKEY]     = { .type = NLA_U32 },
 	[IFLA_VTI_LOCAL]    = { .minlen = sizeof(struct in6_addr) },
 	[IFLA_VTI_REMOTE]   = { .minlen = sizeof(struct in6_addr) },
+	[IFLA_VTI_FWMARK]   = { .type = NLA_U32 },
 };
 
 static int ip6vti_alloc(struct rtnl_link *link)
@@ -115,6 +118,11 @@
 		ip6vti->ip6vti_mask |= IP6VTI_ATTR_REMOTE;
 	}
 
+	if (tb[IFLA_VTI_FWMARK]) {
+		ip6vti->fwmark = nla_get_u32(tb[IFLA_VTI_FWMARK]);
+		ip6vti->ip6vti_mask |= IP6VTI_ATTR_FWMARK;
+	}
+
 	err = 0;
 
  errout:
@@ -145,6 +153,9 @@
 	if (ip6vti->ip6vti_mask & IP6VTI_ATTR_REMOTE)
 		NLA_PUT(msg, IFLA_VTI_REMOTE, sizeof(struct in6_addr), &ip6vti->remote);
 
+	if (ip6vti->ip6vti_mask & IP6VTI_ATTR_FWMARK)
+		NLA_PUT_U32(msg, IFLA_VTI_FWMARK, ip6vti->fwmark);
+
 	nla_nest_end(msg, data);
 
 nla_put_failure:
@@ -204,6 +215,11 @@
 		else
 			nl_dump_line(p, "%#x\n", ip6vti->remote);
 	}
+
+	if (ip6vti->ip6vti_mask & IP6VTI_ATTR_FWMARK) {
+		nl_dump(p, "      fwmark ");
+		nl_dump_line(p, "%x\n", ip6vti->fwmark);
+	}
 }
 
 static int ip6vti_clone(struct rtnl_link *dst, struct rtnl_link *src)
@@ -498,6 +514,45 @@
 	return 0;
 }
 
+/**
+ * Set IP6VTI tunnel fwmark
+ * @arg link            Link object
+ * @arg fwmark          fwmark
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6vti_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
+{
+	struct ip6vti_info *ip6vti = link->l_info;
+
+	IS_IP6VTI_LINK_ASSERT(link);
+
+	ip6vti->fwmark = fwmark;
+	ip6vti->ip6vti_mask |= IP6VTI_ATTR_FWMARK;
+
+	return 0;
+}
+
+/**
+ * Get IP6VTI tunnel fwmark
+ * @arg link            Link object
+ * @arg fwmark          addr to fill in with the fwmark
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ip6vti_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
+{
+	struct ip6vti_info *ip6vti = link->l_info;
+
+	IS_IP6VTI_LINK_ASSERT(link);
+
+	HAS_IP6VTI_ATTR_ASSERT(ip6vti, IP6VTI_ATTR_FWMARK);
+
+	*fwmark = ip6vti->fwmark;
+
+	return 0;
+}
+
 static void __init ip6vti_init(void)
 {
 	rtnl_link_register_info(&ip6vti_info_ops);
diff --git a/libnl-route-3.sym b/libnl-route-3.sym
index 020d5cd..5d5d2ae 100644
--- a/libnl-route-3.sym
+++ b/libnl-route-3.sym
@@ -1184,11 +1184,13 @@
 	rtnl_link_ip6vti_add;
 	rtnl_link_ip6vti_alloc;
 	rtnl_link_ip6vti_get_ikey;
+	rtnl_link_ip6vti_get_fwmark;
 	rtnl_link_ip6vti_get_link;
 	rtnl_link_ip6vti_get_local;
 	rtnl_link_ip6vti_get_okey;
 	rtnl_link_ip6vti_get_remote;
 	rtnl_link_ip6vti_set_ikey;
+	rtnl_link_ip6vti_set_fwmark;
 	rtnl_link_ip6vti_set_link;
 	rtnl_link_ip6vti_set_local;
 	rtnl_link_ip6vti_set_okey;