Add patch to Linux 4.4 to support OVS 63/13763/2
authorDonald Dugger <n0ano@n0ano.com>
Thu, 28 Apr 2016 21:39:53 +0000 (21:39 +0000)
committerDon Dugger <n0ano@n0ano.com>
Fri, 13 May 2016 23:19:46 +0000 (17:19 -0600)
Given that OVS doesn't support Linux 4.4 yet we need to add a patch
to the OVS sources so that we can build a 4.4 version of the OVS
loadable kernel module that works with the RT Linux 4.4 kernel used
in OPNFV.

The directory `patches/ovs' contains patches (currently only one) that
are applied against the OVS tree.  The Fuel build script is modified
to apply all of the patches in this directory to the OVS tree.  Then
a working OVS KLM is created that is then inserted into the RT kernel
DEB package so that the end result is an RT kernel that supports OVS.

Upstream status: NA

Change-Id: I361f92526fb4bcafbeab9ce21570202f4aad1632
Signed-off-by: Don Dugger <n0ano@n0ano.com>
fuel-plugin/build_kvm.sh
patches/ovs/0001-Add-Linux-4.4-support.patch [new file with mode: 0644]

index 2c39292..f5854d8 100755 (executable)
@@ -38,7 +38,7 @@ EOF
 }
 
 KVM_COMMIT=""
-OVS_COMMIT=""
+OVS_COMMIT="4ff6642f3c1dd8949c2f42b3310ee2523ee970a6"
 KEEP=no
 for i
 do
@@ -821,6 +821,19 @@ fi
        else
                git reset --hard
        fi
+
+       #
+       # Apply out of tree patches
+       #
+       for i in $SRC/kvmfornfv/patches/ovs/*.patch
+       do
+               if [ -f "$i" ]
+               then
+                       echo "Applying: $i"
+                       patch -p1 <$i
+               fi
+       done
+
        ./boot.sh
        ./configure --with-linux=$SRC/kvmfornfv/kernel
        make
diff --git a/patches/ovs/0001-Add-Linux-4.4-support.patch b/patches/ovs/0001-Add-Linux-4.4-support.patch
new file mode 100644 (file)
index 0000000..a580bc2
--- /dev/null
@@ -0,0 +1,246 @@
+From a4c2305b6190ce24ceaafb9f85fc5a67787fb71d Mon Sep 17 00:00:00 2001
+From: Donald Dugger <n0ano@n0ano.com>
+Date: Mon, 9 May 2016 05:14:12 +0000
+Subject: [PATCH] Add Linux 4.4 support
+
+A bit cleaner than my previous patch.
+  http://patchwork.ozlabs.org/patch/595969/
+
+Though I couldn't figure out a clean solution for ip6_local_out(),
+genl_notify(), and vport-vxlan
+
+Signed-off-by: Alexandru Ardelean <ardeleanalex@gmail.com>
+
+Note that this patch has been rejected for the upstream OVS tree as
+the maintainers feel a different apporach (backporting all Linux
+patches that affect the OVS code).  We'll just use this patch until
+the official OVS tree is updated to support Linux 4.4.
+
+Upstream status: NA
+
+Signed-off-by: Don Dugger <n0ano@n0ano.com>
+---
+ acinclude.m4                                         |  4 ++--
+ datapath/actions.c                                   |  6 ++++--
+ datapath/datapath.c                                  |  6 +++++-
+ datapath/linux/compat/include/linux/netfilter_ipv6.h |  2 +-
+ datapath/linux/compat/include/net/ip.h               | 19 ++++++++++++++++---
+ datapath/linux/compat/include/net/ip6_tunnel.h       |  4 ++++
+ datapath/linux/compat/include/net/vxlan.h            | 10 ++++++++++
+ datapath/linux/compat/stt.c                          |  6 ++++++
+ datapath/vport-vxlan.c                               |  5 +++++
+ 9 files changed, 53 insertions(+), 9 deletions(-)
+
+diff --git a/acinclude.m4 b/acinclude.m4
+index 23015fe..22e75ec 100644
+--- a/acinclude.m4
++++ b/acinclude.m4
+@@ -134,10 +134,10 @@ AC_DEFUN([OVS_CHECK_LINUX], [
+     AC_MSG_RESULT([$kversion])
+     if test "$version" -ge 4; then
+-       if test "$version" = 4 && test "$patchlevel" -le 3; then
++       if test "$version" = 4 && test "$patchlevel" -le 4; then
+           : # Linux 4.x
+        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)])
++          AC_ERROR([Linux kernel in $KBUILD is version $kversion, but version newer than 4.4.x is not supported (please refer to the FAQ for advice)])
+        fi
+     elif test "$version" = 3 && test "$patchlevel" -ge 10; then
+        : # Linux 3.x
+diff --git a/datapath/actions.c b/datapath/actions.c
+index dcf8591..242e710 100644
+--- a/datapath/actions.c
++++ b/datapath/actions.c
+@@ -702,7 +702,8 @@ static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru,
+               skb_dst_set_noref(skb, &ovs_dst);
+               IPCB(skb)->frag_max_size = mru;
+-              ip_do_fragment(skb->sk, skb, ovs_vport_output);
++              ip_do_fragment(NET_ARG(dev_net(ovs_dst.dev))
++                      skb->sk, skb, ovs_vport_output);
+               refdst_drop(orig_dst);
+       } else if (ethertype == htons(ETH_P_IPV6)) {
+               const struct nf_ipv6_ops *v6ops = nf_get_ipv6_ops();
+@@ -723,7 +724,8 @@ static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru,
+               skb_dst_set_noref(skb, &ovs_rt.dst);
+               IP6CB(skb)->frag_max_size = mru;
+-              v6ops->fragment(skb->sk, skb, ovs_vport_output);
++              v6ops->fragment(NET_ARG(dev_net(ovs_rt.dst.dev))
++                      skb->sk, skb, ovs_vport_output);
+               refdst_drop(orig_dst);
+       } else {
+               WARN_ONCE(1, "Failed fragment ->%s: eth=%04x, MRU=%d, MTU=%d.",
+diff --git a/datapath/datapath.c b/datapath/datapath.c
+index 5bec072..ba19c01 100644
+--- a/datapath/datapath.c
++++ b/datapath/datapath.c
+@@ -95,8 +95,12 @@ static bool ovs_must_notify(struct genl_family *family, struct genl_info *info,
+ static void ovs_notify(struct genl_family *family, struct genl_multicast_group *grp,
+                      struct sk_buff *skb, struct genl_info *info)
+ {
+-      genl_notify(family, skb, genl_info_net(info),
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
++      genl_notify(family, skb, info, GROUP_ID(grp), GFP_KERNEL);
++#else
++      genl_notify(family, skb, genl_info_net(info),
+                   info->snd_portid, GROUP_ID(grp), info->nlhdr, GFP_KERNEL);
++#endif
+ }
+ /**
+diff --git a/datapath/linux/compat/include/linux/netfilter_ipv6.h b/datapath/linux/compat/include/linux/netfilter_ipv6.h
+index 8d896fb..9f64002 100644
+--- a/datapath/linux/compat/include/linux/netfilter_ipv6.h
++++ b/datapath/linux/compat/include/linux/netfilter_ipv6.h
+@@ -13,7 +13,7 @@
+  * the callback parameter needs to be in the form that older kernels accept.
+  * We don't backport the other ipv6_ops as they're currently unused by OVS. */
+ struct ovs_nf_ipv6_ops {
+-      int (*fragment)(struct sock *sk, struct sk_buff *skb,
++      int (*fragment)(NET_ARG(net) struct sock *sk, struct sk_buff *skb,
+                       int (*output)(OVS_VPORT_OUTPUT_PARAMS));
+ };
+ #define nf_ipv6_ops ovs_nf_ipv6_ops
+diff --git a/datapath/linux/compat/include/net/ip.h b/datapath/linux/compat/include/net/ip.h
+index c283ad0..483662c 100644
+--- a/datapath/linux/compat/include/net/ip.h
++++ b/datapath/linux/compat/include/net/ip.h
+@@ -59,8 +59,20 @@ static inline unsigned int rpl_ip_skb_dst_mtu(const struct sk_buff *skb)
+ #define ip_skb_dst_mtu rpl_ip_skb_dst_mtu
+ #endif /* HAVE_IP_SKB_DST_MTU */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
++#define NET_PARAM(x) struct net *x,
++#define NET_ARG(x) x,
++#define NET_DEV_NET(x) dev_net(x)
++#define NET_DECLARE_INIT(x,y)
++#else
++#define NET_PARAM(x)
++#define NET_ARG(x)
++#define NET_DEV_NET(x)
++#define NET_DECLARE_INIT(x,y) struct net *x = y;
++#endif
++
+ #ifdef HAVE_IP_FRAGMENT_TAKES_SOCK
+-#define OVS_VPORT_OUTPUT_PARAMS struct sock *sock, struct sk_buff *skb
++#define OVS_VPORT_OUTPUT_PARAMS NET_PARAM(net) struct sock *sock, struct sk_buff *skb
+ #else
+ #define OVS_VPORT_OUTPUT_PARAMS struct sk_buff *skb
+ #endif
+@@ -82,12 +94,13 @@ static inline bool ip_defrag_user_in_between(u32 user,
+ #endif /* < v4.2 */
+ #ifndef HAVE_IP_DO_FRAGMENT
+-static inline int rpl_ip_do_fragment(struct sock *sk, struct sk_buff *skb,
++static inline int rpl_ip_do_fragment(NET_PARAM(net) struct sock *sk, struct sk_buff *skb,
+                                    int (*output)(OVS_VPORT_OUTPUT_PARAMS))
+ {
+       unsigned int mtu = ip_skb_dst_mtu(skb);
+       struct iphdr *iph = ip_hdr(skb);
+       struct rtable *rt = skb_rtable(skb);
++      NET_DECLARE_INIT(net, dev_net(dev));
+       struct net_device *dev = rt->dst.dev;
+       if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->ignore_df) ||
+@@ -95,7 +108,7 @@ static inline int rpl_ip_do_fragment(struct sock *sk, struct sk_buff *skb,
+                     IPCB(skb)->frag_max_size > mtu))) {
+               pr_warn("Dropping packet in ip_do_fragment()\n");
+-              IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
++              IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS);
+               kfree_skb(skb);
+               return -EMSGSIZE;
+       }
+diff --git a/datapath/linux/compat/include/net/ip6_tunnel.h b/datapath/linux/compat/include/net/ip6_tunnel.h
+index ce65087..eacf9ca 100644
+--- a/datapath/linux/compat/include/net/ip6_tunnel.h
++++ b/datapath/linux/compat/include/net/ip6_tunnel.h
+@@ -17,11 +17,15 @@ static inline void ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb,
+       pkt_len = skb->len - skb_inner_network_offset(skb);
+       /* TODO: Fix GSO for ipv6 */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
++      err = ip6_local_out(dev_net(dev), sk, skb);
++#else
+ #ifdef HAVE_IP6_LOCAL_OUT_SK
+       err = ip6_local_out_sk(sk, skb);
+ #else
+       err = ip6_local_out(skb);
+ #endif
++#endif /* >= kernel 4.4 */
+       if (net_xmit_eval(err) != 0)
+               pkt_len = net_xmit_eval(err);
+       else
+diff --git a/datapath/linux/compat/include/net/vxlan.h b/datapath/linux/compat/include/net/vxlan.h
+index 75a5a7a..589cc0d 100644
+--- a/datapath/linux/compat/include/net/vxlan.h
++++ b/datapath/linux/compat/include/net/vxlan.h
+@@ -218,10 +218,20 @@ struct vxlan_dev {
+ struct net_device *rpl_vxlan_dev_create(struct net *net, const char *name,
+                                   u8 name_assign_type, struct vxlan_config *conf);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
++static inline __be16 vxlan_dev_dst_port(struct vxlan_dev *vxlan,
++                                      unsigned short family)
++{
++      if (family == AF_INET6)
++              return inet_sk(vxlan->vn6_sock->sock->sk)->inet_sport;
++      return inet_sk(vxlan->vn4_sock->sock->sk)->inet_sport;
++}
++#else
+ static inline __be16 vxlan_dev_dst_port(struct vxlan_dev *vxlan)
+ {
+       return inet_sk(vxlan->vn_sock->sock->sk)->inet_sport;
+ }
++#endif
+ static inline netdev_features_t vxlan_features_check(struct sk_buff *skb,
+                                                    netdev_features_t features)
+diff --git a/datapath/linux/compat/stt.c b/datapath/linux/compat/stt.c
+index 86d225e..6b1e3a3 100644
+--- a/datapath/linux/compat/stt.c
++++ b/datapath/linux/compat/stt.c
+@@ -1544,7 +1544,11 @@ static void clean_percpu(struct work_struct *work)
+ }
+ #ifdef HAVE_NF_HOOKFN_ARG_OPS
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
++#define FIRST_PARAM void *priv
++#else
+ #define FIRST_PARAM const struct nf_hook_ops *ops
++#endif /* >= kernel 4.4 */
+ #else
+ #define FIRST_PARAM unsigned int hooknum
+ #endif
+@@ -1592,7 +1596,9 @@ static unsigned int nf_ip_hook(FIRST_PARAM, struct sk_buff *skb, LAST_PARAM)
+ static struct nf_hook_ops nf_hook_ops __read_mostly = {
+       .hook           = nf_ip_hook,
++#if LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0)
+       .owner          = THIS_MODULE,
++#endif
+       .pf             = NFPROTO_IPV4,
+       .hooknum        = NF_INET_LOCAL_IN,
+       .priority       = INT_MAX,
+diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c
+index c05f5d4..3cbb568 100644
+--- a/datapath/vport-vxlan.c
++++ b/datapath/vport-vxlan.c
+@@ -153,7 +153,12 @@ static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
+ {
+       struct vxlan_dev *vxlan = netdev_priv(vport->dev);
+       struct net *net = ovs_dp_get_net(vport->dp);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
++      unsigned short family = ip_tunnel_info_af(upcall->egress_tun_info);
++      __be16 dst_port = vxlan_dev_dst_port(vxlan, family);
++#else
+       __be16 dst_port = vxlan_dev_dst_port(vxlan);
++#endif
+       __be16 src_port;
+       int port_min;
+       int port_max;
+-- 
+1.9.1
+