[ovs-dev] [PATCH V2] compat: Fixups for newer kernels

Greg Rose gvrose8192 at gmail.com
Thu May 31 21:10:10 UTC 2018


A recent patch series added support for ERSPAN but left some problems
remaining for kernel releases from 4.10 to 4.14.  This patch
addresses those problems.

Of note is that the old cisco gre compat layer code is gone for good.

Also, several compat defines in acinclude.m4 were looking for keys
in .c source files - this does not work on distros without source
code.  A more reliable key was already defined so we use that instead.

We have pared support for the Linux kernel releases in .travis.yml
to reflect that 4.15 is no longer in the LTS list.  With this patch
the Out of Tree OVS datapath kernel modules can build on kernels
up to 4.14.47.  Support for kernels up to 4.16.x will be added
later.

Signed-off-by: Greg Rose <gvrose8192 at gmail.com>

---

V2 - Remove some additional code that was commented out and does
     not need to be saved.
---
 .travis.yml                                        |  11 +-
 acinclude.m4                                       |  15 +--
 datapath/linux/compat/geneve.c                     |  15 +++
 datapath/linux/compat/gre.c                        | 149 ---------------------
 datapath/linux/compat/include/linux/compiler-gcc.h |   5 +
 datapath/linux/compat/include/net/dst_metadata.h   |   2 -
 datapath/linux/compat/include/net/erspan.h         |   2 +-
 datapath/linux/compat/include/net/gre.h            |  28 ----
 datapath/linux/compat/include/net/ip_tunnels.h     |  18 ++-
 datapath/linux/compat/ip6_gre.c                    |  46 ++++---
 datapath/linux/compat/ip6_tunnel.c                 |  19 +--
 datapath/linux/compat/ip_gre.c                     | 118 +++++++---------
 datapath/linux/compat/ip_tunnel.c                  |   2 +
 datapath/linux/compat/ip_tunnels_core.c            |  25 +++-
 datapath/linux/compat/vxlan.c                      |  18 ++-
 15 files changed, 170 insertions(+), 303 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index cf37e8c..ff2fa2e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -33,12 +33,11 @@ env:
   - BUILD_ENV="-m32" OPTS="--disable-ssl"
   - KERNEL=3.16.54 DPDK=1
   - KERNEL=3.16.54 DPDK=1 OPTS="--enable-shared"
-  - KERNEL=4.15.3
-  - KERNEL=4.14.19
-  - KERNEL=4.9.81
-  - KERNEL=4.4.115
-  - KERNEL=4.1.49
-  - KERNEL=3.10.108
+  - KERNEL=4.14.47
+  - KERNEL=4.9.105
+  - KERNEL=4.4.135
+  - KERNEL=4.1.52
+  - KERNEL=3.16.56
   - TESTSUITE=1 LIBS=-ljemalloc
 
 matrix:
diff --git a/acinclude.m4 b/acinclude.m4
index 2351792..7a653cb 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -151,10 +151,10 @@ AC_DEFUN([OVS_CHECK_LINUX], [
     AC_MSG_RESULT([$kversion])
 
     if test "$version" -ge 4; then
-       if test "$version" = 4 && test "$patchlevel" -le 15; then
+       if test "$version" = 4 && test "$patchlevel" -le 14; then
           : # Linux 4.x
        else
-          AC_ERROR([Linux kernel in $KBUILD is version $kversion, but version newer than 4.15.x is not supported (please refer to the FAQ for advice)])
+          AC_ERROR([Linux kernel in $KBUILD is version $kversion, but version newer than 4.14.x is not supported (please refer to the FAQ for advice)])
        fi
     elif test "$version" = 3 && test "$patchlevel" -ge 10; then
        : # Linux 3.x
@@ -828,12 +828,6 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
   OVS_FIND_FIELD_IFELSE([$KSRC/include/linux/netdevice.h], [net_device],
                         [max_mtu],
                         [OVS_DEFINE([HAVE_NET_DEVICE_MAX_MTU])])
-  OVS_GREP_IFELSE([$KSRC/include/net/erspan.h],
-                  [__LINUX_ERSPAN_H],
-                  [OVS_DEFINE([HAVE_LINUX_ERSPAN_H])])
-  OVS_FIND_PARAM_IFELSE([$KSRC/net/ipv6/ip6_gre.c],
-                        [ip6gre_tunnel_validate], [extack],
-                        [OVS_DEFINE([HAVE_IP6GRE_EXTACK])])
   OVS_FIND_FIELD_IFELSE([$KSRC/include/net/ip6_tunnel.h], [__ip6_tnl_parm],
                         [erspan_ver],
                         [OVS_DEFINE([HAVE_IP6_TNL_PARM_ERSPAN_VER])])
@@ -864,9 +858,6 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
   OVS_GREP_IFELSE([$KSRC/include/uapi/linux/if_tunnel.h],
                   [IFLA_IPTUN_COLLECT_METADATA],
                   [OVS_DEFINE([HAVE_IFLA_IPTUN_COLLECT_METADATA])])
-  OVS_GREP_IFELSE([$KSRC/net/ipv4/gre_demux.c],
-                  [parse_gre_header],
-                  [OVS_DEFINE([HAVE_DEMUX_PARSE_GRE_HEADER])])
   OVS_GREP_IFELSE([$KSRC/include/uapi/linux/if_tunnel.h],
                   [IFLA_GRE_ENCAP_DPORT])
   OVS_GREP_IFELSE([$KSRC/include/uapi/linux/if_tunnel.h],
@@ -879,6 +870,8 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
                   [IFLA_GRE_ERSPAN_INDEX])
   OVS_GREP_IFELSE([$KSRC/include/uapi/linux/if_tunnel.h],
                   [IFLA_GRE_ERSPAN_HWID])
+  OVS_GREP_IFELSE([$KSRC/include/uapi/linux/if_tunnel.h],
+                  [IFLA_IPTUN_FWMARK])
 
   if cmp -s datapath/linux/kcompat.h.new \
             datapath/linux/kcompat.h >/dev/null 2>&1; then
diff --git a/datapath/linux/compat/geneve.c b/datapath/linux/compat/geneve.c
index 0fcc6e5..435a23f 100644
--- a/datapath/linux/compat/geneve.c
+++ b/datapath/linux/compat/geneve.c
@@ -1336,7 +1336,11 @@ static void geneve_setup(struct net_device *dev)
 
 	dev->netdev_ops = &geneve_netdev_ops;
 	dev->ethtool_ops = &geneve_ethtool_ops;
+#ifndef HAVE_NEEDS_FREE_NETDEV
 	dev->destructor = free_netdev;
+#else
+	dev->needs_free_netdev = true;
+#endif
 
 	SET_NETDEV_DEVTYPE(dev, &geneve_type);
 
@@ -1370,7 +1374,12 @@ static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = {
 	[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]	= { .type = NLA_U8 },
 };
 
+#ifdef  HAVE_EXT_ACK_IN_RTNL_LINKOPS
+static int geneve_validate(struct nlattr *tb[], struct nlattr *data[],
+			   struct netlink_ext_ack *extack)
+#else
 static int geneve_validate(struct nlattr *tb[], struct nlattr *data[])
+#endif
 {
 	if (tb[IFLA_ADDRESS]) {
 		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
@@ -1489,8 +1498,14 @@ static int geneve_configure(struct net *net, struct net_device *dev,
 	return 0;
 }
 
+#ifdef  HAVE_EXT_ACK_IN_RTNL_LINKOPS
+static int geneve_newlink(struct net *net, struct net_device *dev,
+			  struct nlattr *tb[], struct nlattr *data[],
+			  struct netlink_ext_ack *extack)
+#else
 static int geneve_newlink(struct net *net, struct net_device *dev,
 			  struct nlattr *tb[], struct nlattr *data[])
+#endif
 {
 	__be16 dst_port = htons(GENEVE_UDP_PORT);
 	__u8 ttl = 0, tos = 0;
diff --git a/datapath/linux/compat/gre.c b/datapath/linux/compat/gre.c
index b45f8b4..7f2b545 100644
--- a/datapath/linux/compat/gre.c
+++ b/datapath/linux/compat/gre.c
@@ -154,155 +154,6 @@ static int rpl_ip_gre_calc_hlen(__be16 o_flags)
 	return addend;
 }
 
-#ifndef HAVE_GRE_HANDLE_OFFLOADS
-#ifndef HAVE_GRE_CISCO_REGISTER
-
-#ifdef HAVE_DEMUX_PARSE_GRE_HEADER
-static __sum16 check_checksum(struct sk_buff *skb)
-{
-	__sum16 csum = 0;
-
-	switch (skb->ip_summed) {
-	case CHECKSUM_COMPLETE:
-		csum = csum_fold(skb->csum);
-
-		if (!csum)
-			break;
-		/* Fall through. */
-
-	case CHECKSUM_NONE:
-		skb->csum = 0;
-		csum = __skb_checksum_complete(skb);
-		skb->ip_summed = CHECKSUM_COMPLETE;
-		break;
-	}
-
-	return csum;
-}
-
-static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
-			    bool *csum_err)
-{
-	unsigned int ip_hlen = ip_hdrlen(skb);
-	struct gre_base_hdr *greh;
-	__be32 *options;
-	int hdr_len;
-
-	if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr))))
-		return -EINVAL;
-
-	greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen);
-	if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING)))
-		return -EINVAL;
-
-	tpi->flags = gre_flags_to_tnl_flags(greh->flags);
-	hdr_len = ip_gre_calc_hlen(tpi->flags);
-	tpi->hdr_len = hdr_len;
-	tpi->proto = greh->protocol;
-
-	if (!pskb_may_pull(skb, hdr_len))
-		return -EINVAL;
-
-	options = (__be32 *)(greh + 1);
-	if (greh->flags & GRE_CSUM) {
-		if (check_checksum(skb)) {
-			*csum_err = true;
-			return -EINVAL;
-		}
-		options++;
-	}
-
-	if (greh->flags & GRE_KEY) {
-		tpi->key = *options;
-		options++;
-	} else
-		tpi->key = 0;
-
-	if (unlikely(greh->flags & GRE_SEQ)) {
-		tpi->seq = *options;
-		options++;
-	} else
-		tpi->seq = 0;
-
-	/* WCCP version 1 and 2 protocol decoding.
-	 * - Change protocol to IP
-	 * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
-	 */
-	if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) {
-		tpi->proto = htons(ETH_P_IP);
-		if ((*(u8 *)options & 0xF0) != 0x40) {
-			hdr_len += 4;
-			if (!pskb_may_pull(skb, hdr_len))
-				return -EINVAL;
-		}
-	}
-
-	return iptunnel_pull_header(skb, hdr_len, tpi->proto, false);
-}
-
-static struct gre_cisco_protocol __rcu *gre_cisco_proto;
-static int gre_cisco_rcv(struct sk_buff *skb)
-{
-	struct gre_cisco_protocol *proto;
-	struct tnl_ptk_info tpi;
-	bool csum_err = false;
-
-	rcu_read_lock();
-	proto = rcu_dereference(gre_cisco_proto);
-	if (!proto)
-		goto drop;
-
-	if (parse_gre_header(skb, &tpi, &csum_err) < 0)
-			goto drop;
-	proto->handler(skb, &tpi);
-	rcu_read_unlock();
-	return 0;
-
-drop:
-	rcu_read_unlock();
-	kfree_skb(skb);
-	return 0;
-}
-
-static const struct gre_protocol ipgre_protocol = {
-	.handler	=	gre_cisco_rcv,
-};
-
-int rpl_gre_cisco_register(struct gre_cisco_protocol *newp)
-{
-	int err;
-
-	err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
-	if (err) {
-		pr_warn("%s: cannot register gre_cisco protocol handler\n", __func__);
-		return err;
-	}
-
-
-	return (cmpxchg((struct gre_cisco_protocol **)&gre_cisco_proto, NULL, newp) == NULL) ?
-		0 : -EBUSY;
-}
-EXPORT_SYMBOL_GPL(rpl_gre_cisco_register);
-
-int rpl_gre_cisco_unregister(struct gre_cisco_protocol *proto)
-{
-	int ret;
-	ret = (cmpxchg((struct gre_cisco_protocol **)&gre_cisco_proto, proto, NULL) == proto) ?
-		0 : -EINVAL;
-
-	if (ret)
-		return ret;
-
-	synchronize_net();
-	ret = gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(rpl_gre_cisco_unregister);
-
-#endif /* HAVE_DEMUX_PARSE_GRE_HEADER */
-#endif /* !HAVE_GRE_CISCO_REGISTER */
-#endif
-
 void rpl_gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
 			  int hdr_len)
 {
diff --git a/datapath/linux/compat/include/linux/compiler-gcc.h b/datapath/linux/compat/include/linux/compiler-gcc.h
index bfcd531..39d2e01 100644
--- a/datapath/linux/compat/include/linux/compiler-gcc.h
+++ b/datapath/linux/compat/include/linux/compiler-gcc.h
@@ -1,8 +1,13 @@
 #ifndef __LINUX_COMPILER_H
+#if 0
+/* Disable this check - it no longer makes sense with so many backports
+ * due to spectre mitigation
+ */
 #ifndef HAVE_LINUX_COMPILER_TYPES_H
 #error "Please don't include <linux/compiler-gcc.h> directly, include <linux/compiler.h> instead."
 #endif
 #endif
+#endif
 
 #include_next <linux/compiler-gcc.h>
 
diff --git a/datapath/linux/compat/include/net/dst_metadata.h b/datapath/linux/compat/include/net/dst_metadata.h
index 93ea954..e53a29e 100644
--- a/datapath/linux/compat/include/net/dst_metadata.h
+++ b/datapath/linux/compat/include/net/dst_metadata.h
@@ -116,13 +116,11 @@ static inline void ovs_ipv6_tun_rx_dst(struct metadata_dst *md_dst,
 void ovs_ip_tunnel_rcv(struct net_device *dev, struct sk_buff *skb,
 		      struct metadata_dst *tun_dst);
 
-#ifndef HAVE_METADATA_DST_ALLOC_WITH_METADATA_TYPE
 static inline struct metadata_dst *
 rpl_metadata_dst_alloc(u8 optslen, enum metadata_type type, gfp_t flags)
 {
 	return metadata_dst_alloc(optslen, flags);
 }
 #define metadata_dst_alloc rpl_metadata_dst_alloc
-#endif
 
 #endif /* __NET_DST_METADATA_WRAPPER_H */
diff --git a/datapath/linux/compat/include/net/erspan.h b/datapath/linux/compat/include/net/erspan.h
index 8adc89f..9fdae97 100644
--- a/datapath/linux/compat/include/net/erspan.h
+++ b/datapath/linux/compat/include/net/erspan.h
@@ -1,4 +1,4 @@
-#ifndef HAVE_LINUX_ERSPAN_H
+#ifndef USE_UPSTREAM_TUNNEL
 #ifndef __LINUX_ERSPAN_H
 #define __LINUX_ERSPAN_H
 
diff --git a/datapath/linux/compat/include/net/gre.h b/datapath/linux/compat/include/net/gre.h
index 141ed2d..58fa97a 100644
--- a/datapath/linux/compat/include/net/gre.h
+++ b/datapath/linux/compat/include/net/gre.h
@@ -124,34 +124,6 @@ static inline __be16 rpl_gre_tnl_flags_to_gre_flags(__be16 tflags)
 	return flags;
 }
 
-#ifndef HAVE_GRE_CISCO_REGISTER
-
-/* GRE demux not available, implement our own demux. */
-#define MAX_GRE_PROTO_PRIORITY 255
-
-struct gre_cisco_protocol {
-	int (*handler)(struct sk_buff *skb, const struct tnl_ptk_info *tpi);
-	int (*err_handler)(struct sk_buff *skb, u32 info,
-			   const struct tnl_ptk_info *tpi);
-	u8 priority;
-};
-
-#define gre_cisco_register rpl_gre_cisco_register
-int rpl_gre_cisco_register(struct gre_cisco_protocol *proto);
-
-#define gre_cisco_unregister rpl_gre_cisco_unregister
-int rpl_gre_cisco_unregister(struct gre_cisco_protocol *proto);
-
-#ifndef GRE_HEADER_SECTION
-struct gre_base_hdr {
-	__be16 flags;
-	__be16 protocol;
-};
-#define GRE_HEADER_SECTION 4
-#endif
-
-#endif /* HAVE_GRE_CISCO_REGISTER */
-
 #define gre_build_header rpl_gre_build_header
 void rpl_gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
 			  int hdr_len);
diff --git a/datapath/linux/compat/include/net/ip_tunnels.h b/datapath/linux/compat/include/net/ip_tunnels.h
index 9b2621e..b1c383d 100644
--- a/datapath/linux/compat/include/net/ip_tunnels.h
+++ b/datapath/linux/compat/include/net/ip_tunnels.h
@@ -60,9 +60,15 @@ int ovs_iptunnel_handle_offloads(struct sk_buff *skb,
  * rpl prefix is to make OVS build happy.
  */
 #define iptunnel_handle_offloads rpl_iptunnel_handle_offloads
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)
 struct sk_buff *rpl_iptunnel_handle_offloads(struct sk_buff *skb,
 					     bool csum_help,
 					     int gso_type_mask);
+#else
+int rpl_iptunnel_handle_offloads(struct sk_buff *skb,
+				 bool csum_help,
+				 int gso_type_mask);
+#endif
 
 #define iptunnel_xmit rpl_iptunnel_xmit
 void rpl_iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
@@ -231,7 +237,6 @@ static inline void ip_tunnel_key_init(struct ip_tunnel_key *key,
 
 #define ip_tunnel_collect_metadata() true
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0)
 #undef TUNNEL_NOCACHE
 #define TUNNEL_NOCACHE 0
 
@@ -248,7 +253,6 @@ ip_tunnel_dst_cache_usable(const struct sk_buff *skb,
 
 	return true;
 }
-#endif
 
 #define ip_tunnel_dst rpl_ip_tunnel_dst
 struct rpl_ip_tunnel_dst {
@@ -359,14 +363,14 @@ static inline int ovs_ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t,
 	return ret;
 }
 
-#ifndef HAVE_PCPU_SW_NETSTATS
 #define ip_tunnel_get_stats64 rpl_ip_tunnel_get_stats64
-#else
-#define rpl_ip_tunnel_get_stats64 ip_tunnel_get_stats64
-#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,11,0)
 struct rtnl_link_stats64 *rpl_ip_tunnel_get_stats64(struct net_device *dev,
 						    struct rtnl_link_stats64 *tot);
-
+#else
+void rpl_ip_tunnel_get_stats64(struct net_device *dev,
+						    struct rtnl_link_stats64 *tot);
+#endif
 #define ip_tunnel_get_dsfield rpl_ip_tunnel_get_dsfield
 static inline u8 rpl_ip_tunnel_get_dsfield(const struct iphdr *iph,
 					   const struct sk_buff *skb)
diff --git a/datapath/linux/compat/ip6_gre.c b/datapath/linux/compat/ip6_gre.c
index 94a031c..dd22240 100644
--- a/datapath/linux/compat/ip6_gre.c
+++ b/datapath/linux/compat/ip6_gre.c
@@ -785,9 +785,9 @@ static int rpl_gre_handle_offloads(struct sk_buff *skb, bool gre_csum)
 #else
 static int gre_handle_offloads(struct sk_buff *skb, bool csum)
 {
-	return iptunnel_handle_offloads(skb,
+	return iptunnel_handle_offloads(skb, csum,
 					csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
-
+}
 #endif
 
 static void prepare_ip6gre_xmit_ipv4(struct sk_buff *skb,
@@ -1526,7 +1526,7 @@ static const struct net_device_ops ip6gre_netdev_ops = {
 	.ndo_start_xmit		= ip6gre_tunnel_xmit,
 	.ndo_do_ioctl		= ip6gre_tunnel_ioctl,
 	.ndo_change_mtu		= ip6_tnl_change_mtu,
-	.ndo_get_stats64	= rpl_ip_tunnel_get_stats64,
+	.ndo_get_stats64	= ip_tunnel_get_stats64,
 #ifdef HAVE_NDO_GET_IFLINK
 	.ndo_get_iflink		= ip6_tnl_get_iflink,
 #endif
@@ -1787,7 +1787,7 @@ static struct pernet_operations ip6gre_net_ops = {
 	.id   = &ip6gre_net_id,
 	.size = sizeof(struct ip6gre_net),
 };
-#ifdef HAVE_IP6GRE_EXTACK
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
 static int rpl_ip6gre_tunnel_validate(struct nlattr *tb[],
 				      struct nlattr *data[],
 				      struct netlink_ext_ack *extack)
@@ -1813,7 +1813,7 @@ static int rpl_ip6gre_tunnel_validate(struct nlattr *tb[],
 }
 #define ip6gre_tunnel_validate rpl_ip6gre_tunnel_validate
 
-#ifdef HAVE_IP6GRE_EXTACK
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
 static int rpl_ip6gre_tap_validate(struct nlattr *tb[], struct nlattr *data[],
 				   struct netlink_ext_ack *extack)
 #else
@@ -1839,7 +1839,7 @@ static int rpl_ip6gre_tap_validate(struct nlattr *tb[], struct nlattr *data[])
 	}
 
 out:
-#ifdef HAVE_IP6GRE_EXTACK
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
 	return ip6gre_tunnel_validate(tb, data, extack);
 #else
 	return ip6gre_tunnel_validate(tb, data);
@@ -1847,7 +1847,7 @@ out:
 }
 #define ip6gre_tap_validate rpl_ip6gre_tap_validate
 
-#ifdef HAVE_IP6GRE_EXTACK
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
 static int rpl_ip6erspan_tap_validate(struct nlattr *tb[],
 				      struct nlattr *data[],
 				      struct netlink_ext_ack *extack)
@@ -1862,7 +1862,7 @@ static int rpl_ip6erspan_tap_validate(struct nlattr *tb[],
 	if (!data)
 		return 0;
 
-#ifdef HAVE_IP6GRE_EXTACK
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
 	ret = ip6gre_tap_validate(tb, data, extack);
 #else
 	ret = ip6gre_tap_validate(tb, data);
@@ -2011,7 +2011,7 @@ static const struct net_device_ops ip6gre_tap_netdev_ops = {
 	.ndo_set_mac_address = eth_mac_addr,
 	.ndo_validate_addr = eth_validate_addr,
 	.ndo_change_mtu = ip6_tnl_change_mtu,
-	.ndo_get_stats64 = rpl_ip_tunnel_get_stats64,
+	.ndo_get_stats64 = ip_tunnel_get_stats64,
 #ifdef HAVE_NDO_GET_IFLINK
 	.ndo_get_iflink = ip6_tnl_get_iflink,
 #endif
@@ -2134,7 +2134,7 @@ static bool ip6gre_netlink_encap_parms(struct nlattr *data[],
 	return ret;
 }
 
-#ifdef HAVE_IP6GRE_EXTACK
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
 static int rpl_ip6gre_newlink_common(struct net *src_net, struct net_device *dev,
 			      struct nlattr *tb[], struct nlattr *data[],
 			      struct netlink_ext_ack *extack)
@@ -2176,7 +2176,7 @@ out:
 }
 #define ip6gre_newlink_common rpl_ip6gre_newlink_common
 
-#ifdef HAVE_IP6GRE_EXTACK
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
 static int rpl_ip6gre_newlink(struct net *src_net, struct net_device *dev,
 			  struct nlattr *tb[], struct nlattr *data[],
 			  struct netlink_ext_ack *extack)
@@ -2201,7 +2201,7 @@ static int rpl_ip6gre_newlink(struct net *src_net, struct net_device *dev,
 			return -EEXIST;
 	}
 
-#ifdef HAVE_IP6GRE_EXTACK
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
 	err = ip6gre_newlink_common(src_net, dev, tb, data, extack);
 #else
 	err = ip6gre_newlink_common(src_net, dev, tb, data);
@@ -2216,7 +2216,7 @@ static int rpl_ip6gre_newlink(struct net *src_net, struct net_device *dev,
 
 #define ip6gre_newlink rpl_ip6gre_newlink
 
-#ifdef HAVE_IP6GRE_EXTACK
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
 static struct ip6_tnl *
 rpl_ip6gre_changelink_common(struct net_device *dev, struct nlattr *tb[],
 			 struct nlattr *data[], struct __ip6_tnl_parm *p_p,
@@ -2257,7 +2257,7 @@ rpl_ip6gre_changelink_common(struct net_device *dev, struct nlattr *tb[],
 }
 #define ip6gre_changelink_common rpl_ip6gre_changelink_common
 
-#ifdef HAVE_IP6GRE_EXTACK
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
 static int rpl_ip6gre_changelink(struct net_device *dev, struct nlattr *tb[],
 			     struct nlattr *data[],
 			     struct netlink_ext_ack *extack)
@@ -2270,7 +2270,7 @@ static int rpl_ip6gre_changelink(struct net_device *dev, struct nlattr *tb[],
 	struct __ip6_tnl_parm p;
 	struct ip6_tnl *t;
 
-#ifdef HAVE_IP6GRE_EXTACK
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
 	t = ip6gre_changelink_common(dev, tb, data, &p, extack);
 #else
 	t = ip6gre_changelink_common(dev, tb, data, &p);
@@ -2436,7 +2436,7 @@ static void ip6erspan_tap_setup(struct net_device *dev)
 	netif_keep_dst(dev);
 }
 
-#ifdef HAVE_IP6GRE_EXTACK
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
 static int rpl_ip6erspan_newlink(struct net *src_net, struct net_device *dev,
 				 struct nlattr *tb[], struct nlattr *data[],
 				 struct netlink_ext_ack *extack)
@@ -2461,7 +2461,7 @@ static int rpl_ip6erspan_newlink(struct net *src_net, struct net_device *dev,
 			return -EEXIST;
 	}
 
-#ifdef HAVE_IP6GRE_EXTACK
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
 	err = ip6gre_newlink_common(src_net, dev, tb, data, extack);
 #else
 	err = ip6gre_newlink_common(src_net, dev, tb, data);
@@ -2489,7 +2489,7 @@ static int ip6erspan_tnl_change(struct ip6_tnl *t,
 	return 0;
 }
 
-#ifdef HAVE_IP6GRE_EXTACK
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
 static int rpl_ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[],
 				    struct nlattr *data[],
 				    struct netlink_ext_ack *extack)
@@ -2501,7 +2501,7 @@ static int rpl_ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[],
 	struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id);
 	struct __ip6_tnl_parm p;
 	struct ip6_tnl *t;
-#ifdef HAVE_IP6GRE_EXTACK
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
 	t = ip6gre_changelink_common(dev, tb, data, &p, extack);
 #else
 	t = ip6gre_changelink_common(dev, tb, data, &p);
@@ -2588,7 +2588,11 @@ struct net_device *ip6erspan_fb_dev_create(struct net *net, const char *name,
 	t = netdev_priv(dev);
 	t->parms.collect_md = true;
 
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
+	err = ip6erspan_newlink(net, dev, tb, NULL, NULL);
+#else
 	err = ip6erspan_newlink(net, dev, tb, NULL);
+#endif
 	if (err < 0) {
 		free_netdev(dev);
 		return ERR_PTR(err);
@@ -2685,7 +2689,11 @@ struct net_device *ip6gre_fb_dev_create(struct net *net, const char *name,
 	t = netdev_priv(dev);
 	t->parms.collect_md = true;
 
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
+	err = ip6gre_newlink(net, dev, tb, NULL, NULL);
+#else
 	err = ip6gre_newlink(net, dev, tb, NULL);
+#endif
 	if (err < 0) {
 		free_netdev(dev);
 		return ERR_PTR(err);
diff --git a/datapath/linux/compat/ip6_tunnel.c b/datapath/linux/compat/ip6_tunnel.c
index f9720a3..f6ac069 100644
--- a/datapath/linux/compat/ip6_tunnel.c
+++ b/datapath/linux/compat/ip6_tunnel.c
@@ -73,9 +73,11 @@ enum {
 	IFLA_IPTUN_ENCAP_SPORT,
 	IFLA_IPTUN_ENCAP_DPORT,
 #endif
-#ifndef HAVE_IFLA_IPTUN_COLLECT_METADTA
+#ifndef HAVE_IFLA_IPTUN_COLLECT_METADATA
 	IFLA_IPTUN_COLLECT_METADATA = IFLA_IPTUN_ENCAP_DPORT + 1,
-	IFLA_IPTUN_FWMARK,
+#endif
+#ifndef HAVE_IFLA_IPTUN_FWMARK
+	IFLA_IPTUN_FWMARK = IFLA_IPTUN_COLLECT_METADATA + 1,
 #endif
 	RPL__IFLA_IPTUN_MAX = IFLA_IPTUN_FWMARK + 1,
 };
@@ -104,7 +106,8 @@ static void gre_csum_fix(struct sk_buff *skb)
 }
 
 #define iptunnel_handle_offloads rpl__iptunnel_handle_offloads
-static int rpl__iptunnel_handle_offloads(struct sk_buff *skb, bool gre_csum)
+static int rpl__iptunnel_handle_offloads(struct sk_buff *skb, bool gre_csum,
+					 int __always_unused ignored)
 {
 	int type = gre_csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE;
 	gso_fix_segment_t fix_segment;
@@ -1116,7 +1119,7 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
 // FIX ME
 //	fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
 
-	if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6))
+	if (iptunnel_handle_offloads(skb, true, SKB_GSO_IPXIP6))
 		return -1;
 
 	dsfield = INET_ECN_encapsulate(dsfield, ipv4_get_dsfield(iph));
@@ -1208,7 +1211,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
 //	FIX ME
 //	fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
 
-	if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6))
+	if (iptunnel_handle_offloads(skb, true, SKB_GSO_IPXIP6))
 		return -1;
 
 	dsfield = INET_ECN_encapsulate(dsfield, ipv6_get_dsfield(ipv6h));
@@ -1746,7 +1749,7 @@ static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
 	return 0;
 }
 
-#ifdef HAVE_IP6GRE_EXTACK
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
 static int rpl_ip6_tnl_validate(struct nlattr *tb[], struct nlattr *data[],
 				struct netlink_ext_ack *extack)
 #else
@@ -1840,7 +1843,7 @@ static bool ip6_tnl_netlink_encap_parms(struct nlattr *data[],
 	return ret;
 }
 
-#ifdef HAVE_IP6GRE_EXTACK
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
 static int rpl_ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
 			       struct nlattr *tb[], struct nlattr *data[],
 			       struct netlink_ext_ack *extack)
@@ -1882,7 +1885,7 @@ static int rpl_ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
 }
 #define ip6_tnl_newlink rpl_ip6_tnl_newlink
 
-#ifdef HAVE_IP6GRE_EXTACK
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
 static int rpl_ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[],
 				  struct nlattr *data[],
 				  struct netlink_ext_ack *extack)
diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c
index 5911c6c..d35614e 100644
--- a/datapath/linux/compat/ip_gre.c
+++ b/datapath/linux/compat/ip_gre.c
@@ -19,7 +19,7 @@
 #include <linux/kernel.h>
 #include <linux/kconfig.h>
 #include <linux/slab.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/netdev_features.h>
@@ -96,14 +96,6 @@ static __be32 tunnel_id_to_key(__be64 x)
 #endif
 }
 
-#ifdef HAVE_DEMUX_PARSE_GRE_HEADER
-/* Called with rcu_read_lock and BH disabled. */
-static int gre_err(struct sk_buff *skb, u32 info,
-		   const struct tnl_ptk_info *tpi)
-{
-	return PACKET_REJECT;
-}
-#endif
 static struct dst_ops md_dst_ops = {
 	.family =		AF_UNSPEC,
 };
@@ -354,7 +346,6 @@ static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
 	ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol);
 }
 
-#ifndef HAVE_DEMUX_PARSE_GRE_HEADER
 static int gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *unused_tpi)
 {
 	struct tnl_ptk_info tpi;
@@ -379,28 +370,9 @@ drop:
 	kfree_skb(skb);
 	return 0;
 }
-#else
-static int gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *__tpi)
-{
-	struct tnl_ptk_info tpi = *__tpi;
-
-	if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) ||
-		     tpi.proto == htons(ETH_P_ERSPAN2))) {
-		if (erspan_rcv(skb, &tpi, 0) == PACKET_RCVD)
-			return 0;
-		goto drop;
-	}
-
-	if (ipgre_rcv(skb, &tpi, 0) == PACKET_RCVD)
-		return 0;
-drop:
-
-	kfree_skb(skb);
-	return 0;
-}
-#endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)
+#include "gso.h"
 /* gre_handle_offloads() has different return type on older kernsl. */
 static void gre_nop_fix(struct sk_buff *skb) { }
 
@@ -418,11 +390,6 @@ static void gre_csum_fix(struct sk_buff *skb)
 						     skb->len - gre_offset, 0));
 }
 
-static bool is_gre_gso(struct sk_buff *skb)
-{
-	return skb_is_gso(skb);
-}
-
 #define gre_handle_offloads rpl_gre_handle_offloads
 static int rpl_gre_handle_offloads(struct sk_buff *skb, bool gre_csum)
 {
@@ -437,6 +404,12 @@ static int rpl_gre_handle_offloads(struct sk_buff *skb, bool gre_csum)
 	return ovs_iptunnel_handle_offloads(skb, type, fix_segment);
 }
 #else
+static int gre_handle_offloads(struct sk_buff *skb, bool csum)
+{
+	return iptunnel_handle_offloads(skb, csum,
+					csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
+}
+#endif
 
 static bool is_gre_gso(struct sk_buff *skb)
 {
@@ -444,16 +417,6 @@ static bool is_gre_gso(struct sk_buff *skb)
 		(SKB_GSO_GRE | SKB_GSO_GRE_CSUM);
 }
 
-static int rpl_gre_handle_offloads(struct sk_buff *skb, bool gre_csum)
-{
-	if (skb_is_gso(skb) && skb_is_encapsulated(skb))
-		return -ENOSYS;
-
-#undef gre_handle_offloads
-	return gre_handle_offloads(skb, gre_csum);
-}
-#endif
-
 static void build_header(struct sk_buff *skb, int hdr_len, __be16 flags,
 			 __be16 proto, __be32 key, __be32 seq)
 {
@@ -589,14 +552,14 @@ netdev_tx_t rpl_gre_fb_xmit(struct sk_buff *skb)
 			goto err_free_rt;
 	}
 
-	skb = vlan_hwaccel_push_inside(skb);
+	skb = __vlan_hwaccel_push_inside(skb);
 	if (unlikely(!skb)) {
 		err = -ENOMEM;
 		goto err_free_rt;
 	}
 
 	/* Push Tunnel header. */
-	err = rpl_gre_handle_offloads(skb, !!(tun_info->key.tun_flags & TUNNEL_CSUM));
+	err = gre_handle_offloads(skb, !!(tun_info->key.tun_flags & TUNNEL_CSUM));
 	if (err)
 		goto err_free_rt;
 
@@ -747,14 +710,6 @@ static void __gre_tunnel_init(struct net_device *dev)
 	}
 }
 
-#ifdef HAVE_DEMUX_PARSE_GRE_HEADER
-static struct gre_cisco_protocol ipgre_cisco_protocol = {
-	.handler        = gre_rcv,
-	.err_handler    = gre_err,
-	.priority       = 1,
-};
-#endif
-
 static int __gre_rcv(struct sk_buff *skb)
 {
 	return gre_rcv(skb, NULL);
@@ -789,7 +744,12 @@ static struct pernet_operations ipgre_net_ops = {
 	.size = sizeof(struct ip_tunnel_net),
 };
 
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
+static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[],
+				 struct netlink_ext_ack *extack)
+#else
 static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
+#endif
 {
 	__be16 flags;
 
@@ -807,7 +767,12 @@ static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
 	return 0;
 }
 
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
+static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[],
+			      struct netlink_ext_ack *extack)
+#else
 static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[])
+#endif
 {
 	__be32 daddr;
 
@@ -828,7 +793,11 @@ static int ipgre_tap_validate(struct nlattr *tb[], struct nlattr *data[])
 	}
 
 out:
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
+	return ipgre_tunnel_validate(tb, data, NULL);
+#else
 	return ipgre_tunnel_validate(tb, data);
+#endif
 }
 
 enum {
@@ -859,7 +828,12 @@ enum {
 
 #define RPL_IFLA_GRE_MAX (IFLA_GRE_ERSPAN_HWID + 1)
 
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
+static int erspan_validate(struct nlattr *tb[], struct nlattr *data[],
+			   struct netlink_ext_ack *extack)
+#else
 static int erspan_validate(struct nlattr *tb[], struct nlattr *data[])
+#endif
 {
 	__be16 flags = 0;
 	int ret;
@@ -867,7 +841,11 @@ static int erspan_validate(struct nlattr *tb[], struct nlattr *data[])
 	if (!data)
 		return 0;
 
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
+	ret = ipgre_tap_validate(tb, data, NULL);
+#else
 	ret = ipgre_tap_validate(tb, data);
+#endif
 	if (ret)
 		return ret;
 
@@ -1194,7 +1172,7 @@ static const struct net_device_ops gre_tap_netdev_ops = {
 #else
 	.ndo_change_mtu		= ip_tunnel_change_mtu,
 #endif
-	.ndo_get_stats64	= rpl_ip_tunnel_get_stats64,
+	.ndo_get_stats64	= ip_tunnel_get_stats64,
 #ifdef HAVE_NDO_GET_IFLINK
 	.ndo_get_iflink		= rpl_ip_tunnel_get_iflink,
 #endif
@@ -1210,7 +1188,7 @@ static const struct net_device_ops erspan_netdev_ops = {
 	.ndo_set_mac_address	= eth_mac_addr,
 	.ndo_validate_addr	= eth_validate_addr,
 	.ndo_change_mtu		= ip_tunnel_change_mtu,
-	.ndo_get_stats64	= rpl_ip_tunnel_get_stats64,
+	.ndo_get_stats64	= ip_tunnel_get_stats64,
 #ifdef HAVE_NDO_GET_IFLINK
 	.ndo_get_iflink		= rpl_ip_tunnel_get_iflink,
 #endif
@@ -1247,8 +1225,14 @@ static void erspan_setup(struct net_device *dev)
 	ip_tunnel_setup(dev, erspan_net_id);
 }
 
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
+static int ipgre_newlink(struct net *src_net, struct net_device *dev,
+			 struct nlattr *tb[], struct nlattr *data[],
+			 struct netlink_ext_ack *extack)
+#else
 static int ipgre_newlink(struct net *src_net, struct net_device *dev,
 			 struct nlattr *tb[], struct nlattr *data[])
+#endif
 {
 	struct ip_tunnel_parm p;
 	int err;
@@ -1424,7 +1408,11 @@ struct net_device *rpl_gretap_fb_dev_create(struct net *net, const char *name,
 	t = netdev_priv(dev);
 	t->collect_md = true;
 	/* Configure flow based GRE device. */
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
+	err = ipgre_newlink(net, dev, tb, NULL, NULL);
+#else
 	err = ipgre_newlink(net, dev, tb, NULL);
+#endif
 	if (err < 0) {
 		free_netdev(dev);
 		return ERR_PTR(err);
@@ -1504,7 +1492,11 @@ static struct net_device *erspan_fb_dev_create(struct net *net,
 	t = netdev_priv(dev);
 	t->collect_md = true;
 	/* Configure flow based GRE device. */
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
+	err = ipgre_newlink(net, dev, tb, NULL, NULL);
+#else
 	err = ipgre_newlink(net, dev, tb, NULL);
+#endif
 	if (err < 0) {
 		free_netdev(dev);
 		return ERR_PTR(err);
@@ -1648,19 +1640,11 @@ int rpl_ipgre_init(void)
 	if (err < 0)
 		goto pnet_ipgre_failed;
 
-#ifdef HAVE_DEMUX_PARSE_GRE_HEADER
-	err = gre_cisco_register(&ipgre_cisco_protocol);
-	if (err < 0) {
-		pr_info("%s: can't add protocol\n", __func__);
-		goto add_proto_failed;
-	}
-#else
 	err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
 	if (err < 0) {
 		pr_info("%s: can't add protocol\n", __func__);
 		goto add_proto_failed;
 	}
-#endif
 
 	pr_info("GRE over IPv4 tunneling driver\n");
 	
@@ -1683,11 +1667,7 @@ void rpl_ipgre_fini(void)
 {
 	ovs_vport_ops_unregister(&ovs_erspan_vport_ops);
 	ovs_vport_ops_unregister(&ovs_ipgre_vport_ops);
-#ifdef HAVE_DEMUX_PARSE_GRE_HEADER
-	gre_cisco_unregister(&ipgre_cisco_protocol);
-#else
 	gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
-#endif
 	unregister_pernet_device(&ipgre_net_ops);
 	unregister_pernet_device(&erspan_net_ops);
 	unregister_pernet_device(&ipgre_tap_net_ops);
diff --git a/datapath/linux/compat/ip_tunnel.c b/datapath/linux/compat/ip_tunnel.c
index 58870bc..5ab6035 100644
--- a/datapath/linux/compat/ip_tunnel.c
+++ b/datapath/linux/compat/ip_tunnel.c
@@ -470,7 +470,9 @@ EXPORT_SYMBOL_GPL(rpl_ip_tunnel_xmit);
 static void ip_tunnel_dev_free(struct net_device *dev)
 {
 	free_percpu(dev->tstats);
+#ifndef HAVE_NEEDS_FREE_NETDEV
 	free_netdev(dev);
+#endif
 }
 
 void rpl_ip_tunnel_dellink(struct net_device *dev, struct list_head *head)
diff --git a/datapath/linux/compat/ip_tunnels_core.c b/datapath/linux/compat/ip_tunnels_core.c
index 90e838a..fcb0890 100644
--- a/datapath/linux/compat/ip_tunnels_core.c
+++ b/datapath/linux/compat/ip_tunnels_core.c
@@ -129,9 +129,16 @@ error:
 }
 EXPORT_SYMBOL_GPL(ovs_iptunnel_handle_offloads);
 
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)
 struct sk_buff *rpl_iptunnel_handle_offloads(struct sk_buff *skb,
 					     bool csum_help,
 					     int gso_type_mask)
+#else
+int rpl_iptunnel_handle_offloads(struct sk_buff *skb,
+				 bool csum_help,
+				 int gso_type_mask)
+#endif
 {
 	int err;
 
@@ -145,7 +152,7 @@ struct sk_buff *rpl_iptunnel_handle_offloads(struct sk_buff *skb,
 		if (unlikely(err))
 			goto error;
 		skb_shinfo(skb)->gso_type |= gso_type_mask;
-		return skb;
+		goto out;
 	}
 
 	/* If packet is not gso and we are resolving any partial checksum,
@@ -163,10 +170,17 @@ struct sk_buff *rpl_iptunnel_handle_offloads(struct sk_buff *skb,
 	} else if (skb->ip_summed != CHECKSUM_PARTIAL)
 		skb->ip_summed = CHECKSUM_NONE;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0)
+out:
 	return skb;
 error:
 	kfree_skb(skb);
 	return ERR_PTR(err);
+#else
+out:
+error:
+	return 0;
+#endif
 }
 EXPORT_SYMBOL_GPL(rpl_iptunnel_handle_offloads);
 
@@ -258,9 +272,15 @@ static void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64,
 		dst[i] = src[i];
 #endif
 }
+#endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,11,0)
 struct rtnl_link_stats64 *rpl_ip_tunnel_get_stats64(struct net_device *dev,
 						struct rtnl_link_stats64 *tot)
+#else
+void rpl_ip_tunnel_get_stats64(struct net_device *dev,
+						struct rtnl_link_stats64 *tot)
+#endif
 {
 	int i;
 
@@ -286,9 +306,10 @@ struct rtnl_link_stats64 *rpl_ip_tunnel_get_stats64(struct net_device *dev,
 		tot->tx_bytes   += tx_bytes;
 	}
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,11,0)
 	return tot;
-}
 #endif
+}
 
 void rpl_ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb,
 		    struct net_device *dev)
diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c
index fa4e7b1..7f5d5ce 100644
--- a/datapath/linux/compat/vxlan.c
+++ b/datapath/linux/compat/vxlan.c
@@ -844,7 +844,8 @@ static int vxlan_build_skb(struct sk_buff *skb, struct dst_entry *dst,
 	if (unlikely(err))
 		goto out_free;
 
-	skb = vlan_hwaccel_push_inside(skb);
+	if (skb_vlan_tag_present(skb))
+		skb = __vlan_hwaccel_push_inside(skb);
 	if (WARN_ON(!skb))
 		return -ENOMEM;
 
@@ -1556,7 +1557,11 @@ static void vxlan_setup(struct net_device *dev)
 	eth_hw_addr_random(dev);
 	ether_setup(dev);
 
+#ifndef HAVE_NEEDS_FREE_NETDEV
 	dev->destructor = free_netdev;
+#else
+	dev->needs_free_netdev = true;
+#endif
 	SET_NETDEV_DEVTYPE(dev, &vxlan_type);
 
 	dev->features	|= NETIF_F_LLTX;
@@ -1636,7 +1641,12 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = {
 	[IFLA_VXLAN_REMCSUM_NOPARTIAL]	= { .type = NLA_FLAG },
 };
 
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
+static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[],
+			  struct netlink_ext_ack *extack)
+#else
 static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[])
+#endif
 {
 	if (tb[IFLA_ADDRESS]) {
 		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) {
@@ -1955,8 +1965,14 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
 	return 0;
 }
 
+#ifdef HAVE_EXT_ACK_IN_RTNL_LINKOPS
+static int vxlan_newlink(struct net *src_net, struct net_device *dev,
+			 struct nlattr *tb[], struct nlattr *data[],
+			 struct netlink_ext_ack *extack)
+#else
 static int vxlan_newlink(struct net *src_net, struct net_device *dev,
 			 struct nlattr *tb[], struct nlattr *data[])
+#endif
 {
 	pr_info("unsupported operation\n");
 	return -EINVAL;
-- 
1.8.3.1



More information about the dev mailing list