]> git.proxmox.com Git - ovs.git/commitdiff
compat: Fixup ipv6 fragmentation on 4.9.135+ kernels
authorGreg Rose <gvrose8192@gmail.com>
Thu, 10 Jan 2019 22:09:51 +0000 (14:09 -0800)
committerBen Pfaff <blp@ovn.org>
Wed, 23 Jan 2019 01:09:09 +0000 (17:09 -0800)
Upstream commit 648700f76b03 ("inet: frags: use rhashtables...") changed
how ipv6 fragmentation is implemented.  This patch was backported to
the upstream stable 4.9.x kernel starting at 4.9.135.

This patch creates the compatibility layer changes required to both
compile and also operate correctly with ipv6 fragmentation on these
kernels. Check if the inet_frags 'rnd' field is present to key on
whether the upstream patch is present.  Also update Travis to the
latest 4.9 kernel release so that this patch is compile tested.

Passes Travis:
https://travis-ci.org/gvrose8192/ovs-experimental/builds/478033409

Cc: William Tu <u9012063@gmail.com>
Cc: Yi-Hung Wei <yihung.wei@gmail.com>
Cc: Yifeng Sun <pkusunyifeng@gmail.com>
Acked-by: Yi-Hung Wei <yihung.wei@gmail.com>
Signed-off-by: Greg Rose <gvrose8192@gmail.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
.travis.yml
acinclude.m4
datapath/linux/compat/nf_conntrack_reasm.c

index b74ba2bfdce4aa14520bc366c6c0c40d10051122..f35eb4ab60c8a2636230677fb91bce7544cf03c4 100644 (file)
@@ -41,7 +41,7 @@ env:
   - KERNEL=4.16.18
   - KERNEL=4.15.18
   - KERNEL=4.14.63
-  - KERNEL=4.9.120
+  - KERNEL=4.9.149
   - KERNEL=4.4.148
   - KERNEL=3.19.8
   - KERNEL=3.16.57
index 8b43d2bfe98301910278c2fef3b98a191ea9ae55..f038fd45701a698d976d081297c5c42e7aa5154d 100644 (file)
@@ -915,6 +915,9 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
   OVS_FIND_PARAM_IFELSE([$KSRC/include/net/ip_tunnels.h],
                         [ip_tunnel_info_opts_set], [flags],
                         [OVS_DEFINE([HAVE_IP_TUNNEL_INFO_OPTS_SET_FLAGS])])
+  OVS_FIND_FIELD_IFELSE([$KSRC/include/net/inet_frag.h], [inet_frags],
+                        [rnd],
+                        [OVS_DEFINE([HAVE_INET_FRAGS_RND])])
 
   if cmp -s datapath/linux/kcompat.h.new \
             datapath/linux/kcompat.h >/dev/null 2>&1; then
index ce13112fc42349445c24e52bb8ec1706c7570747..9d77d982712c8a16f29ea112c9f0ab009c762d9c 100644 (file)
@@ -99,6 +99,7 @@ static inline u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h)
        return 1 << (ipv6_get_dsfield(ipv6h) & INET_ECN_MASK);
 }
 
+#ifdef HAVE_INET_FRAGS_RND
 static unsigned int nf_hash_frag(__be32 id, const struct in6_addr *saddr,
                                 const struct in6_addr *daddr)
 {
@@ -125,6 +126,7 @@ static unsigned int nf_hashfn(struct inet_frag_queue *q)
        return nf_hash_frag(nq->id, &nq->saddr, &nq->daddr);
 }
 
+#endif /* HAVE_INET_FRAGS_RND */
 static void nf_ct_frag6_expire(unsigned long data)
 {
        struct frag_queue *fq;
@@ -133,9 +135,14 @@ static void nf_ct_frag6_expire(unsigned long data)
        fq = container_of((struct inet_frag_queue *)data, struct frag_queue, q);
        net = get_net_from_netns_frags6(fq->q.net);
 
+#ifdef HAVE_INET_FRAGS_RND
        ip6_expire_frag_queue(net, fq, &nf_frags);
+#else
+       ip6_expire_frag_queue(net, fq);
+#endif
 }
 
+#ifdef HAVE_INET_FRAGS_RND
 /* Creation primitives. */
 static inline struct frag_queue *fq_find(struct net *net, __be32 id,
                                         u32 user, struct in6_addr *src,
@@ -168,7 +175,27 @@ static inline struct frag_queue *fq_find(struct net *net, __be32 id,
        }
        return container_of(q, struct frag_queue, q);
 }
+#else
+static struct frag_queue *fq_find(struct net *net, __be32 id, u32 user,
+                                 const struct ipv6hdr *hdr, int iif)
+{
+       struct frag_v6_compare_key key = {
+               .id = id,
+               .saddr = hdr->saddr,
+               .daddr = hdr->daddr,
+               .user = user,
+               .iif = iif,
+       };
+       struct inet_frag_queue *q;
+
+       q = inet_frag_find(&net->nf_frag.frags, &key);
+       if (!q)
+               return NULL;
+
+       return container_of(q, struct frag_queue, q);
+}
 
+#endif  /* HAVE_INET_FRAGS_RND */
 
 static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb,
                             const struct frag_hdr *fhdr, int nhoff)
@@ -317,7 +344,11 @@ found:
        return 0;
 
 discard_fq:
+#ifdef HAVE_INET_FRAGS_RND
        inet_frag_kill(&fq->q, &nf_frags);
+#else
+       inet_frag_kill(&fq->q);
+#endif
 err:
        return -1;
 }
@@ -339,7 +370,11 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct sk_buff *prev,  struct net_devic
        int    payload_len;
        u8 ecn;
 
+#ifdef HAVE_INET_FRAGS_RND
        inet_frag_kill(&fq->q, &nf_frags);
+#else
+       inet_frag_kill(&fq->q);
+#endif
 
        WARN_ON(head == NULL);
        WARN_ON(NFCT_FRAG6_CB(head)->offset != 0);
@@ -561,8 +596,13 @@ int rpl_nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user)
 #endif
 
        skb_orphan(skb);
+#ifdef HAVE_INET_FRAGS_RND
        fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr,
                     ip6_frag_ecn(hdr));
+#else
+       fq = fq_find(net, fhdr->identification, user, hdr,
+                    skb->dev ? skb->dev->ifindex : 0);
+#endif
        if (fq == NULL)
                return -ENOMEM;
 
@@ -584,7 +624,11 @@ int rpl_nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user)
 
 out_unlock:
        spin_unlock_bh(&fq->q.lock);
+#ifdef HAVE_INET_FRAGS_RND
        inet_frag_put(&fq->q, &nf_frags);
+#else
+       inet_frag_put(&fq->q);
+#endif
        return ret;
 }
 
@@ -614,10 +658,12 @@ void ovs_netns_frags6_init(struct net *net)
 
 void ovs_netns_frags6_exit(struct net *net)
 {
+#ifdef HAVE_INET_FRAGS_RND
        struct netns_frags *frags;
 
        frags = get_netns_frags6_from_net(net);
        inet_frags_exit_net(frags, &nf_frags);
+#endif
 }
 
 static struct pernet_operations nf_ct_net_ops = {
@@ -634,13 +680,17 @@ int rpl_nf_ct_frag6_init(void)
 #ifndef HAVE_DEFRAG_ENABLE_TAKES_NET
        nf_defrag_ipv6_enable();
 #endif
+#ifdef HAVE_INET_FRAGS_RND
        nf_frags.hashfn = nf_hashfn;
+       nf_frags.match = ip6_frag_match;
+#else
+       nf_frags.rhash_params = ip6_rhash_params;
+#endif
        nf_frags.constructor = ip6_frag_init;
        nf_frags.destructor = NULL;
        nf_frags.qsize = sizeof(struct frag_queue);
-       nf_frags.match = ip6_frag_match;
        nf_frags.frag_expire = nf_ct_frag6_expire;
-#ifdef HAVE_INET_FRAGS_WITH_FRAGS_WORK
+#if defined(HAVE_INET_FRAGS_WITH_FRAGS_WORK) || !defined(HAVE_INET_FRAGS_RND)
        nf_frags.frags_cache_name = nf_frags_cache_name;
 #endif
 #if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8,0)