[ovs-dev] [PATCH] openvswitch: add support for kernel 4.4

Alexandru Ardelean ardeleanalex at gmail.com
Thu Mar 10 16:46:29 UTC 2016


Maybe not the cleanest patch/approach to add support for kernel 4.4,
but it works.

Will do more tests later.

Signed-off-by: Alexandru Ardelean <ardeleanalex at gmail.com>
---
 acinclude.m4                                       |    4 +--
 datapath/actions.c                                 |    8 ++++--
 datapath/conntrack.c                               |    6 +++-
 datapath/datapath.c                                |    6 +++-
 .../linux/compat/include/linux/netfilter_ipv6.h    |    4 +++
 datapath/linux/compat/include/net/ip.h             |   30 ++++++++++++++++++--
 datapath/linux/compat/include/net/ip6_tunnel.h     |    4 +++
 datapath/linux/compat/include/net/vxlan.h          |   10 +++++++
 datapath/linux/compat/ip_fragment.c                |    7 ++++-
 datapath/linux/compat/stt.c                        |    6 ++++
 datapath/vport-vxlan.c                             |    3 +-
 11 files changed, 77 insertions(+), 11 deletions(-)

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..78f1f16 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -688,6 +688,8 @@ static void prepare_frag(struct vport *vport, struct sk_buff *skb)
 static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru,
 			 __be16 ethertype)
 {
+	struct net *net;
+
 	if (skb_network_offset(skb) > MAX_L2_LEN) {
 		OVS_NLERR(1, "L2 header too long to fragment");
 		goto err;
@@ -701,12 +703,13 @@ static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru,
 		dst_init(&ovs_dst, &ovs_dst_ops, NULL, 1,
 			 DST_OBSOLETE_NONE, DST_NOCOUNT);
 		ovs_dst.dev = vport->dev;
+		net = dev_net(ovs_dst.dev);
 
 		orig_dst = (unsigned long) skb_dst(skb);
 		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, 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();
@@ -722,12 +725,13 @@ static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru,
 		dst_init(&ovs_rt.dst, &ovs_dst_ops, NULL, 1,
 			 DST_OBSOLETE_NONE, DST_NOCOUNT);
 		ovs_rt.dst.dev = vport->dev;
+		net = dev_net(ovs_rt.dst.dev);
 
 		orig_dst = (unsigned long) skb_dst(skb);
 		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, 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..b589562 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, skb, user);
 		if (err)
 			return err;
 
@@ -374,7 +374,11 @@ ovs_ct_expect_find(struct net *net, const struct nf_conntrack_zone *zone,
 {
 	struct nf_conntrack_tuple tuple;
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
+	if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), proto, net, &tuple))
+#else
 	if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), proto, &tuple))
+#endif
 		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..eff3100 100644
--- a/datapath/linux/compat/include/linux/netfilter_ipv6.h
+++ b/datapath/linux/compat/include/linux/netfilter_ipv6.h
@@ -13,7 +13,11 @@
  * 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 {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
+	int (*fragment)(struct net *net, struct sock *sk, struct sk_buff *skb,
+#else
 	int (*fragment)(struct sock *sk, struct sk_buff *skb,
+#endif
 			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..2b79150 100644
--- a/datapath/linux/compat/include/net/ip.h
+++ b/datapath/linux/compat/include/net/ip.h
@@ -67,7 +67,11 @@ static inline unsigned int rpl_ip_skb_dst_mtu(const struct sk_buff *skb)
 #endif /* HAVE_IP_SKB_DST_MTU */
 
 #ifdef HAVE_IP_FRAGMENT_TAKES_SOCK
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
+#define OVS_VPORT_OUTPUT_PARAMS struct net *net, struct sock *sock, struct sk_buff *skb
+#else
 #define OVS_VPORT_OUTPUT_PARAMS struct sock *sock, struct sk_buff *skb
+#endif
 #else
 #define OVS_VPORT_OUTPUT_PARAMS struct sk_buff *skb
 #endif
@@ -89,9 +93,16 @@ static inline bool ip_defrag_user_in_between(u32 user,
 #endif /* < v4.2 */
 
 #ifndef HAVE_IP_DO_FRAGMENT
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
+static inline int rpl_ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
+				     int (*output)(OVS_VPORT_OUTPUT_PARAMS))
+{
+#else
 static inline int rpl_ip_do_fragment(struct sock *sk, struct sk_buff *skb,
 				     int (*output)(OVS_VPORT_OUTPUT_PARAMS))
 {
+	struct net *net = dev_net(dev);
+#endif
 	unsigned int mtu = ip_skb_dst_mtu(skb);
 	struct iphdr *iph = ip_hdr(skb);
 	struct rtable *rt = skb_rtable(skb);
@@ -102,7 +113,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 +127,11 @@ 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 */
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
+int rpl_ip_defrag(struct net *net, struct sk_buff *skb, u32 user);
+#else
 int rpl_ip_defrag(struct sk_buff *skb, u32 user);
-#define ip_defrag rpl_ip_defrag
+#endif
 
 int __init rpl_ipfrag_init(void);
 void rpl_ipfrag_fini(void);
@@ -127,14 +141,24 @@ 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)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
+static inline int rpl_ip_defrag(struct net *net, struct sk_buff *skb, u32 user)
+{
+	skb_orphan(skb);
+	return ip_defrag(net, skb, user);
+}
+
+#else
 static inline int rpl_ip_defrag(struct sk_buff *skb, u32 user)
 {
 	skb_orphan(skb);
 	return ip_defrag(skb, user);
 }
-#define ip_defrag rpl_ip_defrag
+#endif /* >= kernel 4.4 */
 #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..35635d4 100644
--- a/datapath/linux/compat/ip_fragment.c
+++ b/datapath/linux/compat/ip_fragment.c
@@ -674,11 +674,16 @@ out_fail:
 }
 
 /* Process an incoming IP datagram fragment. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
+int rpl_ip_defrag(struct net *net, struct sk_buff *skb, u32 user)
+{
+#else
 int rpl_ip_defrag(struct sk_buff *skb, u32 user)
 {
+	struct net *net = dev_net(dev);
+#endif
 	struct net_device *dev = skb->dev ? : skb_dst(skb)->dev;
 	int vif = vrf_master_ifindex_rcu(dev);
-	struct net *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..d4587dd 100644
--- a/datapath/vport-vxlan.c
+++ b/datapath/vport-vxlan.c
@@ -153,7 +153,8 @@ 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);
-	__be16 dst_port = vxlan_dev_dst_port(vxlan);
+	unsigned short family = ip_tunnel_info_af(upcall->egress_tun_info);
+	__be16 dst_port = vxlan_dev_dst_port(vxlan, family);
 	__be16 src_port;
 	int port_min;
 	int port_max;
-- 
1.7.10.4




More information about the dev mailing list