[ovs-dev] [PATCH v2 1/2] datapath: Drop support for kernel older than 3.10

Pravin B Shelar pshelar at ovn.org
Wed Feb 24 05:01:41 UTC 2016


Currently OVS out of tree datapath supports a large number of kernel
versions. From 2.6.32 to 4.3 and various distribution-specific
kernels. But at this point major features are only available on more
recent kernels.  For example, stateful services are only available
starting in kernel 3.10 and STT is available on starting with 3.5.

Since these features are becoming essential to many OVS deployments,
and the effort of maintaining the backports is high. We have decided
to drop support for older kernel. Following patch drops supports
for kernel older than 3.10.

Signed-off-by: Pravin B Shelar <pshelar at ovn.org>
---
Update FAQ, NEWS and travis config
---
 .travis.yml                                       |   3 -
 FAQ.md                                            |   1 +
 NEWS                                              |   1 +
 acinclude.m4                                      |  15 ++-
 datapath/actions.c                                |  28 ++----
 datapath/compat.h                                 |  23 +----
 datapath/conntrack.c                              |   5 +-
 datapath/conntrack.h                              |   2 +-
 datapath/datapath.c                               |   7 +-
 datapath/datapath.h                               |   1 -
 datapath/flow.c                                   |   3 +-
 datapath/flow_table.c                             |  10 +-
 datapath/linux/compat/geneve.c                    |  10 +-
 datapath/linux/compat/gso.c                       |   3 +-
 datapath/linux/compat/include/linux/netdevice.h   |   8 +-
 datapath/linux/compat/include/net/net_namespace.h |  51 -----------
 datapath/linux/compat/include/net/vxlan.h         |   4 +-
 datapath/linux/compat/ip_gre.c                    |   4 +-
 datapath/linux/compat/ip_tunnel.c                 |   2 +-
 datapath/linux/compat/ip_tunnels_core.c           |   9 +-
 datapath/linux/compat/lisp.c                      |   6 +-
 datapath/linux/compat/vxlan.c                     |   9 +-
 datapath/vlan.h                                   |  65 -------------
 datapath/vport-geneve.c                           |   8 +-
 datapath/vport-internal_dev.c                     | 107 +++++++++-------------
 datapath/vport-netdev.c                           |  38 +-------
 datapath/vport-netdev.h                           |   1 -
 datapath/vport.c                                  |  32 +++++--
 datapath/vport.h                                  |  35 ++-----
 29 files changed, 127 insertions(+), 364 deletions(-)
 delete mode 100644 datapath/vlan.h

diff --git a/.travis.yml b/.travis.yml
index 52c9362..2b262e4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -30,9 +30,6 @@ env:
   - KERNEL=3.14.60
   - KERNEL=3.12.53
   - KERNEL=3.10.96
-  - KERNEL=3.4.110
-  - KERNEL=3.2.76
-  - KERNEL=2.6.32.70
 
 script: ./.travis/build.sh $OPTS
 
diff --git a/FAQ.md b/FAQ.md
index 8bd7ab9..8e0a775 100644
--- a/FAQ.md
+++ b/FAQ.md
@@ -157,6 +157,7 @@ A: The following table lists the Linux kernel versions against which the
 |    2.3.x     | 2.6.32 to 3.14
 |    2.4.x     | 2.6.32 to 4.0
 |    2.5.x     | 2.6.32 to 4.3
+|    Master    | 3.10 to 4.3
 
    Open vSwitch userspace should also work with the Linux kernel module
    built into Linux 3.3 and later.
diff --git a/NEWS b/NEWS
index 57a250e..9fb976e 100644
--- a/NEWS
+++ b/NEWS
@@ -28,6 +28,7 @@ Post-v2.5.0
    - python:
      * Added support for Python 3.4+ in addition to existing support
        for 2.7+.
+   - Linux kernel support for kernel older than 3.10 is dropped.
 
 v2.5.0 - xx xxx xxxx
 ---------------------
diff --git a/acinclude.m4 b/acinclude.m4
index 11c7787..0ae6a81 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -139,14 +139,10 @@ AC_DEFUN([OVS_CHECK_LINUX], [
        else
           AC_ERROR([Linux kernel in $KBUILD is version $kversion, but version newer than 4.3.x is not supported (please refer to the FAQ for advice)])
        fi
-    elif test "$version" = 3; then
+    elif test "$version" = 3 && test "$patchlevel" -ge 10; then
        : # Linux 3.x
     else
-       if test "$version" -le 1 || test "$patchlevel" -le 5 || test "$sublevel" -le 31; then
-         AC_ERROR([Linux kernel in $KBUILD is version $kversion, but version 2.6.32 or later is required])
-       else
-         : # Linux 2.6.x
-       fi
+       AC_ERROR([Linux kernel in $KBUILD is version $kversion, but version 3.10 or later is required])
     fi
     if (test ! -e "$KBUILD"/include/linux/version.h && \
         test ! -e "$KBUILD"/include/generated/uapi/linux/version.h)|| \
@@ -307,7 +303,7 @@ AC_DEFUN([OVS_DEFINE], [
 
 dnl OVS_CHECK_LINUX_COMPAT
 dnl
-dnl Runs various Autoconf checks on the Linux 2.6 kernel source in
+dnl Runs various Autoconf checks on the Linux kernel source in
 dnl the directory in $KBUILD.
 AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
   rm -f datapath/linux/kcompat.h.new
@@ -381,7 +377,10 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
   OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [can_checksum_protocol])
   OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [ndo_get_iflink])
   OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [netdev_features_t])
-  OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [pcpu_sw_netstats])
+  dnl Ubuntu kernel 3.13 has defined this struct but not used for netdev->tstats.
+  dnl So check type of tstats.
+  OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [pcpu_sw_netstats.*tstats],
+                  [OVS_DEFINE([HAVE_PCPU_SW_NETSTATS])])
   OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [netdev_rx_handler_register])
   OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [net_device_extended])
   OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [rx_handler_func_t.*pskb],
diff --git a/datapath/actions.c b/datapath/actions.c
index 20413c9..dcf8591 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -41,7 +41,6 @@
 #include "datapath.h"
 #include "conntrack.h"
 #include "gso.h"
-#include "vlan.h"
 #include "vport.h"
 
 static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
@@ -68,9 +67,7 @@ struct ovs_frag_data {
 	u8 l2_data[MAX_L2_LEN];
 };
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
 static DEFINE_PER_CPU(struct ovs_frag_data, ovs_frag_data_storage);
-#endif
 
 #define DEFERRED_ACTION_FIFO_SIZE 10
 struct action_fifo {
@@ -149,7 +146,7 @@ static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key,
 	struct ethhdr *hdr;
 
 	/* Networking stack do not allow simultaneous Tunnel and MPLS GSO. */
-	if (skb_encapsulation(skb))
+	if (skb->encapsulation)
 		return -ENOTSUPP;
 
 	if (skb_cow_head(skb, MPLS_HLEN) < 0)
@@ -302,14 +299,14 @@ static void update_ip_l4_checksum(struct sk_buff *skb, struct iphdr *nh,
 	if (nh->protocol == IPPROTO_TCP) {
 		if (likely(transport_len >= sizeof(struct tcphdr)))
 			inet_proto_csum_replace4(&tcp_hdr(skb)->check, skb,
-						 addr, new_addr, 1);
+						 addr, new_addr, true);
 	} else if (nh->protocol == IPPROTO_UDP) {
 		if (likely(transport_len >= sizeof(struct udphdr))) {
 			struct udphdr *uh = udp_hdr(skb);
 
 			if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
 				inet_proto_csum_replace4(&uh->check, skb,
-							 addr, new_addr, 1);
+							 addr, new_addr, true);
 				if (!uh->check)
 					uh->check = CSUM_MANGLED_0;
 			}
@@ -335,14 +332,14 @@ static void update_ipv6_checksum(struct sk_buff *skb, u8 l4_proto,
 	if (l4_proto == NEXTHDR_TCP) {
 		if (likely(transport_len >= sizeof(struct tcphdr)))
 			inet_proto_csum_replace16(&tcp_hdr(skb)->check, skb,
-						  addr, new_addr, 1);
+						  addr, new_addr, true);
 	} else if (l4_proto == NEXTHDR_UDP) {
 		if (likely(transport_len >= sizeof(struct udphdr))) {
 			struct udphdr *uh = udp_hdr(skb);
 
 			if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
 				inet_proto_csum_replace16(&uh->check, skb,
-							  addr, new_addr, 1);
+							  addr, new_addr, true);
 				if (!uh->check)
 					uh->check = CSUM_MANGLED_0;
 			}
@@ -350,7 +347,7 @@ static void update_ipv6_checksum(struct sk_buff *skb, u8 l4_proto,
 	} else if (l4_proto == NEXTHDR_ICMP) {
 		if (likely(transport_len >= sizeof(struct icmp6hdr)))
 			inet_proto_csum_replace16(&icmp6_hdr(skb)->icmp6_cksum,
-						  skb, addr, new_addr, 1);
+						  skb, addr, new_addr, true);
 	}
 }
 
@@ -518,7 +515,7 @@ static int set_ipv6(struct sk_buff *skb, struct sw_flow_key *flow_key,
 static void set_tp_port(struct sk_buff *skb, __be16 *port,
 			__be16 new_port, __sum16 *check)
 {
-	inet_proto_csum_replace2(check, skb, *port, new_port, 0);
+	inet_proto_csum_replace2(check, skb, *port, new_port, false);
 	*port = new_port;
 }
 
@@ -625,7 +622,6 @@ static int set_sctp(struct sk_buff *skb, struct sw_flow_key *flow_key,
 	return 0;
 }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
 static int ovs_vport_output(OVS_VPORT_OUTPUT_PARAMS)
 {
 	struct ovs_frag_data *data = get_pcpu_ptr(ovs_frag_data_storage);
@@ -740,16 +736,6 @@ static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru,
 err:
 	kfree_skb(skb);
 }
-#else /* < 3.10 */
-static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru,
-			 __be16 ethertype)
-{
-	WARN_ONCE(1, "Fragment unavailable ->%s: eth=%04x, MRU=%d, MTU=%d.",
-		  ovs_vport_name(vport), ntohs(ethertype), mru,
-		  vport->dev->mtu);
-	kfree_skb(skb);
-}
-#endif
 
 static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
 		      struct sw_flow_key *key)
diff --git a/datapath/compat.h b/datapath/compat.h
index 0e19051..8bf779f 100644
--- a/datapath/compat.h
+++ b/datapath/compat.h
@@ -27,33 +27,14 @@
 #include <net/xfrm.h>
 #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
 
+/* Even though vanilla 3.10 kernel has grp->id, RHEL 7 kernel is missing
+ * this field. */
 #ifdef HAVE_GENL_MULTICAST_GROUP_WITH_ID
 #define GROUP_ID(grp)	((grp)->id)
 #else
 #define GROUP_ID(grp)	0
 #endif
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
-#define rt_dst(rt) (rt->dst)
-#else
-#define rt_dst(rt) (rt->u.dst)
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
-#define inet_sport(sk)	(inet_sk(sk)->sport)
-#else
-#define inet_sport(sk)	(inet_sk(sk)->inet_sport)
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
-static inline bool skb_encapsulation(struct sk_buff *skb)
-{
-	return skb->encapsulation;
-}
-#else
-#define skb_encapsulation(skb) false
-#endif
-
 #ifdef OVS_FRAGMENT_BACKPORT
 #ifdef HAVE_NF_IPV6_OPS_FRAGMENT
 static inline int __init ip6_output_init(void) { return 0; }
diff --git a/datapath/conntrack.c b/datapath/conntrack.c
index 795ed91..0338f9f 100644
--- a/datapath/conntrack.c
+++ b/datapath/conntrack.c
@@ -14,8 +14,7 @@
 #include <linux/kconfig.h>
 #include <linux/version.h>
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) && \
-    IS_ENABLED(CONFIG_NF_CONNTRACK)
+#if IS_ENABLED(CONFIG_NF_CONNTRACK)
 
 #include <linux/module.h>
 #include <linux/openvswitch.h>
@@ -799,4 +798,4 @@ void ovs_ct_exit(struct net *net)
 		nf_connlabels_put(net);
 }
 
-#endif /* CONFIG_NF_CONNTRACK && LINUX > 3.10 */
+#endif /* CONFIG_NF_CONNTRACK */
diff --git a/datapath/conntrack.h b/datapath/conntrack.h
index 90b91be..8a849e8 100644
--- a/datapath/conntrack.h
+++ b/datapath/conntrack.h
@@ -20,7 +20,7 @@
 struct ovs_conntrack_info;
 enum ovs_key_attr;
 
-#if IS_ENABLED(CONFIG_NF_CONNTRACK) && LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+#if IS_ENABLED(CONFIG_NF_CONNTRACK)
 void ovs_ct_init(struct net *);
 void ovs_ct_exit(struct net *);
 bool ovs_ct_verify(struct net *, enum ovs_key_attr attr);
diff --git a/datapath/datapath.c b/datapath/datapath.c
index e3d3c8c..5bec072 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -58,7 +58,6 @@
 #include "flow_table.h"
 #include "flow_netlink.h"
 #include "gso.h"
-#include "vlan.h"
 #include "vport-internal_dev.h"
 #include "vport-netdev.h"
 
@@ -450,12 +449,10 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
 		if (!nskb)
 			return -ENOMEM;
 
-		nskb = vlan_insert_tag_set_proto(nskb, nskb->vlan_proto, skb_vlan_tag_get(nskb));
+		nskb = __vlan_hwaccel_push_inside(nskb);
 		if (!nskb)
 			return -ENOMEM;
 
-		vlan_set_tci(nskb, 0);
-
 		skb = nskb;
 	}
 
@@ -2316,8 +2313,6 @@ static struct pernet_operations ovs_net_ops = {
 	.size = sizeof(struct ovs_net),
 };
 
-DEFINE_COMPAT_PNET_REG_FUNC(device);
-
 static int __init dp_init(void)
 {
 	int err;
diff --git a/datapath/datapath.h b/datapath/datapath.h
index ce5b82a..ceb3372 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -31,7 +31,6 @@
 #include "compat.h"
 #include "flow.h"
 #include "flow_table.h"
-#include "vlan.h"
 
 #define DP_MAX_PORTS           USHRT_MAX
 #define DP_VPORT_HASH_BUCKETS  1024
diff --git a/datapath/flow.c b/datapath/flow.c
index 057dde1..c97c9c9 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -50,7 +50,6 @@
 #include "flow.h"
 #include "flow_netlink.h"
 #include "vport.h"
-#include "vlan.h"
 
 u64 ovs_flow_used_time(unsigned long flow_jiffies)
 {
@@ -477,7 +476,7 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
 
 	key->eth.tci = 0;
 	if (skb_vlan_tag_present(skb))
-		key->eth.tci = htons(vlan_get_tci(skb));
+		key->eth.tci = htons(skb->vlan_tci);
 	else if (eth->h_proto == htons(ETH_P_8021Q))
 		if (unlikely(parse_vlan(skb, key)))
 			return -ENOMEM;
diff --git a/datapath/flow_table.c b/datapath/flow_table.c
index b51be69..dd77922 100644
--- a/datapath/flow_table.c
+++ b/datapath/flow_table.c
@@ -44,7 +44,6 @@
 #include <net/ipv6.h>
 #include <net/ndisc.h>
 
-#include "vlan.h"
 #include "flow_netlink.h"
 
 #define TBL_MIN_BUCKETS		1024
@@ -168,13 +167,6 @@ static void rcu_free_flow_callback(struct rcu_head *rcu)
 	flow_free(flow);
 }
 
-static void rcu_free_sw_flow_mask_cb(struct rcu_head *rcu)
-{
-	struct sw_flow_mask *mask = container_of(rcu, struct sw_flow_mask, rcu);
-
-	kfree(mask);
-}
-
 void ovs_flow_free(struct sw_flow *flow, bool deferred)
 {
 	if (!flow)
@@ -774,7 +766,7 @@ static void tbl_mask_array_delete_mask(struct mask_array *ma,
 		if (mask == ovsl_dereference(ma->masks[i])) {
 			RCU_INIT_POINTER(ma->masks[i], NULL);
 			ma->count--;
-			call_rcu(&mask->rcu, rcu_free_sw_flow_mask_cb);
+			kfree_rcu(mask, rcu);
 			return;
 		}
 	}
diff --git a/datapath/linux/compat/geneve.c b/datapath/linux/compat/geneve.c
index 92feeef..8a795bd 100644
--- a/datapath/linux/compat/geneve.c
+++ b/datapath/linux/compat/geneve.c
@@ -16,6 +16,7 @@
 #include <linux/etherdevice.h>
 #include <linux/hash.h>
 #include <linux/if_link.h>
+#include <linux/if_vlan.h>
 
 #include <net/dst_metadata.h>
 #include <net/net_namespace.h>
@@ -495,7 +496,7 @@ static struct geneve_sock *geneve_find_sock(struct geneve_net *gn,
 	struct geneve_sock *gs;
 
 	list_for_each_entry(gs, &gn->sock_list, list) {
-		if (inet_sport(gs->sock->sk) == dst_port &&
+		if (inet_sk(gs->sock->sk)->inet_sport == dst_port &&
 		    inet_sk(gs->sock->sk)->sk.sk_family == AF_INET) {
 			return gs;
 		}
@@ -549,7 +550,7 @@ static int geneve_build_skb(struct rtable *rt, struct sk_buff *skb,
 	int min_headroom;
 	int err;
 
-	min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len
+	min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
 			+ GENEVE_BASE_HLEN + opt_len + sizeof(struct iphdr)
 			+ (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);
 	err = skb_cow_head(skb, min_headroom);
@@ -623,7 +624,7 @@ static struct rtable *geneve_get_rt(struct sk_buff *skb,
 		dev->stats.tx_carrier_errors++;
 		return rt;
 	}
-	if (rt_dst(rt).dev == dev) { /* is this necessary? */
+	if (rt->dst.dev == dev) { /* is this necessary? */
 		netdev_dbg(dev, "circular route to %pI4\n", &fl4->daddr);
 		dev->stats.collisions++;
 		ip_rt_put(rt);
@@ -712,7 +713,7 @@ netdev_tx_t rpl_geneve_xmit(struct sk_buff *skb)
 		ttl = geneve->ttl;
 		if (!ttl && IN_MULTICAST(ntohl(fl4.daddr)))
 			ttl = 1;
-		ttl = ttl ? : ip4_dst_hoplimit(&rt_dst(rt));
+		ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
 		df = 0;
 	}
 	err = udp_tunnel_xmit_skb(rt, gs->sock->sk, skb, fl4.saddr, fl4.daddr,
@@ -1118,7 +1119,6 @@ static struct pernet_operations geneve_net_ops = {
 	.size = sizeof(struct geneve_net),
 };
 
-DEFINE_COMPAT_PNET_REG_FUNC(device)
 int rpl_geneve_init_module(void)
 {
 	int rc;
diff --git a/datapath/linux/compat/gso.c b/datapath/linux/compat/gso.c
index c52b2b1..06b6d2c 100644
--- a/datapath/linux/compat/gso.c
+++ b/datapath/linux/compat/gso.c
@@ -39,7 +39,6 @@
 #include <net/xfrm.h>
 
 #include "gso.h"
-#include "vlan.h"
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) && \
 	!defined(HAVE_VLAN_BUG_WORKAROUND)
@@ -114,7 +113,7 @@ int rpl_dev_queue_xmit(struct sk_buff *skb)
 							skb_vlan_tag_get(skb));
 			if (unlikely(!skb))
 				return err;
-			vlan_set_tci(skb, 0);
+			skb->vlan_tci = 0;
 		}
 
 		/* As of v3.11 the kernel provides an mpls_features field in
diff --git a/datapath/linux/compat/include/linux/netdevice.h b/datapath/linux/compat/include/linux/netdevice.h
index 19a7b8e..581d7a0 100644
--- a/datapath/linux/compat/include/linux/netdevice.h
+++ b/datapath/linux/compat/include/linux/netdevice.h
@@ -169,13 +169,7 @@ static inline struct net_device *netdev_notifier_info_to_dev(void *info)
 
 #include <linux/u64_stats_sync.h>
 
-struct pcpu_sw_netstats {
-	u64     rx_packets;
-	u64     rx_bytes;
-	u64     tx_packets;
-	u64     tx_bytes;
-	struct u64_stats_sync   syncp;
-};
+#define pcpu_sw_netstats pcpu_tstats
 #endif
 
 #if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,0)
diff --git a/datapath/linux/compat/include/net/net_namespace.h b/datapath/linux/compat/include/net/net_namespace.h
index 9f50872..4270722 100644
--- a/datapath/linux/compat/include/net/net_namespace.h
+++ b/datapath/linux/compat/include/net/net_namespace.h
@@ -3,57 +3,6 @@
 
 #include_next <net/net_namespace.h>
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
-/* for 2.6.32* */
-struct rpl_pernet_operations {
-	int (*init)(struct net *net);
-	void (*exit)(struct net *net);
-	int *id;
-	size_t size;
-	struct pernet_operations ops;
-};
-#define pernet_operations rpl_pernet_operations
-
-#define register_pernet_device rpl_register_pernet_gen_device
-#define unregister_pernet_device rpl_unregister_pernet_gen_device
-
-#define register_pernet_subsys rpl_register_pernet_gen_device
-#define unregister_pernet_subsys rpl_unregister_pernet_gen_device
-
-#define compat_init_net ovs_compat_init_net
-int ovs_compat_init_net(struct net *net, struct rpl_pernet_operations *pnet);
-#define compat_exit_net ovs_compat_exit_net
-void ovs_compat_exit_net(struct net *net, struct rpl_pernet_operations *pnet);
-
-#define DEFINE_COMPAT_PNET_REG_FUNC(TYPE)					\
-									\
-static struct rpl_pernet_operations *pnet_gen_##TYPE;			\
-static int compat_init_net_gen_##TYPE(struct net *net)	\
-{									\
-	return compat_init_net(net, pnet_gen_##TYPE);			\
-}									\
-									\
-static void compat_exit_net_gen_##TYPE(struct net *net)	\
-{									\
-	compat_exit_net(net, pnet_gen_##TYPE);				\
-}									\
-									\
-static int rpl_register_pernet_gen_##TYPE(struct rpl_pernet_operations *rpl_pnet)	\
-{										\
-	pnet_gen_##TYPE = rpl_pnet;						\
-	rpl_pnet->ops.init = compat_init_net_gen_##TYPE;			\
-	rpl_pnet->ops.exit = compat_exit_net_gen_##TYPE;			\
-	return register_pernet_gen_##TYPE(pnet_gen_##TYPE->id, &rpl_pnet->ops); \
-}											\
-											\
-static void rpl_unregister_pernet_gen_##TYPE(struct rpl_pernet_operations *rpl_pnet)		\
-{											\
-	unregister_pernet_gen_##TYPE(*pnet_gen_##TYPE->id, &rpl_pnet->ops);		\
-}
-#else
-#define DEFINE_COMPAT_PNET_REG_FUNC(TYPE)
-#endif /* 2.6.33 */
-
 #ifndef HAVE_POSSIBLE_NET_T
 typedef struct {
 #ifdef CONFIG_NET_NS
diff --git a/datapath/linux/compat/include/net/vxlan.h b/datapath/linux/compat/include/net/vxlan.h
index b50cd17..75a5a7a 100644
--- a/datapath/linux/compat/include/net/vxlan.h
+++ b/datapath/linux/compat/include/net/vxlan.h
@@ -220,7 +220,7 @@ struct net_device *rpl_vxlan_dev_create(struct net *net, const char *name,
 
 static inline __be16 vxlan_dev_dst_port(struct vxlan_dev *vxlan)
 {
-	return inet_sport(vxlan->vn_sock->sock->sk);
+	return inet_sk(vxlan->vn_sock->sock->sk)->inet_sport;
 }
 
 static inline netdev_features_t vxlan_features_check(struct sk_buff *skb,
@@ -228,7 +228,7 @@ static inline netdev_features_t vxlan_features_check(struct sk_buff *skb,
 {
 	u8 l4_hdr = 0;
 
-	if (!skb_encapsulation(skb))
+	if (!skb->encapsulation)
 		return features;
 
 	switch (vlan_get_protocol(skb)) {
diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c
index f6a841f..2e13843 100644
--- a/datapath/linux/compat/ip_gre.c
+++ b/datapath/linux/compat/ip_gre.c
@@ -289,7 +289,7 @@ netdev_tx_t rpl_gre_fb_xmit(struct sk_buff *skb)
 
 	tunnel_hlen = ip_gre_calc_hlen(key->tun_flags);
 
-	min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len
+	min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
 			+ tunnel_hlen + sizeof(struct iphdr)
 			+ (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);
 	if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
@@ -647,8 +647,6 @@ static struct pernet_operations ipgre_tap_net_ops = {
 	.size = sizeof(struct ip_tunnel_net),
 };
 
-DEFINE_COMPAT_PNET_REG_FUNC(device);
-
 int rpl_ipgre_init(void)
 {
 	int err;
diff --git a/datapath/linux/compat/ip_tunnel.c b/datapath/linux/compat/ip_tunnel.c
index 8190937..4ed0068 100644
--- a/datapath/linux/compat/ip_tunnel.c
+++ b/datapath/linux/compat/ip_tunnel.c
@@ -113,7 +113,7 @@ static int ip_tunnel_bind_dev(struct net_device *dev)
 		rt = ip_route_output_key(tunnel->net, &fl4);
 
 		if (!IS_ERR(rt)) {
-			tdev = rt_dst(rt).dev;
+			tdev = rt->dst.dev;
 			ip_rt_put(rt);
 		}
 		if (dev->type != ARPHRD_ETHER)
diff --git a/datapath/linux/compat/ip_tunnels_core.c b/datapath/linux/compat/ip_tunnels_core.c
index 179fa47..0858d02 100644
--- a/datapath/linux/compat/ip_tunnels_core.c
+++ b/datapath/linux/compat/ip_tunnels_core.c
@@ -19,6 +19,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/if_vlan.h>
 #include <linux/in.h>
 #include <linux/in_route.h>
 #include <linux/inetdevice.h>
@@ -48,7 +49,7 @@ int rpl_iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
 	skb_scrub_packet(skb, xnet);
 
 	skb_clear_hash(skb);
-	skb_dst_set(skb, &rt_dst(rt));
+	skb_dst_set(skb, &rt->dst);
 
 #if 0
 	/* Do not clear ovs_skb_cb.  It will be done in gso code. */
@@ -71,7 +72,7 @@ int rpl_iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
 	iph->ttl	=	ttl;
 
 #ifdef HAVE_IP_SELECT_IDENT_USING_DST_ENTRY
-	__ip_select_ident(iph, &rt_dst(rt), (skb_shinfo(skb)->gso_segs ?: 1) - 1);
+	__ip_select_ident(iph, &rt->dst, (skb_shinfo(skb)->gso_segs ?: 1) - 1);
 #elif defined(HAVE_IP_SELECT_IDENT_USING_NET)
 	__ip_select_ident(dev_net(rt->dst.dev), iph,
 			  skb_shinfo(skb)->gso_segs ?: 1);
@@ -167,7 +168,7 @@ int rpl_iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_prot
 	secpath_reset(skb);
 	skb_clear_hash(skb);
 	skb_dst_drop(skb);
-	vlan_set_tci(skb, 0);
+	skb->vlan_tci = 0;
 	skb_set_queue_mapping(skb, 0);
 	skb->pkt_type = PACKET_HOST;
 	return 0;
@@ -181,7 +182,7 @@ bool ovs_skb_is_encapsulated(struct sk_buff *skb)
 	/* checking for inner protocol should be sufficient on newer kernel, but
 	 * old kernel just set encapsulation bit.
 	 */
-	return ovs_skb_get_inner_protocol(skb) || skb_encapsulation(skb);
+	return ovs_skb_get_inner_protocol(skb) || skb->encapsulation;
 }
 EXPORT_SYMBOL_GPL(ovs_skb_is_encapsulated);
 
diff --git a/datapath/linux/compat/lisp.c b/datapath/linux/compat/lisp.c
index fa6da6c..a90104d 100644
--- a/datapath/linux/compat/lisp.c
+++ b/datapath/linux/compat/lisp.c
@@ -17,6 +17,7 @@
 
 #include <linux/version.h>
 
+#include <linux/etherdevice.h>
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/net.h>
@@ -310,7 +311,7 @@ netdev_tx_t rpl_lisp_xmit(struct sk_buff *skb)
 		goto error;
 	}
 
-	min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len
+	min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
 		+ sizeof(struct iphdr) + LISP_HLEN;
 
 	if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
@@ -327,7 +328,7 @@ netdev_tx_t rpl_lisp_xmit(struct sk_buff *skb)
 	/* Reset l2 headers. */
 	skb_pull(skb, network_offset);
 	skb_reset_mac_header(skb);
-	vlan_set_tci(skb, 0);
+	skb->vlan_tci = 0;
 
 	skb = udp_tunnel_handle_offloads(skb, false, 0, false);
 	if (IS_ERR(skb)) {
@@ -697,7 +698,6 @@ static struct pernet_operations lisp_net_ops = {
 	.size = sizeof(struct lisp_net),
 };
 
-DEFINE_COMPAT_PNET_REG_FUNC(device)
 int rpl_lisp_init_module(void)
 {
 	int rc;
diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c
index 769b76f..07a0b7c 100644
--- a/datapath/linux/compat/vxlan.c
+++ b/datapath/linux/compat/vxlan.c
@@ -199,7 +199,7 @@ static struct vxlan_sock *vxlan_find_sock(struct net *net, sa_family_t family,
 	flags &= VXLAN_F_RCV_FLAGS;
 
 	hlist_for_each_entry_rcu(vs, vs_head(net, port), hlist) {
-		if (inet_sport(vs->sock->sk) == port &&
+		if (inet_sk(vs->sock->sk)->inet_sport == port &&
 		    vxlan_get_sk_family(vs) == family &&
 		    vs->flags == flags)
 			return vs;
@@ -1152,7 +1152,7 @@ static int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *sk
 		}
 	}
 
-	min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len
+	min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
 			+ VXLAN_HLEN + sizeof(struct iphdr)
 			+ (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);
 
@@ -1306,7 +1306,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 			goto tx_error;
 		}
 
-		if (rt_dst(rt).dev == dev) {
+		if (rt->dst.dev == dev) {
 			netdev_dbg(dev, "circular route to %pI4\n",
 				   &dst->sin.sin_addr.s_addr);
 			dev->stats.collisions++;
@@ -1330,7 +1330,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 		}
 
 		tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
-		ttl = ttl ? : ip4_dst_hoplimit(&rt_dst(rt));
+		ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
 		err = vxlan_xmit_skb(rt, sk, skb, fl4.saddr,
 				     dst->sin.sin_addr.s_addr, tos, ttl, df,
 				     src_port, dst_port, htonl(vni << 8), md,
@@ -2206,7 +2206,6 @@ static struct pernet_operations vxlan_net_ops = {
 	.size = sizeof(struct vxlan_net),
 };
 
-DEFINE_COMPAT_PNET_REG_FUNC(device)
 int rpl_vxlan_init_module(void)
 {
 	int rc;
diff --git a/datapath/vlan.h b/datapath/vlan.h
deleted file mode 100644
index 13ae6a7..0000000
--- a/datapath/vlan.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2007-2011 Nicira, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- */
-
-#ifndef VLAN_H
-#define VLAN_H 1
-
-#include <linux/if_vlan.h>
-#include <linux/skbuff.h>
-#include <linux/version.h>
-
-/**
- * DOC: VLAN tag manipulation.
- *
- * &struct sk_buff handling of VLAN tags has evolved over time:
- *
- * In 2.6.26 and earlier, VLAN tags did not have any generic representation in
- * an skb, other than as a raw 802.1Q header inside the packet data.
- *
- * In 2.6.27 &struct sk_buff added a @vlan_tci member.  Between 2.6.27 and
- * 2.6.32, its value was the raw contents of the 802.1Q TCI field, or zero if
- * no 802.1Q header was present.  This worked OK except for the corner case of
- * an 802.1Q header with an all-0-bits TCI, which could not be represented.
- *
- * In 2.6.33, @vlan_tci semantics changed.  Now, if an 802.1Q header is
- * present, then the VLAN_TAG_PRESENT bit is always set.  This fixes the
- * all-0-bits TCI corner case.
- *
- * For compatibility we emulate the 2.6.33+ behavior on earlier kernel
- * versions.  The client must not access @vlan_tci directly.  Instead, use
- * vlan_get_tci() to read it or vlan_set_tci() to write it, with semantics
- * equivalent to those on 2.6.33+.
- */
-
-static inline u16 vlan_get_tci(struct sk_buff *skb)
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
-	if (skb->vlan_tci)
-		return skb->vlan_tci | VLAN_TAG_PRESENT;
-#endif
-	return skb->vlan_tci;
-}
-
-static inline void vlan_set_tci(struct sk_buff *skb, u16 vlan_tci)
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
-	vlan_tci &= ~VLAN_TAG_PRESENT;
-#endif
-	skb->vlan_tci = vlan_tci;
-}
-#endif /* vlan.h */
diff --git a/datapath/vport-geneve.c b/datapath/vport-geneve.c
index 392d750..e65e43d 100644
--- a/datapath/vport-geneve.c
+++ b/datapath/vport-geneve.c
@@ -34,7 +34,7 @@ static struct vport_ops ovs_geneve_vport_ops;
  * @dst_port: destination port.
  */
 struct geneve_port {
-	u16 port_no;
+	u16 dst_port;
 };
 
 static inline struct geneve_port *geneve_vport(const struct vport *vport)
@@ -47,7 +47,7 @@ static int geneve_get_options(const struct vport *vport,
 {
 	struct geneve_port *geneve_port = geneve_vport(vport);
 
-	if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, geneve_port->port_no))
+	if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, geneve_port->dst_port))
 		return -EMSGSIZE;
 	return 0;
 }
@@ -57,7 +57,7 @@ static int geneve_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
 {
 	struct geneve_port *geneve_port = geneve_vport(vport);
 	struct net *net = ovs_dp_get_net(vport->dp);
-	__be16 dport = htons(geneve_port->port_no);
+	__be16 dport = htons(geneve_port->dst_port);
 	__be16 sport = udp_flow_src_port(net, skb, 1, USHRT_MAX, true);
 
 	return ovs_tunnel_get_egress_info(upcall, ovs_dp_get_net(vport->dp),
@@ -95,7 +95,7 @@ static struct vport *geneve_tnl_create(const struct vport_parms *parms)
 		return vport;
 
 	geneve_port = geneve_vport(vport);
-	geneve_port->port_no = dst_port;
+	geneve_port->dst_port = dst_port;
 
 	rtnl_lock();
 	dev = geneve_dev_create_fb(net, parms->name, NET_NAME_USER, dst_port);
diff --git a/datapath/vport-internal_dev.c b/datapath/vport-internal_dev.c
index 7f21679..ec76398 100644
--- a/datapath/vport-internal_dev.c
+++ b/datapath/vport-internal_dev.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2015 Nicira, Inc.
+ * Copyright (c) 2007-2012 Nicira, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public
@@ -23,9 +23,6 @@
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/skbuff.h>
-#include <linux/percpu.h>
-#include <linux/u64_stats_sync.h>
-#include <linux/netdev_features.h>
 
 #include <net/dst.h>
 #include <net/xfrm.h>
@@ -57,16 +54,12 @@ static int internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev)
 	rcu_read_unlock();
 
 	if (likely(!err)) {
-#ifdef HAVE_DEV_TSTATS
-		struct pcpu_sw_netstats *tstats;
-
-		tstats = this_cpu_ptr((struct pcpu_sw_netstats __percpu *)netdev->tstats);
+		struct pcpu_sw_netstats *tstats = this_cpu_ptr(netdev->tstats);
 
 		u64_stats_update_begin(&tstats->syncp);
 		tstats->tx_bytes += len;
 		tstats->tx_packets++;
 		u64_stats_update_end(&tstats->syncp);
-#endif
 	} else {
 		netdev->stats.tx_errors++;
 	}
@@ -94,14 +87,6 @@ static void internal_dev_getinfo(struct net_device *netdev,
 static const struct ethtool_ops internal_dev_ethtool_ops = {
 	.get_drvinfo	= internal_dev_getinfo,
 	.get_link	= ethtool_op_get_link,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)
-	.get_sg		= ethtool_op_get_sg,
-	.set_sg		= ethtool_op_set_sg,
-	.get_tx_csum	= ethtool_op_get_tx_csum,
-	.set_tx_csum	= ethtool_op_set_tx_hw_csum,
-	.get_tso	= ethtool_op_get_tso,
-	.set_tso	= ethtool_op_set_tso,
-#endif
 };
 
 static int internal_dev_change_mtu(struct net_device *netdev, int new_mtu)
@@ -121,32 +106,45 @@ static void internal_dev_destructor(struct net_device *dev)
 	free_netdev(dev);
 }
 
-#ifdef HAVE_DEV_TSTATS
-static int internal_dev_init(struct net_device *dev)
+static struct rtnl_link_stats64 *
+internal_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
 {
-	dev->tstats = (typeof(dev->tstats)) netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
-	if (!dev->tstats)
-		return -ENOMEM;
-	return 0;
-}
+	int i;
+
+	memset(stats, 0, sizeof(*stats));
+	stats->rx_errors  = dev->stats.rx_errors;
+	stats->tx_errors  = dev->stats.tx_errors;
+	stats->tx_dropped = dev->stats.tx_dropped;
+	stats->rx_dropped = dev->stats.rx_dropped;
+
+	for_each_possible_cpu(i) {
+		const struct pcpu_sw_netstats *percpu_stats;
+		struct pcpu_sw_netstats local_stats;
+		unsigned int start;
+
+		percpu_stats = per_cpu_ptr(dev->tstats, i);
+
+		do {
+			start = u64_stats_fetch_begin_irq(&percpu_stats->syncp);
+			local_stats = *percpu_stats;
+		} while (u64_stats_fetch_retry_irq(&percpu_stats->syncp, start));
+
+		stats->rx_bytes         += local_stats.rx_bytes;
+		stats->rx_packets       += local_stats.rx_packets;
+		stats->tx_bytes         += local_stats.tx_bytes;
+		stats->tx_packets       += local_stats.tx_packets;
+	}
 
-static void internal_dev_uninit(struct net_device *dev)
-{
-	free_percpu(dev->tstats);
+	return stats;
 }
-#endif
 
 static const struct net_device_ops internal_dev_netdev_ops = {
-#ifdef HAVE_DEV_TSTATS
-	.ndo_init = internal_dev_init,
-	.ndo_uninit = internal_dev_uninit,
-	.ndo_get_stats64 = ip_tunnel_get_stats64,
-#endif
 	.ndo_open = internal_dev_open,
 	.ndo_stop = internal_dev_stop,
 	.ndo_start_xmit = internal_dev_xmit,
 	.ndo_set_mac_address = eth_mac_addr,
 	.ndo_change_mtu = internal_dev_change_mtu,
+	.ndo_get_stats64 = internal_get_stats,
 };
 
 static struct rtnl_link_ops internal_dev_link_ops __read_mostly = {
@@ -171,14 +169,10 @@ static void do_setup(struct net_device *netdev)
 			   NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ENCAP_ALL;
 
 	netdev->vlan_features = netdev->features;
-	netdev->features |= NETIF_F_HW_VLAN_CTAG_TX;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
 	netdev->hw_enc_features = netdev->features;
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+	netdev->features |= NETIF_F_HW_VLAN_CTAG_TX;
 	netdev->hw_features = netdev->features & ~NETIF_F_LLTX;
-#endif
+
 	eth_hw_addr_random(netdev);
 }
 
@@ -200,6 +194,11 @@ static struct vport *internal_dev_create(const struct vport_parms *parms)
 		err = -ENOMEM;
 		goto error_free_vport;
 	}
+	vport->dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
+	if (!vport->dev->tstats) {
+		err = -ENOMEM;
+		goto error_free_netdev;
+	}
 
 	dev_net_set(vport->dev, ovs_dp_get_net(vport->dp));
 	internal_dev = internal_dev_priv(vport->dev);
@@ -212,7 +211,7 @@ static struct vport *internal_dev_create(const struct vport_parms *parms)
 	rtnl_lock();
 	err = register_netdevice(vport->dev);
 	if (err)
-		goto error_free_netdev;
+		goto error_unlock;
 
 	dev_set_promiscuity(vport->dev, 1);
 	rtnl_unlock();
@@ -220,8 +219,10 @@ static struct vport *internal_dev_create(const struct vport_parms *parms)
 
 	return vport;
 
-error_free_netdev:
+error_unlock:
 	rtnl_unlock();
+	free_percpu(vport->dev->tstats);
+error_free_netdev:
 	free_netdev(vport->dev);
 error_free_vport:
 	ovs_vport_free(vport);
@@ -237,16 +238,14 @@ static void internal_dev_destroy(struct vport *vport)
 
 	/* unregister_netdevice() waits for an RCU grace period. */
 	unregister_netdevice(vport->dev);
-
+	free_percpu(vport->dev->tstats);
 	rtnl_unlock();
 }
 
 static netdev_tx_t internal_dev_recv(struct sk_buff *skb)
 {
 	struct net_device *netdev = skb->dev;
-#ifdef HAVE_DEV_TSTATS
 	struct pcpu_sw_netstats *stats;
-#endif
 
 	if (unlikely(!(netdev->flags & IFF_UP))) {
 		kfree_skb(skb);
@@ -254,22 +253,6 @@ static netdev_tx_t internal_dev_recv(struct sk_buff *skb)
 		return NETDEV_TX_OK;
 	}
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
-	if (skb_vlan_tag_present(skb)) {
-		if (unlikely(!vlan_insert_tag_set_proto(skb,
-							skb->vlan_proto,
-							skb_vlan_tag_get(skb))))
-			return NETDEV_TX_OK;
-
-		if (skb->ip_summed == CHECKSUM_COMPLETE)
-			skb->csum = csum_add(skb->csum,
-					     csum_partial(skb->data + (2 * ETH_ALEN),
-							  VLAN_HLEN, 0));
-
-		vlan_set_tci(skb, 0);
-	}
-#endif
-
 	skb_dst_drop(skb);
 	nf_reset(skb);
 	secpath_reset(skb);
@@ -278,13 +261,11 @@ static netdev_tx_t internal_dev_recv(struct sk_buff *skb)
 	skb->protocol = eth_type_trans(skb, netdev);
 	skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
 
-#ifdef HAVE_DEV_TSTATS
-	stats = this_cpu_ptr((struct pcpu_sw_netstats __percpu *)netdev->tstats);
+	stats = this_cpu_ptr(netdev->tstats);
 	u64_stats_update_begin(&stats->syncp);
 	stats->rx_packets++;
 	stats->rx_bytes += skb->len;
 	u64_stats_update_end(&stats->syncp);
-#endif
 
 	netif_rx(skb);
 	return NETDEV_TX_OK;
diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c
index a1df79b..02917b0 100644
--- a/datapath/vport-netdev.c
+++ b/datapath/vport-netdev.c
@@ -26,6 +26,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/skbuff.h>
 #include <linux/openvswitch.h>
+#include <linux/export.h>
 
 #include <net/ip_tunnels.h>
 #include <net/rtnetlink.h>
@@ -83,8 +84,7 @@ static rx_handler_result_t netdev_frame_hook(struct sk_buff **pskb)
 	port_receive(skb);
 	return RX_HANDLER_CONSUMED;
 }
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) || \
-      defined HAVE_RHEL_OVS_HOOK
+#elif defined HAVE_RHEL_OVS_HOOK
 /* Called with rcu_read_lock and bottom-halves disabled. */
 static struct sk_buff *netdev_frame_hook(struct sk_buff *skb)
 {
@@ -94,18 +94,6 @@ static struct sk_buff *netdev_frame_hook(struct sk_buff *skb)
 	port_receive(skb);
 	return NULL;
 }
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
-/*
- * Used as br_handle_frame_hook.  (Cannot run bridge at the same time, even on
- * different set of devices!)
- */
-/* Called with rcu_read_lock and bottom-halves disabled. */
-static struct sk_buff *netdev_frame_hook(struct net_bridge_port *p,
-					 struct sk_buff *skb)
-{
-	port_receive(skb);
-	return NULL;
-}
 #else
 #error
 #endif
@@ -217,10 +205,8 @@ void ovs_netdev_tunnel_destroy(struct vport *vport)
 	 * underlying netdev deregistration; delete the link only
 	 * if it's not already shutting down.
 	 */
-
 	if (vport->dev->reg_state == NETREG_REGISTERED)
 		rtnl_delete_link(vport->dev);
-
 	dev_put(vport->dev);
 	vport->dev = NULL;
 	rtnl_unlock();
@@ -272,23 +258,3 @@ void ovs_netdev_exit(void)
 {
 	ovs_vport_ops_unregister(&ovs_netdev_vport_ops);
 }
-
-#if !defined HAVE_NETDEV_RX_HANDLER_REGISTER && \
-    !defined HAVE_RHEL_OVS_HOOK
-/*
- * Enforces, mutual exclusion with the Linux bridge module, by declaring and
- * exporting br_should_route_hook.  Because the bridge module also exports the
- * same symbol, the module loader will refuse to load both modules at the same
- * time (e.g. "bridge: exports duplicate symbol br_should_route_hook (owned by
- * openvswitch)").
- *
- * Before Linux 2.6.36, Open vSwitch cannot safely coexist with the Linux
- * bridge module, so openvswitch uses this macro in those versions.  In
- * Linux 2.6.36 and later, Open vSwitch can coexist with the bridge module.
- *
- * The use of "typeof" here avoids the need to track changes in the type of
- * br_should_route_hook over various kernel versions.
- */
-typeof(br_should_route_hook) br_should_route_hook;
-EXPORT_SYMBOL(br_should_route_hook);
-#endif
diff --git a/datapath/vport-netdev.h b/datapath/vport-netdev.h
index f8fbb86..04ad190 100644
--- a/datapath/vport-netdev.h
+++ b/datapath/vport-netdev.h
@@ -27,7 +27,6 @@
 struct vport *ovs_netdev_get_vport(struct net_device *dev);
 
 struct vport *ovs_netdev_link(struct vport *vport, const char *name);
-void ovs_netdev_send(struct vport *vport, struct sk_buff *skb);
 void ovs_netdev_detach_dev(struct vport *);
 
 int __init ovs_netdev_init(void);
diff --git a/datapath/vport.c b/datapath/vport.c
index 7fd9858..44b9dfb 100644
--- a/datapath/vport.c
+++ b/datapath/vport.c
@@ -33,8 +33,9 @@
 #include <net/lisp.h>
 #include <net/gre.h>
 #include <net/geneve.h>
-#include <net/vxlan.h>
+#include <net/route.h>
 #include <net/stt.h>
+#include <net/vxlan.h>
 
 #include "datapath.h"
 #include "gso.h"
@@ -375,14 +376,6 @@ int ovs_vport_get_options(const struct vport *vport, struct sk_buff *skb)
 	return 0;
 }
 
-static void vport_portids_destroy_rcu_cb(struct rcu_head *rcu)
-{
-	struct vport_portids *ids = container_of(rcu, struct vport_portids,
-						 rcu);
-
-	kfree(ids);
-}
-
 /**
  *	ovs_vport_set_upcall_portids - set upcall portids of @vport.
  *
@@ -417,7 +410,7 @@ int ovs_vport_set_upcall_portids(struct vport *vport, const struct nlattr *ids)
 	rcu_assign_pointer(vport->upcall_portids, vport_portids);
 
 	if (old)
-		call_rcu(&old->rcu, vport_portids_destroy_rcu_cb);
+		kfree_rcu(old, rcu);
 	return 0;
 }
 
@@ -532,6 +525,25 @@ void ovs_vport_deferred_free(struct vport *vport)
 }
 EXPORT_SYMBOL_GPL(ovs_vport_deferred_free);
 
+static struct rtable *ovs_tunnel_route_lookup(struct net *net,
+					      const struct ip_tunnel_key *key,
+					      u32 mark,
+					      struct flowi4 *fl,
+					      u8 protocol)
+{
+	struct rtable *rt;
+
+	memset(fl, 0, sizeof(*fl));
+	fl->daddr = key->u.ipv4.dst;
+	fl->saddr = key->u.ipv4.src;
+	fl->flowi4_tos = RT_TOS(key->tos);
+	fl->flowi4_mark = mark;
+	fl->flowi4_proto = protocol;
+
+	rt = ip_route_output_key(net, fl);
+	return rt;
+}
+
 int ovs_tunnel_get_egress_info(struct dp_upcall_info *upcall,
 			       struct net *net,
 			       struct sk_buff *skb,
diff --git a/datapath/vport.h b/datapath/vport.h
index 33c3935..6e80493 100644
--- a/datapath/vport.h
+++ b/datapath/vport.h
@@ -27,7 +27,6 @@
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 #include <linux/u64_stats_sync.h>
-#include <net/route.h>
 
 #include "datapath.h"
 
@@ -81,7 +80,7 @@ struct vport_portids {
 
 /**
  * struct vport - one port within a datapath
- * @rcu: RCU callback head for deferred destruction.
+ * @dev: Pointer to net_device.
  * @dp: Datapath to which this port belongs.
  * @upcall_portids: RCU protected 'struct vport_portids'.
  * @port_no: Index into @dp's @ports array.
@@ -89,6 +88,7 @@ struct vport_portids {
  * @dp_hash_node: Element in @datapath->ports hash table in datapath.c.
  * @ops: Class structure.
  * @detach_list: list used for detaching vport in net-exit call.
+ * @rcu: RCU callback head for deferred destruction.
  */
 struct vport {
 	struct net_device *dev;
@@ -153,9 +153,9 @@ struct vport_ops {
 	int (*set_options)(struct vport *, struct nlattr *);
 	int (*get_options)(const struct vport *, struct sk_buff *);
 
+	netdev_tx_t (*send)(struct sk_buff *skb);
 	int (*get_egress_tun_info)(struct vport *, struct sk_buff *,
 				   struct dp_upcall_info *upcall);
-	netdev_tx_t (*send)(struct sk_buff *skb);
 
 	struct module *owner;
 	struct list_head list;
@@ -214,31 +214,12 @@ static inline const char *ovs_vport_name(struct vport *vport)
 
 int __ovs_vport_ops_register(struct vport_ops *ops);
 #define ovs_vport_ops_register(ops)		\
-({						\
-	(ops)->owner = THIS_MODULE;		\
-	__ovs_vport_ops_register(ops);		\
-})
+	({					\
+		(ops)->owner = THIS_MODULE;	\
+		__ovs_vport_ops_register(ops);	\
+	})
 
 void ovs_vport_ops_unregister(struct vport_ops *ops);
-
-static inline struct rtable *ovs_tunnel_route_lookup(struct net *net,
-						     const struct ip_tunnel_key *key,
-						     u32 mark,
-						     struct flowi4 *fl,
-						     u8 protocol)
-{
-	struct rtable *rt;
-
-	memset(fl, 0, sizeof(*fl));
-	fl->daddr = key->u.ipv4.dst;
-	fl->saddr = key->u.ipv4.src;
-	fl->flowi4_tos = RT_TOS(key->tos);
-	fl->flowi4_mark = mark;
-	fl->flowi4_proto = protocol;
-
-	rt = ip_route_output_key(net, fl);
-	return rt;
-}
-
 void ovs_vport_send(struct vport *vport, struct sk_buff *skb);
+
 #endif /* vport.h */
-- 
1.9.1





More information about the dev mailing list