[ovs-dev] [PATCH v2] datapath: Provide compatibility for kernels up to 3.17
Thomas Graf
tgraf at noironetworks.com
Thu Sep 18 12:48:56 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>
---
v2:
- Swapped ignore_df local_df compat direction
- Provide alloc_netdev() compat macro to avoid #ifdef
- iptunnel_xmit() version for > 3.12 && < 3.15
.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 | 21 ++++++++++++++
datapath/linux/compat/include/linux/skbuff.h | 4 +++
datapath/linux/compat/include/net/ip_tunnels.h | 14 +++++++++-
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 | 4 +--
datapath/vport-internal_dev.c | 4 +--
datapath/vport-lisp.c | 4 +--
datapath/vport-netdev.c | 3 +-
datapath/vport-vxlan.c | 12 ++------
18 files changed, 114 insertions(+), 40 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..6456542 100644
--- a/datapath/linux/compat/include/linux/netdevice.h
+++ b/datapath/linux/compat/include/linux/netdevice.h
@@ -8,10 +8,31 @@ 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
+#ifndef HAVE_NET_NAME_UNKNOWN
+#undef alloc_netdev
+#define NET_NAME_UNKNOWN 0
+#define alloc_netdev(sizeof_priv, name, name_assign_type, setup) \
+ alloc_netdev_mqs(sizeof_priv, name_assign_type, setup, 1, 1)
+#endif
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
extern void unregister_netdevice_queue(struct net_device *dev,
struct list_head *head);
diff --git a/datapath/linux/compat/include/linux/skbuff.h b/datapath/linux/compat/include/linux/skbuff.h
index 9abd582..18e75d6 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>
+#ifndef HAVE_IGNORE_DF_RENAME
+#define ignore_df local_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..5d0267d 100644
--- a/datapath/linux/compat/include/net/ip_tunnels.h
+++ b/datapath/linux/compat/include/net/ip_tunnels.h
@@ -4,6 +4,18 @@
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,12,0)
#include_next <net/ip_tunnels.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,15,0)
+static inline int rpl_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)
+{
+ return iptunnel_xmit(rt, skb, src, dst, proto, tos, ttl, df, xnet);
+}
+#define iptunnel_xmit rpl_iptunnel_xmit
+#endif
+
#else
#include <linux/if_tunnel.h>
@@ -36,7 +48,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..41c025d 100644
--- a/datapath/vport-gre.c
+++ b/datapath/vport-gre.c
@@ -192,9 +192,9 @@ 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;
+ skb->ignore_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..3a38138 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 |
@@ -189,7 +189,7 @@ static struct vport *internal_dev_create(const struct vport_parms *parms)
netdev_vport = netdev_vport_priv(vport);
netdev_vport->dev = alloc_netdev(sizeof(struct internal_dev),
- parms->name, do_setup);
+ parms->name, NET_NAME_UNKNOWN, do_setup);
if (!netdev_vport->dev) {
err = -ENOMEM;
goto error_free_vport;
diff --git a/datapath/vport-lisp.c b/datapath/vport-lisp.c
index 3335aa5..ad5cd23 100644
--- a/datapath/vport-lisp.c
+++ b/datapath/vport-lisp.c
@@ -495,10 +495,10 @@ static int lisp_send(struct vport *vport, struct sk_buff *skb)
if (err)
goto err_free_rt;
- skb->local_df = 1;
+ skb->ignore_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..8689853 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)) {
@@ -172,10 +170,9 @@ 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;
+ skb->ignore_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