Looping a large port range takes too long. Instead select a random offset within [ntohs(exp->saved_proto.tcp.port), 65535] and try 128 ports. This is a rehash of an erlier patch to do the same, but generalized to handle other helpers as well. Link: https://patchwork.ozlabs.org/project/netfilter-devel/patch/20210920204439.13179-2-Cole.Dishington@xxxxxxxxxxxxxxxxxxx/ Signed-off-by: Florian Westphal <fw@xxxxxxxxx> --- net/netfilter/nf_nat_helper.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nf_nat_helper.c b/net/netfilter/nf_nat_helper.c index 067d6d6f6b7d..a95a25196943 100644 --- a/net/netfilter/nf_nat_helper.c +++ b/net/netfilter/nf_nat_helper.c @@ -201,8 +201,18 @@ EXPORT_SYMBOL(nf_nat_follow_master); u16 nf_nat_exp_find_port(struct nf_conntrack_expect *exp, u16 port) { + static const unsigned int max_attempts = 128; + int range, attempts_left; + u16 min = port; + + range = USHRT_MAX - port; + attempts_left = range; + + if (attempts_left > max_attempts) + attempts_left = max_attempts; + /* Try to get same port: if not, try to change it. */ - for (; port != 0; port++) { + for (;;) { int res; exp->tuple.dst.u.tcp.port = htons(port); @@ -210,8 +220,10 @@ u16 nf_nat_exp_find_port(struct nf_conntrack_expect *exp, u16 port) if (res == 0) return port; - if (res != -EBUSY) + if (res != -EBUSY || (--attempts_left < 0)) break; + + port = min + prandom_u32_max(range); } return 0; -- 2.35.1