summaryrefslogtreecommitdiff
path: root/datapath/linux/compat/nf_conntrack_reasm.c
diff options
context:
space:
mode:
Diffstat (limited to 'datapath/linux/compat/nf_conntrack_reasm.c')
-rw-r--r--datapath/linux/compat/nf_conntrack_reasm.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/datapath/linux/compat/nf_conntrack_reasm.c b/datapath/linux/compat/nf_conntrack_reasm.c
index ca19a9ff9..2024f1f59 100644
--- a/datapath/linux/compat/nf_conntrack_reasm.c
+++ b/datapath/linux/compat/nf_conntrack_reasm.c
@@ -80,6 +80,12 @@ static unsigned int nf_hash_frag(__be32 id, const struct in6_addr *saddr,
return jhash_3words(ipv6_addr_hash(saddr), ipv6_addr_hash(daddr),
(__force u32)id, nf_frags.rnd);
}
+/* fb3cfe6e75b9 ("inet: frag: remove hash size assumptions from callers")
+ * shifted this logic into inet_fragment, but prior kernels still need this.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0)
+#define nf_hash_frag(a, b, c) (nf_hash_frag(a, b, c) & (INETFRAGS_HASHSZ - 1))
+#endif
#ifdef HAVE_INET_FRAGS_CONST
static unsigned int nf_hashfn(const struct inet_frag_queue *q)
@@ -119,7 +125,11 @@ static inline struct frag_queue *fq_find(struct net *net, __be32 id,
arg.dst = dst;
arg.ecn = ecn;
+#ifdef HAVE_INET_FRAGS_WITH_RWLOCK
+ read_lock_bh(&nf_frags.lock);
+#else
local_bh_disable();
+#endif
hash = nf_hash_frag(id, src, dst);
q = inet_frag_find(&net->nf_frag.frags, &nf_frags, &arg, hash);
@@ -512,6 +522,13 @@ int rpl_nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user)
hdr = ipv6_hdr(skb);
fhdr = (struct frag_hdr *)skb_transport_header(skb);
+/* See ip_evictor(). */
+#ifdef HAVE_INET_FRAG_EVICTOR
+ local_bh_disable();
+ inet_frag_evictor(&net->nf_frag.frags, &nf_frags, false);
+ local_bh_enable();
+#endif
+
fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr,
ip6_frag_ecn(hdr));
if (fq == NULL)