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

Pravin Shelar pshelar at nicira.com
Wed Sep 17 23:19:59 UTC 2014


On Tue, Sep 16, 2014 at 10:44 AM, Thomas Graf <tgraf at noironetworks.com> wrote:
> 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).
>
Thanks for working on this. I have couple of comments.

> 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
> +
We do reverse of this. i.e. define ignore_df for old kernels. So that
ovs external module and upstream module code looks same.

>  #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

We can define compat alloc_netdev() to avoid #ifdef here.

>         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
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev



More information about the dev mailing list