Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

netfilter: nf_conncount: increase the connection clean up limit to 64

After the optimization to only perform one GC per jiffy, a new problem
was introduced. If more than 8 new connections are tracked per jiffy the
list won't be cleaned up fast enough possibly reaching the limit
wrongly.

In order to prevent this issue, only skip the GC if it was already
triggered during the same jiffy and the increment is lower than the
clean up limit. In addition, increase the clean up limit to 64
connections to avoid triggering GC too often and do more effective GCs.

This has been tested using a HTTP server and several
performance tools while having nft_connlimit/xt_connlimit or OVS limit
configured.

Output of slowhttptest + OVS limit at 52000 connections:

slow HTTP test status on 340th second:
initializing: 0
pending: 432
connected: 51998
error: 0
closed: 0
service available: YES

Fixes: d265929930e2 ("netfilter: nf_conncount: reduce unnecessary GC")
Reported-by: Aleksandra Rukomoinikova <ARukomoinikova@k2.cloud>
Closes: https://lore.kernel.org/netfilter/b2064e7b-0776-4e14-adb6-c68080987471@k2.cloud/
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
Signed-off-by: Florian Westphal <fw@strlen.de>

authored by

Fernando Fernandez Mancera and committed by
Florian Westphal
21d033e4 8a49fc8d

+11 -5
+1
include/net/netfilter/nf_conntrack_count.h
··· 13 13 u32 last_gc; /* jiffies at most recent gc */ 14 14 struct list_head head; /* connections with the same filtering key */ 15 15 unsigned int count; /* length of list */ 16 + unsigned int last_gc_count; /* length of list at most recent gc */ 16 17 }; 17 18 18 19 struct nf_conncount_data *nf_conncount_init(struct net *net, unsigned int keylen);
+10 -5
net/netfilter/nf_conncount.c
··· 34 34 35 35 #define CONNCOUNT_SLOTS 256U 36 36 37 - #define CONNCOUNT_GC_MAX_NODES 8 38 - #define MAX_KEYLEN 5 37 + #define CONNCOUNT_GC_MAX_NODES 8 38 + #define CONNCOUNT_GC_MAX_COLLECT 64 39 + #define MAX_KEYLEN 5 39 40 40 41 /* we will save the tuples of all connections we care about */ 41 42 struct nf_conncount_tuple { ··· 183 182 goto out_put; 184 183 } 185 184 186 - if ((u32)jiffies == list->last_gc) 185 + if ((u32)jiffies == list->last_gc && 186 + (list->count - list->last_gc_count) < CONNCOUNT_GC_MAX_COLLECT) 187 187 goto add_new_node; 188 188 189 189 /* check the saved connections */ 190 190 list_for_each_entry_safe(conn, conn_n, &list->head, node) { 191 - if (collect > CONNCOUNT_GC_MAX_NODES) 191 + if (collect > CONNCOUNT_GC_MAX_COLLECT) 192 192 break; 193 193 194 194 found = find_or_evict(net, list, conn); ··· 232 230 nf_ct_put(found_ct); 233 231 } 234 232 list->last_gc = (u32)jiffies; 233 + list->last_gc_count = list->count; 235 234 236 235 add_new_node: 237 236 if (WARN_ON_ONCE(list->count > INT_MAX)) { ··· 280 277 spin_lock_init(&list->list_lock); 281 278 INIT_LIST_HEAD(&list->head); 282 279 list->count = 0; 280 + list->last_gc_count = 0; 283 281 list->last_gc = (u32)jiffies; 284 282 } 285 283 EXPORT_SYMBOL_GPL(nf_conncount_list_init); ··· 320 316 } 321 317 322 318 nf_ct_put(found_ct); 323 - if (collected > CONNCOUNT_GC_MAX_NODES) 319 + if (collected > CONNCOUNT_GC_MAX_COLLECT) 324 320 break; 325 321 } 326 322 327 323 if (!list->count) 328 324 ret = true; 329 325 list->last_gc = (u32)jiffies; 326 + list->last_gc_count = list->count; 330 327 331 328 return ret; 332 329 }