From 0bef472f608b968512cbedaaf78f7565dc9d6baa Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Thu, 10 Mar 2016 18:47:59 +0200 Subject: [PATCH] openvswitch: add support for kernel 4.4 Signed-off-by: Alexandru Ardelean --- net/openvswitch/Makefile | 5 +- .../patches/0011-kernel-4-4-support.patch | 279 ++++++++++++++++++ 2 files changed, 282 insertions(+), 2 deletions(-) create mode 100644 net/openvswitch/patches/0011-kernel-4-4-support.patch diff --git a/net/openvswitch/Makefile b/net/openvswitch/Makefile index 636166b8b..5fc3aa4b2 100644 --- a/net/openvswitch/Makefile +++ b/net/openvswitch/Makefile @@ -12,7 +12,7 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=openvswitch -PKG_RELEASE:=5 +PKG_RELEASE:=6 PKG_VERSION:=2.5.0 PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_LICENSE:=Apache-2.0 @@ -32,7 +32,8 @@ PKG_INSTALL:=1 # Upstream package supports kernels between 2.6.32 and 4.3 # see https://github.com/openvswitch/ovs/blob/master/FAQ.md # This list is pruned to only those kernels used in OpenWRT -SUPPORTED_KERNELS:=LINUX_3_18||LINUX_4_1||LINUX_4_3 +# Support for kernel 4.4 is backported +SUPPORTED_KERNELS:=LINUX_3_18||LINUX_4_1||LINUX_4_3||LINUX_4_4 include $(INCLUDE_DIR)/package.mk $(call include_mk, python-package.mk) diff --git a/net/openvswitch/patches/0011-kernel-4-4-support.patch b/net/openvswitch/patches/0011-kernel-4-4-support.patch new file mode 100644 index 000000000..faf1777b4 --- /dev/null +++ b/net/openvswitch/patches/0011-kernel-4-4-support.patch @@ -0,0 +1,279 @@ +diff --git a/acinclude.m4 b/acinclude.m4 +index 11c7787..07dd647 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; then + : # Linux 3.x +diff --git a/datapath/actions.c b/datapath/actions.c +index 20413c9..719c43d 100644 +--- a/datapath/actions.c ++++ b/datapath/actions.c +@@ -706,7 +706,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(); +@@ -727,7 +728,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/conntrack.c b/datapath/conntrack.c +index 795ed91..3b9bfba 100644 +--- a/datapath/conntrack.c ++++ b/datapath/conntrack.c +@@ -323,7 +323,7 @@ static int handle_fragments(struct net *net, struct sw_flow_key *key, + int err; + + memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); +- err = ip_defrag(skb, user); ++ err = ip_defrag(NET_ARG(net) skb, user); + if (err) + return err; + +@@ -374,7 +374,7 @@ ovs_ct_expect_find(struct net *net, const struct nf_conntrack_zone *zone, + { + struct nf_conntrack_tuple tuple; + +- if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), proto, &tuple)) ++ if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), proto, NET_ARG(net) &tuple)) + return NULL; + return __nf_ct_expect_find(net, zone, &tuple); + } +diff --git a/datapath/datapath.c b/datapath/datapath.c +index e3d3c8c..a4157f4 100644 +--- a/datapath/datapath.c ++++ b/datapath/datapath.c +@@ -96,8 +96,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 3939e14..b724623 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 cd87bcc..b749301 100644 +--- a/datapath/linux/compat/include/net/ip.h ++++ b/datapath/linux/compat/include/net/ip.h +@@ -66,8 +66,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 +@@ -89,12 +101,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) || +@@ -102,7 +115,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; + } +@@ -116,8 +129,7 @@ static inline int rpl_ip_do_fragment(struct sock *sk, struct sk_buff *skb, + #define ip_do_fragment rpl_ip_do_fragment + #endif /* IP_DO_FRAGMENT */ + +-int rpl_ip_defrag(struct sk_buff *skb, u32 user); +-#define ip_defrag rpl_ip_defrag ++int rpl_ip_defrag(NET_PARAM(net) struct sk_buff *skb, u32 user); + + int __init rpl_ipfrag_init(void); + void rpl_ipfrag_fini(void); +@@ -127,14 +139,15 @@ void rpl_ipfrag_fini(void); + * ("inet: frag: Always orphan skbs inside ip_defrag()"), but it should be + * always included in kernels 4.5+. */ + #if LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0) +-static inline int rpl_ip_defrag(struct sk_buff *skb, u32 user) ++static inline int rpl_ip_defrag(NET_PARAM(net) struct sk_buff *skb, u32 user) + { + skb_orphan(skb); +- return ip_defrag(skb, user); ++ return ip_defrag(NET_ARG(net) skb, user); + } +-#define ip_defrag rpl_ip_defrag + #endif + ++#define ip_defrag rpl_ip_defrag ++ + static inline int rpl_ipfrag_init(void) { return 0; } + static inline void rpl_ipfrag_fini(void) { } + #endif /* HAVE_CORRECT_MRU_HANDLING && OVS_FRAGMENT_BACKPORT */ +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 b50cd17..230f3ad 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_sport(vxlan->vn_sock->sock->sk); + } ++#endif + + static inline netdev_features_t vxlan_features_check(struct sk_buff *skb, + netdev_features_t features) +diff --git a/datapath/linux/compat/ip_fragment.c b/datapath/linux/compat/ip_fragment.c +index cf2daaa..e168196 100644 +--- a/datapath/linux/compat/ip_fragment.c ++++ b/datapath/linux/compat/ip_fragment.c +@@ -674,11 +674,11 @@ out_fail: + } + + /* Process an incoming IP datagram fragment. */ +-int rpl_ip_defrag(struct sk_buff *skb, u32 user) ++int rpl_ip_defrag(NET_ARG(net) struct sk_buff *skb, u32 user) + { + struct net_device *dev = skb->dev ? : skb_dst(skb)->dev; + int vif = vrf_master_ifindex_rcu(dev); +- struct net *net = dev_net(dev); ++ NET_DECLARE_INIT(net, dev_net(dev)); + struct ipq *qp; + + IP_INC_STATS_BH(net, IPSTATS_MIB_REASMREQDS); +diff --git a/datapath/linux/compat/stt.c b/datapath/linux/compat/stt.c +index eb397e8..5ea3c52 100644 +--- a/datapath/linux/compat/stt.c ++++ b/datapath/linux/compat/stt.c +@@ -1450,7 +1450,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 +@@ -1498,7 +1502,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;