[ovs-dev] [PATCH] datapath: Provide compatibility for kernels up to 3.17

Thomas Graf tgraf at noironetworks.com
Tue Sep 16 17:44:49 UTC 2014


Port datapath to work with kernrels up to 3.17 and use 3.16.2 as
the new kernel for CI testing.

Tested with 3.14, 3.16.2, and net-next (3.17).

Signed-off-by: Thomas Graf <tgraf at noironetworks.com>
Co-authored-by: Madhu Challa <challa at noironetworks.com>
---
 .travis.yml                                     |  2 +-
 .travis/build.sh                                |  6 ++--
 acinclude.m4                                    | 12 ++++++--
 datapath/linux/Modules.mk                       |  1 +
 datapath/linux/compat/include/linux/if.h        | 12 --------
 datapath/linux/compat/include/linux/netdevice.h | 14 ++++++++++
 datapath/linux/compat/include/linux/skbuff.h    |  4 +++
 datapath/linux/compat/include/net/ip_tunnels.h  |  2 +-
 datapath/linux/compat/include/net/udp.h         | 37 +++++++++++++++++++++++++
 datapath/linux/compat/include/net/vxlan.h       |  5 ++++
 datapath/linux/compat/ip_tunnels_core.c         |  2 +-
 datapath/linux/compat/vxlan.c                   |  3 +-
 datapath/vport-geneve.c                         |  8 ++++--
 datapath/vport-gre.c                            |  2 +-
 datapath/vport-internal_dev.c                   |  7 ++++-
 datapath/vport-lisp.c                           |  2 +-
 datapath/vport-netdev.c                         |  3 +-
 datapath/vport-vxlan.c                          | 10 ++-----
 18 files changed, 96 insertions(+), 36 deletions(-)
 create mode 100644 datapath/linux/compat/include/net/udp.h

diff --git a/.travis.yml b/.travis.yml
index b66f821..4dfe15e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,7 +7,7 @@ before_install: ./.travis/prepare.sh
 
 env:
   - OPTS="--disable-ssl"
-  - TESTSUITE=1 KERNEL=1 OPTS="--with-linux=./linux-3.14.7"
+  - TESTSUITE=1 KERNEL=1 OPTS="--with-linux=./linux-3.16.2"
   - KERNEL=1 DPDK=1 OPTS="--with-dpdk=./dpdk-1.7.0/build"
 
 script: ./.travis/build.sh $OPTS
diff --git a/.travis/build.sh b/.travis/build.sh
index 0a23969..b7ce5a0 100755
--- a/.travis/build.sh
+++ b/.travis/build.sh
@@ -7,9 +7,9 @@ CFLAGS="-Werror"
 
 function install_kernel()
 {
-    wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.14.7.tar.gz
-    tar xzvf linux-3.14.7.tar.gz > /dev/null
-    cd linux-3.14.7
+    wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.16.2.tar.gz
+    tar xzvf linux-3.16.2.tar.gz > /dev/null
+    cd linux-3.16.2
     make allmodconfig
     make net/openvswitch/
     KERNELSRC=$(pwd)
diff --git a/acinclude.m4 b/acinclude.m4
index e3a694b..6e31d88 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -134,10 +134,10 @@ AC_DEFUN([OVS_CHECK_LINUX], [
     AC_MSG_RESULT([$kversion])
 
     if test "$version" -ge 3; then
-       if test "$version" = 3 && test "$patchlevel" -le 14; then
+       if test "$version" = 3 && test "$patchlevel" -le 17; then
           : # Linux 3.x
        else
-         AC_ERROR([Linux kernel in $KBUILD is version $kversion, but version newer than 3.14.x is not supported (please refer to the FAQ for advice)])
+         AC_ERROR([Linux kernel in $KBUILD is version $kversion, but version newer than 3.17.x is not supported (please refer to the FAQ for advice)])
        fi
     else
        if test "$version" -le 1 || test "$patchlevel" -le 5 || test "$sublevel" -le 31; then
@@ -370,6 +370,14 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
 
   OVS_GREP_IFELSE([$KSRC/include/linux/openvswitch.h], [openvswitch_handle_frame_hook],
                   [OVS_DEFINE([HAVE_RHEL_OVS_HOOK])])
+  OVS_GREP_IFELSE([$KSRC/include/net/vxlan.h], [bool xnet],
+                  [OVS_DEFINE([HAVE_VXLAN_XMIT_SKB_XNET_ARG])])
+  OVS_GREP_IFELSE([$KSRC/include/net/udp.h], [udp_flow_src_port],
+                  [OVS_DEFINE([HAVE_UDP_FLOW_SRC_PORT])])
+  OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [ignore_df:1],
+                  [OVS_DEFINE([HAVE_IGNORE_DF_RENAME])])
+  OVS_GREP_IFELSE([$KSRC/include/uapi/linux/netdevice.h], [NET_NAME_UNKNOWN],
+                  [OVS_DEFINE([HAVE_NET_NAME_UNKNOWN])])
 
   OVS_CHECK_LOG2_H
 
diff --git a/datapath/linux/Modules.mk b/datapath/linux/Modules.mk
index f7c64e2..274b1f1 100644
--- a/datapath/linux/Modules.mk
+++ b/datapath/linux/Modules.mk
@@ -72,6 +72,7 @@ openvswitch_headers += \
 	linux/compat/include/net/ipv6.h \
 	linux/compat/include/net/net_namespace.h \
 	linux/compat/include/net/netlink.h \
+	linux/compat/include/net/udp.h \
 	linux/compat/include/net/sock.h \
 	linux/compat/include/net/vxlan.h \
 	linux/compat/include/net/sctp/checksum.h
diff --git a/datapath/linux/compat/include/linux/if.h b/datapath/linux/compat/include/linux/if.h
index c4c656c..3beb61d 100644
--- a/datapath/linux/compat/include/linux/if.h
+++ b/datapath/linux/compat/include/linux/if.h
@@ -3,16 +3,4 @@
 
 #include_next <linux/if.h>
 
-#ifndef IFF_TX_SKB_SHARING
-#define IFF_TX_SKB_SHARING 0
-#endif
-
-#ifndef IFF_OVS_DATAPATH
-#define IFF_OVS_DATAPATH 0
-#endif
-
-#ifndef IFF_LIVE_ADDR_CHANGE
-#define IFF_LIVE_ADDR_CHANGE 0
-#endif
-
 #endif
diff --git a/datapath/linux/compat/include/linux/netdevice.h b/datapath/linux/compat/include/linux/netdevice.h
index 5502288..d01434e 100644
--- a/datapath/linux/compat/include/linux/netdevice.h
+++ b/datapath/linux/compat/include/linux/netdevice.h
@@ -8,6 +8,20 @@ struct net;
 
 #include <linux/version.h>
 
+#ifndef IFF_TX_SKB_SHARING
+#define IFF_TX_SKB_SHARING 0
+#endif
+
+#ifndef IFF_OVS_DATAPATH
+#define IFF_OVS_DATAPATH 0
+#else
+#define HAVE_OVS_DATAPATH
+#endif
+
+#ifndef IFF_LIVE_ADDR_CHANGE
+#define IFF_LIVE_ADDR_CHANGE 0
+#endif
+
 #ifndef to_net_dev
 #define to_net_dev(class) container_of(class, struct net_device, NETDEV_DEV_MEMBER)
 #endif
diff --git a/datapath/linux/compat/include/linux/skbuff.h b/datapath/linux/compat/include/linux/skbuff.h
index 9abd582..8fce98c 100644
--- a/datapath/linux/compat/include/linux/skbuff.h
+++ b/datapath/linux/compat/include/linux/skbuff.h
@@ -6,6 +6,10 @@
 #include <linux/jhash.h>
 #include <linux/version.h>
 
+#ifdef HAVE_IGNORE_DF_RENAME
+#define local_df ignore_df
+#endif
+
 #ifndef HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET
 static inline void skb_copy_from_linear_data_offset(const struct sk_buff *skb,
 						    const int offset, void *to,
diff --git a/datapath/linux/compat/include/net/ip_tunnels.h b/datapath/linux/compat/include/net/ip_tunnels.h
index 2a6470a..2a28a72 100644
--- a/datapath/linux/compat/include/net/ip_tunnels.h
+++ b/datapath/linux/compat/include/net/ip_tunnels.h
@@ -36,7 +36,7 @@ struct tnl_ptk_info {
 #define PACKET_RCVD	0
 #define PACKET_REJECT	1
 
-int iptunnel_xmit(struct rtable *rt,
+int iptunnel_xmit(struct sock *sk, struct rtable *rt,
 		  struct sk_buff *skb,
 		  __be32 src, __be32 dst, __u8 proto,
 		  __u8 tos, __u8 ttl, __be16 df, bool xnet);
diff --git a/datapath/linux/compat/include/net/udp.h b/datapath/linux/compat/include/net/udp.h
new file mode 100644
index 0000000..88174ae
--- /dev/null
+++ b/datapath/linux/compat/include/net/udp.h
@@ -0,0 +1,37 @@
+#ifndef __NET_UDP_WRAPPER_H
+#define __NET_UDP_WRAPPER_H  1
+
+#include_next <net/udp.h>
+
+#ifndef HAVE_UDP_FLOW_SRC_PORT
+static inline __be16 udp_flow_src_port(struct net *net, struct sk_buff *skb,
+                                       int min, int max, bool use_eth)
+{
+	u32 hash;
+
+	if (min >= max) {
+		/* Use default range */
+		inet_get_local_port_range(net, &min, &max);
+	}
+
+	hash = skb_get_hash(skb);
+	if (unlikely(!hash) && use_eth) {
+		/* Can't find a normal hash, caller has indicated an Ethernet
+		 * packet so use that to compute a hash.
+		 */
+		hash = jhash(skb->data, 2 * ETH_ALEN,
+			     (__force u32) skb->protocol);
+	}
+
+	/* Since this is being sent on the wire obfuscate hash a bit
+	 * to minimize possbility that any useful information to an
+	 * attacker is leaked. Only upper 16 bits are relevant in the
+	 * computation for 16 bit port value.
+	 */
+	hash ^= hash << 16;
+
+	return htons((((u64) hash * (max - min)) >> 32) + min);
+}
+#endif
+
+#endif
diff --git a/datapath/linux/compat/include/net/vxlan.h b/datapath/linux/compat/include/net/vxlan.h
index d64630b..2e56a9b 100644
--- a/datapath/linux/compat/include/net/vxlan.h
+++ b/datapath/linux/compat/include/net/vxlan.h
@@ -19,8 +19,13 @@ static inline int rpl_vxlan_xmit_skb(struct vxlan_sock *vs,
 		return -ENOSYS;
 	}
 
+#ifdef HAVE_VXLAN_XMIT_SKB_XNET_ARG
+	return vxlan_xmit_skb(vs, rt, skb, src, dst, tos, ttl, df,
+			      src_port, dst_port, vni, false);
+#else
 	return vxlan_xmit_skb(vs, rt, skb, src, dst, tos, ttl, df,
 			      src_port, dst_port, vni);
+#endif
 }
 
 #define vxlan_xmit_skb rpl_vxlan_xmit_skb
diff --git a/datapath/linux/compat/ip_tunnels_core.c b/datapath/linux/compat/ip_tunnels_core.c
index a70aefc..549df3d 100644
--- a/datapath/linux/compat/ip_tunnels_core.c
+++ b/datapath/linux/compat/ip_tunnels_core.c
@@ -37,7 +37,7 @@
 #include "compat.h"
 #include "gso.h"
 
-int iptunnel_xmit(struct rtable *rt,
+int iptunnel_xmit(struct sock *sk, struct rtable *rt,
 		  struct sk_buff *skb,
 		  __be32 src, __be32 dst, __u8 proto,
 		  __u8 tos, __u8 ttl, __be16 df, bool xnet)
diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c
index b8b8fa7..9278c37 100644
--- a/datapath/linux/compat/vxlan.c
+++ b/datapath/linux/compat/vxlan.c
@@ -226,7 +226,8 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,
 	if (err)
 		return err;
 
-	return iptunnel_xmit(rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df, false);
+	return iptunnel_xmit(vs->sock->sk, rt, skb, src, dst, IPPROTO_UDP,
+			     tos, ttl, df, false);
 }
 
 static void rcu_free_vs(struct rcu_head *rcu)
diff --git a/datapath/vport-geneve.c b/datapath/vport-geneve.c
index ce5b509..6ed1e1f 100644
--- a/datapath/vport-geneve.c
+++ b/datapath/vport-geneve.c
@@ -132,12 +132,13 @@ static void geneve_build_header(const struct vport *vport,
 			      struct sk_buff *skb)
 {
 	struct geneve_port *geneve_port = geneve_vport(vport);
+	struct net *net = ovs_dp_get_net(vport->dp);
 	struct udphdr *udph = udp_hdr(skb);
 	struct genevehdr *geneveh = (struct genevehdr *)(udph + 1);
 	const struct ovs_tunnel_info *tun_info = OVS_CB(skb)->egress_tun_info;
 
 	udph->dest = inet_sport(geneve_port->sock->sk);
-	udph->source = vxlan_src_port(1, USHRT_MAX, skb);
+	udph->source = udp_flow_src_port(net, skb, 0, 0, true);
 	udph->check = 0;
 	udph->len = htons(skb->len - skb_transport_offset(skb));
 
@@ -423,7 +424,7 @@ static int geneve_send(struct vport *vport, struct sk_buff *skb)
 
 	df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
 
-	sent_len = iptunnel_xmit(rt, skb,
+	sent_len = iptunnel_xmit(skb->sk, rt, skb,
 			     saddr, tun_key->ipv4_dst,
 			     IPPROTO_UDP, tun_key->ipv4_tos,
 			     tun_key->ipv4_ttl,
@@ -447,6 +448,7 @@ static int geneve_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
 				      struct ovs_tunnel_info *egress_tun_info)
 {
 	struct geneve_port *geneve_port = geneve_vport(vport);
+	struct net *net = ovs_dp_get_net(vport->dp);
 
 	/*
 	 * Get tp_src and tp_dst, refert to geneve_build_header().
@@ -455,7 +457,7 @@ static int geneve_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
 					  ovs_dp_get_net(vport->dp),
 					  OVS_CB(skb)->egress_tun_info,
 					  IPPROTO_UDP, skb->mark,
-					  vxlan_src_port(1, USHRT_MAX, skb),
+					  udp_flow_src_port(net, skb, 0, 0, true),
 					  inet_sport(geneve_port->sock->sk));
 
 }
diff --git a/datapath/vport-gre.c b/datapath/vport-gre.c
index ce203b8..7decaa2 100644
--- a/datapath/vport-gre.c
+++ b/datapath/vport-gre.c
@@ -194,7 +194,7 @@ static int __send(struct vport *vport, struct sk_buff *skb,
 	df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
 	skb->local_df = 1;
 
-	return iptunnel_xmit(rt, skb, saddr,
+	return iptunnel_xmit(skb->sk, rt, skb, saddr,
 			     tun_key->ipv4_dst, IPPROTO_GRE,
 			     tun_key->ipv4_tos,
 			     tun_key->ipv4_ttl, df, false);
diff --git a/datapath/vport-internal_dev.c b/datapath/vport-internal_dev.c
index 8a454df..c9b35d3 100644
--- a/datapath/vport-internal_dev.c
+++ b/datapath/vport-internal_dev.c
@@ -151,7 +151,7 @@ static void do_setup(struct net_device *netdev)
 	netdev->priv_flags &= ~IFF_TX_SKB_SHARING;
 	netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
 	netdev->destructor = internal_dev_destructor;
-	SET_ETHTOOL_OPS(netdev, &internal_dev_ethtool_ops);
+	netdev->ethtool_ops = &internal_dev_ethtool_ops;
 	netdev->tx_queue_len = 0;
 
 	netdev->features = NETIF_F_LLTX | NETIF_F_SG | NETIF_F_FRAGLIST |
@@ -188,8 +188,13 @@ static struct vport *internal_dev_create(const struct vport_parms *parms)
 
 	netdev_vport = netdev_vport_priv(vport);
 
+#ifdef HAVE_NET_NAME_UNKNOWN
+	netdev_vport->dev = alloc_netdev(sizeof(struct internal_dev),
+					 parms->name, NET_NAME_UNKNOWN, do_setup);
+#else
 	netdev_vport->dev = alloc_netdev(sizeof(struct internal_dev),
 					 parms->name, do_setup);
+#endif
 	if (!netdev_vport->dev) {
 		err = -ENOMEM;
 		goto error_free_vport;
diff --git a/datapath/vport-lisp.c b/datapath/vport-lisp.c
index 3335aa5..d7b9b15 100644
--- a/datapath/vport-lisp.c
+++ b/datapath/vport-lisp.c
@@ -498,7 +498,7 @@ static int lisp_send(struct vport *vport, struct sk_buff *skb)
 	skb->local_df = 1;
 
 	df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
-	sent_len = iptunnel_xmit(rt, skb,
+	sent_len = iptunnel_xmit(skb->sk, rt, skb,
 			     saddr, tun_key->ipv4_dst,
 			     IPPROTO_UDP, tun_key->ipv4_tos,
 			     tun_key->ipv4_ttl, df, false);
diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c
index c15923b..a00276b 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/netdevice.h>
 
 #include <net/llc.h>
 
@@ -255,7 +256,7 @@ struct vport *ovs_netdev_get_vport(struct net_device *dev)
 {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) || \
     defined HAVE_RHEL_OVS_HOOK
-#if IFF_OVS_DATAPATH != 0
+#ifdef HAVE_OVS_DATAPATH
 	if (likely(dev->priv_flags & IFF_OVS_DATAPATH))
 #else
 	if (likely(rcu_access_pointer(dev->rx_handler) == netdev_frame_hook))
diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c
index 34dd919..60379a0 100644
--- a/datapath/vport-vxlan.c
+++ b/datapath/vport-vxlan.c
@@ -149,8 +149,6 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
 	__be16 src_port;
 	__be32 saddr;
 	__be16 df;
-	int port_min;
-	int port_max;
 	int err;
 
 	if (unlikely(!OVS_CB(skb)->egress_tun_info)) {
@@ -174,8 +172,7 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
 	df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
 	skb->local_df = 1;
 
-	inet_get_local_port_range(net, &port_min, &port_max);
-	src_port = vxlan_src_port(port_min, port_max, skb);
+	src_port = udp_flow_src_port(net, skb, 0, 0, true);
 
 	err = vxlan_xmit_skb(vxlan_port->vs, rt, skb,
 			     saddr, tun_key->ipv4_dst,
@@ -196,11 +193,8 @@ static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
 	struct vxlan_port *vxlan_port = vxlan_vport(vport);
 	__be16 dst_port = inet_sport(vxlan_port->vs->sock->sk);
 	__be16 src_port;
-	int port_min;
-	int port_max;
 
-	inet_get_local_port_range(net, &port_min, &port_max);
-	src_port = vxlan_src_port(port_min, port_max, skb);
+	src_port = udp_flow_src_port(net, skb, 0, 0, true);
 
 	return ovs_tunnel_get_egress_info(egress_tun_info, net,
 					  OVS_CB(skb)->egress_tun_info,
-- 
1.9.3




More information about the dev mailing list