Message ID | 1649648615-59908-2-git-send-email-wenx05124561@163.com |
---|---|
State | Superseded |
Headers | show |
Series | [ovs-dev,1/2] conntrack: remove the IP iterations in nat_get_unique_l4 | expand |
Context | Check | Description |
---|---|---|
ovsrobot/apply-robot | success | apply and check: success |
ovsrobot/intel-ovs-compilation | success | test: success |
ovsrobot/github-robot-_Build_and_Test | success | github build: passed |
wenx05124561@163.com writes: > From: wenxu <wenxu@chinatelecom.cn> > > 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: wenxu <wenxu@chinatelecom.cn> > --- > lib/conntrack.c | 29 +++++++++++++++++++++++++---- > 1 file changed, 25 insertions(+), 4 deletions(-) > > diff --git a/lib/conntrack.c b/lib/conntrack.c > index ac95d0f..a776e57 100644 > --- a/lib/conntrack.c > +++ b/lib/conntrack.c > @@ -2359,16 +2359,37 @@ nat_get_unique_l4(struct conntrack *ct, struct conn *nat_conn, > ovs_be16 *port, uint16_t curr, uint16_t min, > uint16_t max) > { > + static const unsigned int max_attempts = 128; > + uint16_t range = max - min + 1; > + unsigned int attempts; > uint16_t orig = curr; > + unsigned int i = 0; > > + attempts = range; > + if (attempts > max_attempts) { > + attempts = max_attempts; > + } > + > +another_round: > + i = 0; > FOR_EACH_PORT_IN_RANGE (curr, min, max) { > - *port = htons(curr); > - if (!conn_lookup(ct, &nat_conn->rev_key, > - time_msec(), NULL, NULL)) { > - return true; can't we rewrite this as: if (i++ >= attempts) { break; } ... I find it a bit more readable in this case. > + if (i++ < attempts) { > + *port = htons(curr); > + if (!conn_lookup(ct, &nat_conn->rev_key, > + time_msec(), NULL, NULL)) { > + return true; > + } > + } else { > + break; > } > } > > + if (attempts < range && attempts >= 16) { > + attempts /= 2; > + curr = min + (random_uint32() % range); > + goto another_round; > + } > + > *port = htons(orig); > > return false; > -- > 1.8.3.1
diff --git a/lib/conntrack.c b/lib/conntrack.c index ac95d0f..a776e57 100644 --- a/lib/conntrack.c +++ b/lib/conntrack.c @@ -2359,16 +2359,37 @@ nat_get_unique_l4(struct conntrack *ct, struct conn *nat_conn, ovs_be16 *port, uint16_t curr, uint16_t min, uint16_t max) { + static const unsigned int max_attempts = 128; + uint16_t range = max - min + 1; + unsigned int attempts; uint16_t orig = curr; + unsigned int i = 0; + attempts = range; + if (attempts > max_attempts) { + attempts = max_attempts; + } + +another_round: + i = 0; FOR_EACH_PORT_IN_RANGE (curr, min, max) { - *port = htons(curr); - if (!conn_lookup(ct, &nat_conn->rev_key, - time_msec(), NULL, NULL)) { - return true; + if (i++ < attempts) { + *port = htons(curr); + if (!conn_lookup(ct, &nat_conn->rev_key, + time_msec(), NULL, NULL)) { + return true; + } + } else { + break; } } + if (attempts < range && attempts >= 16) { + attempts /= 2; + curr = min + (random_uint32() % range); + goto another_round; + } + *port = htons(orig); return false;