From 4cd057523f47888d997269a6777fc8944fe5134c Mon Sep 17 00:00:00 2001
From: Pravin B Shelar <pshelar@nicira.com>
Date: Fri, 2 Aug 2013 11:38:51 -0700
Subject: [PATCH 4/5] datapath: Support for Linux kernel 3.10

Changes are mostly related API changes in vlan, GRE
restructuring.

Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Acked-by: Kyle Mestery <kmestery@cisco.com>
Acked-by: Jesse Gross <jesse@nicira.com>
---
 FAQ                                                   |  2 +-
 datapath/actions.c                                    |  6 +++---
 datapath/datapath.c                                   |  2 +-
 datapath/linux/Modules.mk                             |  1 +
 datapath/linux/compat/include/linux/if_vlan.h         | 16 ++++++++++++++--
 datapath/linux/compat/include/linux/netdev_features.h | 12 ++++++++++++
 datapath/vlan.h                                       |  2 +-
 datapath/vport-internal_dev.c                         |  3 ++-
 datapath/vport-netdev.c                               |  4 ++--
 9 files changed, 37 insertions(+), 11 deletions(-)
 create mode 100644 datapath/linux/compat/include/linux/netdev_features.h

diff --git a/FAQ b/FAQ
index d7bab1d..4bbb07e 100644
--- a/FAQ
+++ b/FAQ
@@ -148,7 +148,7 @@ A: The following table lists the Linux kernel versions against which the
        1.9.x      2.6.18 to 3.8
        1.10.x     2.6.18 to 3.8
        1.11.x     2.6.18 to 3.8
-       1.12.x     2.6.18 to 3.9
+       1.12.x     2.6.18 to 3.10
 
    Open vSwitch userspace should also work with the Linux kernel module
    built into Linux 3.3 and later.
diff --git a/datapath/actions.c b/datapath/actions.c
index 0dac658..b753dda 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -100,7 +100,7 @@ static int pop_vlan(struct sk_buff *skb)
 	if (unlikely(err))
 		return err;
 
-	__vlan_hwaccel_put_tag(skb, ntohs(tci));
+	__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(tci));
 	return 0;
 }
 
@@ -112,7 +112,7 @@ static int push_vlan(struct sk_buff *skb, const struct ovs_action_push_vlan *vla
 		/* push down current VLAN tag */
 		current_tag = vlan_tx_tag_get(skb);
 
-		if (!__vlan_put_tag(skb, current_tag))
+		if (!__vlan_put_tag(skb, skb->vlan_proto, current_tag))
 			return -ENOMEM;
 
 		if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
@@ -120,7 +120,7 @@ static int push_vlan(struct sk_buff *skb, const struct ovs_action_push_vlan *vla
 					+ (2 * ETH_ALEN), VLAN_HLEN, 0));
 
 	}
-	__vlan_hwaccel_put_tag(skb, ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT);
+	__vlan_hwaccel_put_tag(skb, vlan->vlan_tpid, ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT);
 	return 0;
 }
 
diff --git a/datapath/datapath.c b/datapath/datapath.c
index 688773d..d0f2fc1 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -61,7 +61,7 @@
 #include "vport-internal_dev.h"
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) || \
-    LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+    LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0)
 #error Kernels before 2.6.18 or after 3.9 are not supported by this version of Open vSwitch.
 #endif
 
diff --git a/datapath/linux/Modules.mk b/datapath/linux/Modules.mk
index 4324336..f9a71c7 100644
--- a/datapath/linux/Modules.mk
+++ b/datapath/linux/Modules.mk
@@ -41,6 +41,7 @@ openvswitch_headers += \
 	linux/compat/include/linux/mutex.h \
 	linux/compat/include/linux/net.h \
 	linux/compat/include/linux/netdevice.h \
+	linux/compat/include/linux/netdev_features.h \
 	linux/compat/include/linux/netfilter_bridge.h \
 	linux/compat/include/linux/netfilter_ipv4.h \
 	linux/compat/include/linux/netlink.h \
diff --git a/datapath/linux/compat/include/linux/if_vlan.h b/datapath/linux/compat/include/linux/if_vlan.h
index b8b1961..730175b 100644
--- a/datapath/linux/compat/include/linux/if_vlan.h
+++ b/datapath/linux/compat/include/linux/if_vlan.h
@@ -5,6 +5,7 @@
 #include <linux/version.h>
 #include_next <linux/if_vlan.h>
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
 /*
  * The behavior of __vlan_put_tag() has changed over time:
  *
@@ -19,8 +20,9 @@
  * to avoid the need to guess whether the version in the kernel tree is
  * acceptable.
  */
-#define __vlan_put_tag rpl_vlan_put_tag
-static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci)
+#define __vlan_put_tag(skb, proto, tag)  rpl__vlan_put_tag(skb, tag)
+
+static inline struct sk_buff *rpl__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci)
 {
 	struct vlan_ethhdr *veth;
 
@@ -45,6 +47,16 @@ static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci)
 	return skb;
 }
 
+static inline struct sk_buff *rpl___vlan_hwaccel_put_tag(struct sk_buff *skb,
+						     __be16 vlan_proto,
+						     u16 vlan_tci)
+{
+	return __vlan_hwaccel_put_tag(skb, vlan_tci);
+}
+
+#define __vlan_hwaccel_put_tag rpl___vlan_hwaccel_put_tag
+
+#endif
 
 /* All of these were introduced in a single commit preceding 2.6.33, so
  * presumably all of them or none of them are present. */
diff --git a/datapath/linux/compat/include/linux/netdev_features.h b/datapath/linux/compat/include/linux/netdev_features.h
new file mode 100644
index 0000000..0259413
--- /dev/null
+++ b/datapath/linux/compat/include/linux/netdev_features.h
@@ -0,0 +1,12 @@
+#ifndef __LINUX_NETDEV_FEATURES_WRAPPER_H
+#define __LINUX_NETDEV_FEATURES_WRAPPER_H
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)
+#include_next <linux/netdev_features.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
+#define NETIF_F_HW_VLAN_CTAG_TX NETIF_F_HW_VLAN_TX
+#endif
+
+#endif
diff --git a/datapath/vlan.h b/datapath/vlan.h
index 5d3573b..1356aed 100644
--- a/datapath/vlan.h
+++ b/datapath/vlan.h
@@ -89,7 +89,7 @@ static inline int vlan_deaccel_tag(struct sk_buff *skb)
 	if (!vlan_tx_tag_present(skb))
 		return 0;
 
-	skb = __vlan_put_tag(skb, vlan_tx_tag_get(skb));
+	skb = __vlan_put_tag(skb, skb->vlan_proto, vlan_tx_tag_get(skb));
 	if (unlikely(!skb))
 		return -ENOMEM;
 
diff --git a/datapath/vport-internal_dev.c b/datapath/vport-internal_dev.c
index 521dadc..c646bcb 100644
--- a/datapath/vport-internal_dev.c
+++ b/datapath/vport-internal_dev.c
@@ -22,6 +22,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
+#include <linux/netdev_features.h>
 #include <linux/skbuff.h>
 #include <linux/version.h>
 
@@ -189,7 +190,7 @@ static void do_setup(struct net_device *netdev)
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
 	netdev->vlan_features = netdev->features;
-	netdev->features |= NETIF_F_HW_VLAN_TX;
+	netdev->features |= NETIF_F_HW_VLAN_CTAG_TX;
 #endif
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c
index 2daa5b8..54ca770 100644
--- a/datapath/vport-netdev.c
+++ b/datapath/vport-netdev.c
@@ -331,7 +331,7 @@ static int netdev_send(struct vport *vport, struct sk_buff *skb)
 				nskb = skb->next;
 				skb->next = NULL;
 
-				skb = __vlan_put_tag(skb, vlan_tx_tag_get(skb));
+				skb = __vlan_put_tag(skb, skb->vlan_proto, vlan_tx_tag_get(skb));
 				if (likely(skb)) {
 					len += skb->len;
 					vlan_set_tci(skb, 0);
@@ -345,7 +345,7 @@ static int netdev_send(struct vport *vport, struct sk_buff *skb)
 		}
 
 tag:
-		skb = __vlan_put_tag(skb, vlan_tx_tag_get(skb));
+		skb = __vlan_put_tag(skb, skb->vlan_proto, vlan_tx_tag_get(skb));
 		if (unlikely(!skb))
 			return 0;
 		vlan_set_tci(skb, 0);
-- 
1.8.3.2

