diff --git a/acinclude.m4 b/acinclude.m4
index 6ef244d..8ee6a44 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -823,6 +823,9 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
   OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h],
                   [__skb_checksum_convert],
                   [OVS_DEFINE([HAVE_SKB_CHECKSUM_CONVERT])])
+  OVS_FIND_FIELD_IFELSE([$KSRC/include/linux/netdevice.h], [net_device],
+                        [max_mtu],
+                        [OVS_DEFINE([HAVE_NET_DEVICE_MAX_MTU])])
 
   if cmp -s datapath/linux/kcompat.h.new \
             datapath/linux/kcompat.h >/dev/null 2>&1; then
diff --git a/datapath/linux/compat/gre.c b/datapath/linux/compat/gre.c
index 98924c9..6a6dc91 100644
--- a/datapath/linux/compat/gre.c
+++ b/datapath/linux/compat/gre.c
@@ -82,29 +82,6 @@ static __sum16 check_checksum(struct sk_buff *skb)
 	return csum;
 }
 
-#define gre_flags_to_tnl_flags rpl_gre_flags_to_tnl_flags
-static __be16 gre_flags_to_tnl_flags(__be16 flags)
-{
-	__be16 tflags = 0;
-
-	if (flags & GRE_CSUM)
-		tflags |= TUNNEL_CSUM;
-	if (flags & GRE_ROUTING)
-		tflags |= TUNNEL_ROUTING;
-	if (flags & GRE_KEY)
-		tflags |= TUNNEL_KEY;
-	if (flags & GRE_SEQ)
-		tflags |= TUNNEL_SEQ;
-	if (flags & GRE_STRICT)
-		tflags |= TUNNEL_STRICT;
-	if (flags & GRE_REC)
-		tflags |= TUNNEL_REC;
-	if (flags & GRE_VERSION)
-		tflags |= TUNNEL_VERSION;
-
-	return tflags;
-}
-
 static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
 			    bool *csum_err)
 {
diff --git a/datapath/linux/compat/include/net/gre.h b/datapath/linux/compat/include/net/gre.h
index e2473f2..78422c8 100644
--- a/datapath/linux/compat/include/net/gre.h
+++ b/datapath/linux/compat/include/net/gre.h
@@ -31,7 +31,52 @@ static inline struct net_device *rpl_gretap_fb_dev_create(
 #include_next <net/gre.h>
 
 #define tnl_flags_to_gre_flags rpl_tnl_flags_to_gre_flags
-static inline __be16 tnl_flags_to_gre_flags(__be16 tflags)
+static inline __be16 rpl_tnl_flags_to_gre_flags(__be16 tflags)
+{
+	__be16 flags = 0;
+
+	if (tflags & TUNNEL_CSUM)
+		flags |= GRE_CSUM;
+	if (tflags & TUNNEL_ROUTING)
+		flags |= GRE_ROUTING;
+	if (tflags & TUNNEL_KEY)
+		flags |= GRE_KEY;
+	if (tflags & TUNNEL_SEQ)
+		flags |= GRE_SEQ;
+	if (tflags & TUNNEL_STRICT)
+		flags |= GRE_STRICT;
+	if (tflags & TUNNEL_REC)
+		flags |= GRE_REC;
+	if (tflags & TUNNEL_VERSION)
+		flags |= GRE_VERSION;
+
+	return flags;
+}
+
+#define gre_flags_to_tnl_flags rpl_gre_flags_to_tnl_flags
+static inline __be16 rpl_gre_flags_to_tnl_flags(__be16 flags)
+{
+	__be16 tflags = 0;
+
+	if (flags & GRE_CSUM)
+		tflags |= TUNNEL_CSUM;
+	if (flags & GRE_ROUTING)
+		tflags |= TUNNEL_ROUTING;
+	if (flags & GRE_KEY)
+		tflags |= TUNNEL_KEY;
+	if (flags & GRE_SEQ)
+		tflags |= TUNNEL_SEQ;
+	if (flags & GRE_STRICT)
+		tflags |= TUNNEL_STRICT;
+	if (flags & GRE_REC)
+		tflags |= TUNNEL_REC;
+	if (flags & GRE_VERSION)
+		tflags |= TUNNEL_VERSION;
+
+	return tflags;
+}
+#define gre_tnl_flags_to_gre_flags rpl_gre_tnl_flags_to_gre_flags
+static inline __be16 rpl_gre_tnl_flags_to_gre_flags(__be16 tflags)
 {
 	__be16 flags = 0;
 
diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c
index 6e75094..7d066ae 100644
--- a/datapath/linux/compat/ip_gre.c
+++ b/datapath/linux/compat/ip_gre.c
@@ -113,7 +113,7 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
 		      int gre_hdr_len)
 {
 	struct net *net = dev_net(skb->dev);
-	struct metadata_dst tun_dst = NULL;
+	struct metadata_dst *tun_dst = NULL;
 	struct erspan_base_hdr *ershdr;
 	struct erspan_metadata *pkt_md;
 	struct ip_tunnel_net *itn;
@@ -123,21 +123,20 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
 	int len;
 
 	itn = net_generic(net, erspan_net_id);
-	iph = ip_hdr(skb);
 	len = gre_hdr_len + sizeof(*ershdr);
 
 	/* Check based hdr len */
 	if (unlikely(!pskb_may_pull(skb, len)))
-		return -ENOMEM;
+		return PACKET_REJECT;
 
 	iph = ip_hdr(skb);
 	ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len);
-	ver = (ntohs(ershdr->ver_vlan) & VER_MASK) >> VER_OFFSET;
+	ver = ershdr->ver;
 
 	/* The original GRE header does not have key field,
 	 * Use ERSPAN 10-bit session ID as key.
 	 */
-	tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK);
+	tpi->key = cpu_to_be32(get_session_id(ershdr));
 	tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex,
 				  tpi->flags | TUNNEL_KEY,
 				  iph->saddr, iph->daddr, tpi->key);
@@ -166,17 +165,17 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
 			flags = tpi->flags;
 			tun_id = key32_to_tunnel_id(tpi->key);
 
-			ovs_ip_tun_rx_dst(&tun_dst, skb, flags,
+			ovs_ip_tun_rx_dst(tun_dst, skb, flags,
 					  tun_id, sizeof(*md));
 
-			md = ip_tunnel_info_opts(&tun_dst.u.tun_info);
+			md = ip_tunnel_info_opts(&tun_dst->u.tun_info);
 			if (!md) {
 				dst_release((struct dst_entry *)tun_dst);
 				return PACKET_REJECT;
 			}
 
 			memcpy(md, pkt_md, sizeof(*md));
-			info = &tun_dst.u.tun_info;
+			info = &tun_dst->u.tun_info;
 			info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
 			info->options_len = sizeof(*md);
 		} else {
@@ -184,7 +183,7 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
 		}
 
 		skb_reset_mac_header(skb);
-		ovs_ip_tunnel_rcv(tunnel->dev, skb, &tun_dst);
+		ovs_ip_tunnel_rcv(tunnel->dev, skb, tun_dst);
 		return PACKET_RCVD;
 	}
 drop:
@@ -841,7 +840,9 @@ static const struct net_device_ops erspan_netdev_ops = {
 static void ipgre_tap_setup(struct net_device *dev)
 {
 	ether_setup(dev);
+#ifdef HAVE_NET_DEVICE_MAX_MTU
 	dev->max_mtu = 0;
+#endif
 	dev->netdev_ops		= &gre_tap_netdev_ops;
 	dev->priv_flags		|= IFF_LIVE_ADDR_CHANGE;
 	ip_tunnel_setup(dev, gre_tap_net_id);
