From 91408ae00320154d4b3ee970c25c219a9782e67d Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Thu, 24 Dec 2015 10:54:37 -0800 Subject: [PATCH] compat: Detect and use inet_frags->frags_work. Kernels 3.17 and newer have a work queue to evict old fragments, while older kernel versions use an LRU in the fast path; see upstream commit b13d3cbfb8e8 ("inet: frag: move eviction of queues to work queue"). This commit fixes the version checking so that rather than enabling the code for either of these approaches using version checks, it is triggered based on the presence of the work queue in "struct inet_frags". Signed-off-by: Joe Stringer Acked-by: Pravin B Shelar --- acinclude.m4 | 2 + datapath/linux/compat/include/net/inet_frag.h | 6 +- datapath/linux/compat/inet_fragment.c | 70 +++++++++---------- datapath/linux/compat/ip_fragment.c | 2 +- datapath/linux/compat/nf_conntrack_reasm.c | 2 +- 5 files changed, 42 insertions(+), 40 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index e99ab0132..3e44abb3a 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -355,6 +355,8 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ [OVS_DEFINE([HAVE_INET_FRAGS_CONST])]) OVS_GREP_IFELSE([$KSRC/include/net/inet_frag.h], [last_in], [OVS_DEFINE([HAVE_INET_FRAGS_LAST_IN])]) + OVS_FIND_FIELD_IFELSE([$KSRC/include/net/inet_frag.h], [inet_frags], + [frags_work]) OVS_GREP_IFELSE([$KSRC/include/net/dst_metadata.h], [metadata_dst]) diff --git a/datapath/linux/compat/include/net/inet_frag.h b/datapath/linux/compat/include/net/inet_frag.h index 0c0c07619..2708cddf2 100644 --- a/datapath/linux/compat/include/net/inet_frag.h +++ b/datapath/linux/compat/include/net/inet_frag.h @@ -36,11 +36,11 @@ struct ovs_inet_frag_queue { static inline bool rpl_inet_frag_evicting(struct inet_frag_queue *q) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0) - return (q_flags(q) & INET_FRAG_FIRST_IN) && q->fragments != NULL; -#else +#ifdef HAVE_INET_FRAGS_WITH_FRAGS_WORK struct ovs_inet_frag_queue *ofq = (struct ovs_inet_frag_queue *)q; return !hlist_unhashed(&ofq->list_evictor); +#else + return (q_flags(q) & INET_FRAG_FIRST_IN) && q->fragments != NULL; #endif } #define inet_frag_evicting rpl_inet_frag_evicting diff --git a/datapath/linux/compat/inet_fragment.c b/datapath/linux/compat/inet_fragment.c index 323226880..15321deaa 100644 --- a/datapath/linux/compat/inet_fragment.c +++ b/datapath/linux/compat/inet_fragment.c @@ -61,7 +61,7 @@ inet_frag_hashfn(const struct inet_frags *f, struct inet_frag_queue *q) return f->hashfn(q) & (INETFRAGS_HASHSZ - 1); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0) +#ifdef HAVE_INET_FRAGS_WITH_FRAGS_WORK static bool inet_frag_may_rebuild(struct inet_frags *f) { return time_after(jiffies, @@ -207,7 +207,7 @@ int inet_frags_init(struct inet_frags *f) { int i; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0) +#ifdef HAVE_INET_FRAGS_WITH_FRAGS_WORK INIT_WORK(&f->frags_work, inet_frag_worker); #endif @@ -218,16 +218,16 @@ int inet_frags_init(struct inet_frags *f) INIT_HLIST_HEAD(&hb->chain); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0) - rwlock_init(&f->lock); - f->secret_timer.expires = jiffies + f->secret_interval; -#else +#ifdef HAVE_INET_FRAGS_WITH_FRAGS_WORK seqlock_init(&f->rnd_seqlock); f->last_rebuild_jiffies = 0; f->frags_cachep = kmem_cache_create(f->frags_cache_name, f->qsize, 0, 0, NULL); if (!f->frags_cachep) return -ENOMEM; +#else + rwlock_init(&f->lock); + f->secret_timer.expires = jiffies + f->secret_interval; #endif return 0; @@ -235,7 +235,7 @@ int inet_frags_init(struct inet_frags *f) void inet_frags_fini(struct inet_frags *f) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0) +#ifdef HAVE_INET_FRAGS_WITH_FRAGS_WORK cancel_work_sync(&f->frags_work); kmem_cache_destroy(f->frags_cachep); #endif @@ -243,14 +243,7 @@ void inet_frags_fini(struct inet_frags *f) int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force); -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0) -void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f) -{ - read_lock_bh(&f->lock); - inet_frag_evictor(nf, f, true); - read_unlock_bh(&f->lock); -} -#else +#ifdef HAVE_INET_FRAGS_WITH_FRAGS_WORK void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f) { unsigned int seq; @@ -268,6 +261,13 @@ evict_again: percpu_counter_sum(&nf->mem)) goto evict_again; } +#else +void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f) +{ + read_lock_bh(&f->lock); + inet_frag_evictor(nf, f, true); + read_unlock_bh(&f->lock); +} #endif static struct inet_frag_bucket * @@ -363,10 +363,10 @@ void rpl_inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f) if (f->destructor) f->destructor(q); -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0) - kfree(q); -#else +#ifdef HAVE_INET_FRAGS_WITH_FRAGS_WORK kmem_cache_free(f->frags_cachep, q); +#else + kfree(q); #endif sub_frag_mem_limit(nf, sum); @@ -374,7 +374,14 @@ void rpl_inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f) int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0) +#ifdef HAVE_INET_FRAGS_WITH_FRAGS_WORK + int i; + + for (i = 0; i < INETFRAGS_HASHSZ ; i++) + inet_evict_bucket(f, &f->hash[i]); + + return 0; +#else struct inet_frag_queue *q; int work, evicted = 0; @@ -406,13 +413,6 @@ int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force) } return evicted; -#else - int i; - - for (i = 0; i < INETFRAGS_HASHSZ ; i++) - inet_evict_bucket(f, &f->hash[i]); - - return 0; #endif } @@ -464,16 +464,16 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf, struct inet_frag_queue *q; if (frag_mem_limit(nf) > nf->high_thresh) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0) +#ifdef HAVE_INET_FRAGS_WITH_FRAGS_WORK inet_frag_schedule_worker(f); #endif return NULL; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0) - q = kzalloc(f->qsize, GFP_ATOMIC); -#else +#ifdef HAVE_INET_FRAGS_WITH_FRAGS_WORK q = kmem_cache_zalloc(f->frags_cachep, GFP_ATOMIC); +#else + q = kzalloc(f->qsize, GFP_ATOMIC); #endif if (!q) return NULL; @@ -510,12 +510,12 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, struct inet_frag_queue *q; int depth = 0; -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0) - if (frag_mem_limit(nf) > nf->high_thresh) - inet_frag_evictor(nf, f, false); -#else +#ifdef HAVE_INET_FRAGS_WITH_FRAGS_WORK if (frag_mem_limit(nf) > nf->low_thresh) inet_frag_schedule_worker(f); +#else + if (frag_mem_limit(nf) > nf->high_thresh) + inet_frag_evictor(nf, f, false); #endif hash &= (INETFRAGS_HASHSZ - 1); @@ -535,7 +535,7 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, if (depth <= INETFRAGS_MAXDEPTH) return inet_frag_create(nf, f, key); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0) +#ifdef HAVE_INET_FRAGS_WITH_FRAGS_WORK if (inet_frag_may_rebuild(f)) { if (!f->rebuild) f->rebuild = true; diff --git a/datapath/linux/compat/ip_fragment.c b/datapath/linux/compat/ip_fragment.c index 42514e428..3815067a9 100644 --- a/datapath/linux/compat/ip_fragment.c +++ b/datapath/linux/compat/ip_fragment.c @@ -731,7 +731,7 @@ int __init rpl_ipfrag_init(void) ip4_frags.qsize = sizeof(struct ipq); ip4_frags.match = ip4_frag_match; ip4_frags.frag_expire = ip_expire; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0) +#ifdef HAVE_INET_FRAGS_WITH_FRAGS_WORK ip4_frags.frags_cache_name = ip_frag_cache_name; #endif if (inet_frags_init(&ip4_frags)) { diff --git a/datapath/linux/compat/nf_conntrack_reasm.c b/datapath/linux/compat/nf_conntrack_reasm.c index 1e207b123..89a39789d 100644 --- a/datapath/linux/compat/nf_conntrack_reasm.c +++ b/datapath/linux/compat/nf_conntrack_reasm.c @@ -631,7 +631,7 @@ int rpl_nf_ct_frag6_init(void) nf_frags.qsize = sizeof(struct frag_queue); nf_frags.match = rpl_ip6_frag_match; nf_frags.frag_expire = nf_ct_frag6_expire; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0) +#ifdef HAVE_INET_FRAGS_WITH_FRAGS_WORK nf_frags.frags_cache_name = nf_frags_cache_name; #endif ret = inet_frags_init(&nf_frags); -- 2.39.5