--- /dev/null
+From foo@baz Thu Feb 3 06:43:31 PM CET 2022
+From: Florian Westphal <fw@strlen.de>
+Date: Thu, 3 Feb 2022 13:32:55 +0100
+Subject: netfilter: nat: limit port clash resolution attempts
+To: <stable@vger.kernel.org>
+Cc: <netfilter-devel@vger.kernel.org>, Florian Westphal <fw@strlen.de>, Pablo Neira Ayuso <pablo@netfilter.org>
+Message-ID: <20220203123255.18974-3-fw@strlen.de>
+
+From: Florian Westphal <fw@strlen.de>
+
+commit a504b703bb1da526a01593da0e4be2af9d9f5fa8 upstream.
+
+In case almost or all available ports are taken, clash resolution can
+take a very long time, resulting in soft lockup.
+
+This can happen when many to-be-natted hosts connect to same
+destination:port (e.g. a proxy) and all connections pass the same SNAT.
+
+Pick a random offset in the acceptable range, then try ever smaller
+number of adjacent port numbers, until either the limit is reached or a
+useable port was found. This results in at most 248 attempts
+(128 + 64 + 32 + 16 + 8, i.e. 4 restarts with new search offset)
+instead of 64000+,
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/nf_nat_proto_common.c | 29 +++++++++++++++++++++++------
+ 1 file changed, 23 insertions(+), 6 deletions(-)
+
+--- a/net/netfilter/nf_nat_proto_common.c
++++ b/net/netfilter/nf_nat_proto_common.c
+@@ -40,9 +40,10 @@ void nf_nat_l4proto_unique_tuple(const s
+ enum nf_nat_manip_type maniptype,
+ const struct nf_conn *ct)
+ {
+- unsigned int range_size, min, max, i;
++ unsigned int range_size, min, max, i, attempts;
+ __be16 *portptr;
+- u_int16_t off;
++ u16 off;
++ static const unsigned int max_attempts = 128;
+
+ if (maniptype == NF_NAT_MANIP_SRC)
+ portptr = &tuple->src.u.all;
+@@ -86,12 +87,28 @@ void nf_nat_l4proto_unique_tuple(const s
+ off = prandom_u32();
+ }
+
+- for (i = 0; ; ++off) {
++ attempts = range_size;
++ if (attempts > max_attempts)
++ attempts = max_attempts;
++
++ /* We are in softirq; doing a search of the entire range risks
++ * soft lockup when all tuples are already used.
++ *
++ * If we can't find any free port from first offset, pick a new
++ * one and try again, with ever smaller search window.
++ */
++another_round:
++ for (i = 0; i < attempts; i++, off++) {
+ *portptr = htons(min + off % range_size);
+- if (++i != range_size && nf_nat_used_tuple(tuple, ct))
+- continue;
+- return;
++ if (!nf_nat_used_tuple(tuple, ct))
++ return;
+ }
++
++ if (attempts >= range_size || attempts < 16)
++ return;
++ attempts /= 2;
++ off = prandom_u32();
++ goto another_round;
+ }
+ EXPORT_SYMBOL_GPL(nf_nat_l4proto_unique_tuple);
+
--- /dev/null
+From foo@baz Thu Feb 3 06:43:31 PM CET 2022
+From: Florian Westphal <fw@strlen.de>
+Date: Thu, 3 Feb 2022 13:32:54 +0100
+Subject: netfilter: nat: remove l4 protocol port rovers
+To: <stable@vger.kernel.org>
+Cc: <netfilter-devel@vger.kernel.org>, Florian Westphal <fw@strlen.de>, Pablo Neira Ayuso <pablo@netfilter.org>
+Message-ID: <20220203123255.18974-2-fw@strlen.de>
+
+From: Florian Westphal <fw@strlen.de>
+
+commit 6ed5943f8735e2b778d92ea4d9805c0a1d89bc2b upstream.
+
+This is a leftover from days where single-cpu systems were common:
+Store last port used to resolve a clash to use it as a starting point when
+the next conflict needs to be resolved.
+
+When we have parallel attempt to connect to same address:port pair,
+its likely that both cores end up computing the same "available" port,
+as both use same starting port, and newly used ports won't become
+visible to other cores until the conntrack gets confirmed later.
+
+One of the cores then has to drop the packet at insertion time because
+the chosen new tuple turns out to be in use after all.
+
+Lets simplify this: remove port rover and use a pseudo-random starting
+point.
+
+Note that this doesn't make netfilter default to 'fully random' mode;
+the 'rover' was only used if NAT could not reuse source port as-is.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/netfilter/nf_nat_l4proto.h | 2 +-
+ net/netfilter/nf_nat_proto_common.c | 7 ++-----
+ net/netfilter/nf_nat_proto_dccp.c | 5 +----
+ net/netfilter/nf_nat_proto_sctp.c | 5 +----
+ net/netfilter/nf_nat_proto_tcp.c | 5 +----
+ net/netfilter/nf_nat_proto_udp.c | 5 +----
+ net/netfilter/nf_nat_proto_udplite.c | 5 +----
+ 7 files changed, 8 insertions(+), 26 deletions(-)
+
+--- a/include/net/netfilter/nf_nat_l4proto.h
++++ b/include/net/netfilter/nf_nat_l4proto.h
+@@ -64,7 +64,7 @@ void nf_nat_l4proto_unique_tuple(const s
+ struct nf_conntrack_tuple *tuple,
+ const struct nf_nat_range *range,
+ enum nf_nat_manip_type maniptype,
+- const struct nf_conn *ct, u16 *rover);
++ const struct nf_conn *ct);
+
+ int nf_nat_l4proto_nlattr_to_range(struct nlattr *tb[],
+ struct nf_nat_range *range);
+--- a/net/netfilter/nf_nat_proto_common.c
++++ b/net/netfilter/nf_nat_proto_common.c
+@@ -38,8 +38,7 @@ void nf_nat_l4proto_unique_tuple(const s
+ struct nf_conntrack_tuple *tuple,
+ const struct nf_nat_range *range,
+ enum nf_nat_manip_type maniptype,
+- const struct nf_conn *ct,
+- u16 *rover)
++ const struct nf_conn *ct)
+ {
+ unsigned int range_size, min, max, i;
+ __be16 *portptr;
+@@ -84,15 +83,13 @@ void nf_nat_l4proto_unique_tuple(const s
+ } else if (range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) {
+ off = prandom_u32();
+ } else {
+- off = *rover;
++ off = prandom_u32();
+ }
+
+ for (i = 0; ; ++off) {
+ *portptr = htons(min + off % range_size);
+ if (++i != range_size && nf_nat_used_tuple(tuple, ct))
+ continue;
+- if (!(range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL))
+- *rover = off;
+ return;
+ }
+ }
+--- a/net/netfilter/nf_nat_proto_dccp.c
++++ b/net/netfilter/nf_nat_proto_dccp.c
+@@ -20,8 +20,6 @@
+ #include <net/netfilter/nf_nat_l3proto.h>
+ #include <net/netfilter/nf_nat_l4proto.h>
+
+-static u_int16_t dccp_port_rover;
+-
+ static void
+ dccp_unique_tuple(const struct nf_nat_l3proto *l3proto,
+ struct nf_conntrack_tuple *tuple,
+@@ -29,8 +27,7 @@ dccp_unique_tuple(const struct nf_nat_l3
+ enum nf_nat_manip_type maniptype,
+ const struct nf_conn *ct)
+ {
+- nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct,
+- &dccp_port_rover);
++ nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct);
+ }
+
+ static bool
+--- a/net/netfilter/nf_nat_proto_sctp.c
++++ b/net/netfilter/nf_nat_proto_sctp.c
+@@ -14,8 +14,6 @@
+
+ #include <net/netfilter/nf_nat_l4proto.h>
+
+-static u_int16_t nf_sctp_port_rover;
+-
+ static void
+ sctp_unique_tuple(const struct nf_nat_l3proto *l3proto,
+ struct nf_conntrack_tuple *tuple,
+@@ -23,8 +21,7 @@ sctp_unique_tuple(const struct nf_nat_l3
+ enum nf_nat_manip_type maniptype,
+ const struct nf_conn *ct)
+ {
+- nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct,
+- &nf_sctp_port_rover);
++ nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct);
+ }
+
+ static bool
+--- a/net/netfilter/nf_nat_proto_tcp.c
++++ b/net/netfilter/nf_nat_proto_tcp.c
+@@ -18,8 +18,6 @@
+ #include <net/netfilter/nf_nat_l4proto.h>
+ #include <net/netfilter/nf_nat_core.h>
+
+-static u16 tcp_port_rover;
+-
+ static void
+ tcp_unique_tuple(const struct nf_nat_l3proto *l3proto,
+ struct nf_conntrack_tuple *tuple,
+@@ -27,8 +25,7 @@ tcp_unique_tuple(const struct nf_nat_l3p
+ enum nf_nat_manip_type maniptype,
+ const struct nf_conn *ct)
+ {
+- nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct,
+- &tcp_port_rover);
++ nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct);
+ }
+
+ static bool
+--- a/net/netfilter/nf_nat_proto_udp.c
++++ b/net/netfilter/nf_nat_proto_udp.c
+@@ -17,8 +17,6 @@
+ #include <net/netfilter/nf_nat_l3proto.h>
+ #include <net/netfilter/nf_nat_l4proto.h>
+
+-static u16 udp_port_rover;
+-
+ static void
+ udp_unique_tuple(const struct nf_nat_l3proto *l3proto,
+ struct nf_conntrack_tuple *tuple,
+@@ -26,8 +24,7 @@ udp_unique_tuple(const struct nf_nat_l3p
+ enum nf_nat_manip_type maniptype,
+ const struct nf_conn *ct)
+ {
+- nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct,
+- &udp_port_rover);
++ nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct);
+ }
+
+ static bool
+--- a/net/netfilter/nf_nat_proto_udplite.c
++++ b/net/netfilter/nf_nat_proto_udplite.c
+@@ -17,8 +17,6 @@
+ #include <net/netfilter/nf_nat_l3proto.h>
+ #include <net/netfilter/nf_nat_l4proto.h>
+
+-static u16 udplite_port_rover;
+-
+ static void
+ udplite_unique_tuple(const struct nf_nat_l3proto *l3proto,
+ struct nf_conntrack_tuple *tuple,
+@@ -26,8 +24,7 @@ udplite_unique_tuple(const struct nf_nat
+ enum nf_nat_manip_type maniptype,
+ const struct nf_conn *ct)
+ {
+- nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct,
+- &udplite_port_rover);
++ nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct);
+ }
+
+ static bool