datapath: Provide compatibility for kernels up to 3.17
authorThomas Graf <tgraf@noironetworks.com>
Thu, 18 Sep 2014 12:48:56 +0000 (14:48 +0200)
committerPravin B Shelar <pshelar@nicira.com>
Sun, 21 Sep 2014 02:36:33 +0000 (19:36 -0700)
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@noironetworks.com>
Co-authored-by: Madhu Challa <challa@noironetworks.com>
Acked-by: Pravin B Shelar <pshelar@nicira.com>
18 files changed:
.travis.yml
.travis/build.sh
acinclude.m4
datapath/linux/Modules.mk
datapath/linux/compat/include/linux/if.h
datapath/linux/compat/include/linux/netdevice.h
datapath/linux/compat/include/linux/skbuff.h
datapath/linux/compat/include/net/ip_tunnels.h
datapath/linux/compat/include/net/udp.h [new file with mode: 0644]
datapath/linux/compat/include/net/vxlan.h
datapath/linux/compat/ip_tunnels_core.c
datapath/linux/compat/vxlan.c
datapath/vport-geneve.c
datapath/vport-gre.c
datapath/vport-internal_dev.c
datapath/vport-lisp.c
datapath/vport-netdev.c
datapath/vport-vxlan.c

index b66f821..4dfe15e 100644 (file)
@@ -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
index ecdd39f..3872893 100755 (executable)
@@ -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)
index e3a694b..6e31d88 100644 (file)
@@ -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
 
index f7c64e2..274b1f1 100644 (file)
@@ -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
index c4c656c..3beb61d 100644 (file)
@@ -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
index 35b04d0..679c861 100644 (file)
@@ -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, 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);
index 9abd582..18e75d6 100644 (file)
@@ -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,
index 2a6470a..5d0267d 100644 (file)
@@ -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 (file)
index 0000000..88174ae
--- /dev/null
@@ -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
index d64630b..2e56a9b 100644 (file)
@@ -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
index a70aefc..549df3d 100644 (file)
@@ -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)
index b8b8fa7..9278c37 100644 (file)
@@ -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)
index ce5b509..6ed1e1f 100644 (file)
@@ -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));
 
 }
index ce203b8..41c025d 100644 (file)
@@ -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);
index 8a454df..3a38138 100644 (file)
@@ -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;
index 3335aa5..ad5cd23 100644 (file)
@@ -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);
index c15923b..a00276b 100644 (file)
@@ -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))
index 34dd919..8689853 100644 (file)
@@ -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,