diff mbox series

[ovs-dev,v10,2/3] conntrack: prefer dst port range during unique tuple search

Message ID 1642477806-18538-2-git-send-email-wenxu@ucloud.cn
State Superseded
Headers show
Series [ovs-dev,v10,1/3] conntrack: select correct sport range for well-known origin sport | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test success github build: passed

Commit Message

wenxu Jan. 18, 2022, 3:50 a.m. UTC
From: wenxu <wenxu@ucloud.cn>

This commit splits the nested loop used to search the unique ports for
the reverse tuple.
It affects only the dnat action, giving more precedence to the dnat
range, similarly to the kernel dp, instead of searching through the
default ephemeral source range for each destination port.

Signed-off-by: wenxu <wenxu@ucloud.cn>
---
 lib/conntrack.c | 61 +++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 46 insertions(+), 15 deletions(-)

Comments

Paolo Valerio Jan. 30, 2022, 9:27 p.m. UTC | #1
wenxu@ucloud.cn writes:

> From: wenxu <wenxu@ucloud.cn>
>
> This commit splits the nested loop used to search the unique ports for
> the reverse tuple.
> It affects only the dnat action, giving more precedence to the dnat
> range, similarly to the kernel dp, instead of searching through the
> default ephemeral source range for each destination port.
>
> Signed-off-by: wenxu <wenxu@ucloud.cn>
> ---
>  lib/conntrack.c | 61 +++++++++++++++++++++++++++++++++++++++++++--------------
>  1 file changed, 46 insertions(+), 15 deletions(-)
>

The patch LGTM.

Please, consider this small improvement on top of this,
if you think it makes sense. It simply removes some redundant
assignments.

--- a/lib/conntrack.c
+++ b/lib/conntrack.c
@@ -2402,6 +2402,8 @@ nat_get_unique_l4(struct conntrack *ct, struct conn *nat_conn,
                   ovs_be16 *port, uint16_t curr, uint16_t min,
                   uint16_t max)
 {
+    uint16_t orig = curr;
+
     FOR_EACH_PORT_IN_RANGE(curr, min, max) {
         *port = htons(curr);
         if (!conn_lookup(ct, &nat_conn->rev_key,
@@ -2410,6 +2412,8 @@ nat_get_unique_l4(struct conntrack *ct, struct conn *nat_conn,
         }
     }
 
+    *port = htons(orig);
+
     return false;
 }
 
@@ -2442,8 +2446,8 @@ nat_get_unique_tuple(struct conntrack *ct, const struct conn *conn,
     union ct_addr min_addr = {0}, max_addr = {0}, curr_addr = {0},
                   guard_addr = {0};
     uint32_t hash = nat_range_hash(conn, ct->hash_basis, nat_info);
-    uint16_t min_sport, max_sport, curr_sport, orig_sport;
-    uint16_t min_dport, max_dport, curr_dport, orig_dport;
+    uint16_t min_sport, max_sport, curr_sport, min_dport,
+        max_dport, curr_dport;
     bool pat_proto = conn->key.nw_proto == IPPROTO_TCP ||
                      conn->key.nw_proto == IPPROTO_UDP;
 
@@ -2457,11 +2461,16 @@ nat_get_unique_tuple(struct conntrack *ct, const struct conn *conn,
      * we can stop once we reach it. */
     guard_addr = curr_addr;
 
-    set_sport_range(nat_info, &conn->key, hash, &orig_sport,
+    set_sport_range(nat_info, &conn->key, hash, &curr_sport,
                     &min_sport, &max_sport);
-    set_dport_range(nat_info, &conn->key, hash, &orig_dport,
+    set_dport_range(nat_info, &conn->key, hash, &curr_dport,
                     &min_dport, &max_dport);
 
+    if (pat_proto) {
+        nat_conn->rev_key.src.port = htons(curr_dport);
+        nat_conn->rev_key.dst.port = htons(curr_sport);
+    }
+
 another_round:
     store_addr_to_key(&curr_addr, &nat_conn->rev_key,
                       nat_info->nat_action);
@@ -2475,19 +2484,10 @@ another_round:
         goto next_addr;
     }
 
-    curr_sport = orig_sport;
-    curr_dport = orig_dport;
-
-    nat_conn->rev_key.src.port = htons(curr_dport);
-    nat_conn->rev_key.dst.port = htons(curr_sport);
-
     bool found = false;
     if (nat_info->nat_action & NAT_ACTION_DST_PORT) {
         found = nat_get_unique_l4(ct, nat_conn, &nat_conn->rev_key.src.port,
                                   curr_dport, min_dport, max_dport);
-        if (!found) {
-            nat_conn->rev_key.src.port = htons(orig_dport);
-        }
     }
 
     if (!found) {

> diff --git a/lib/conntrack.c b/lib/conntrack.c
> index 44f99f3..dc29c9b 100644
> --- a/lib/conntrack.c
> +++ b/lib/conntrack.c
> @@ -2397,6 +2397,22 @@ next_addr_in_range_guarded(union ct_addr *curr, union ct_addr *min,
>      return exhausted;
>  }
>  
> +static bool
> +nat_get_unique_l4(struct conntrack *ct, struct conn *nat_conn,
> +                  ovs_be16 *port, uint16_t curr, uint16_t min,
> +                  uint16_t max)
> +{
> +    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;
> +        }
> +    }
> +
> +    return false;
> +}
> +
>  /* This function tries to get a unique tuple.
>   * Every iteration checks that the reverse tuple doesn't
>   * collide with any existing one.
> @@ -2411,9 +2427,11 @@ next_addr_in_range_guarded(union ct_addr *curr, union ct_addr *min,
>   *
>   * In case of DNAT:
>   *    - For each dst IP address in the range (if any).
> - *        - For each dport in range (if any).
> - *             - Try to find a source port in the ephemeral range
> - *               (after testing the port used by the sender).
> + *        - For each dport in range (if any) tries to find
> + *          an unique tuple.
> + *        - Eventually, if the previous attempt fails,
> + *          tries to find a source port in the ephemeral
> + *          range (after testing the port used by the sender).
>   *
>   * If none can be found, return exhaustion to the caller. */
>  static bool
> @@ -2424,10 +2442,10 @@ nat_get_unique_tuple(struct conntrack *ct, const struct conn *conn,
>      union ct_addr min_addr = {0}, max_addr = {0}, curr_addr = {0},
>                    guard_addr = {0};
>      uint32_t hash = nat_range_hash(conn, ct->hash_basis, nat_info);
> +    uint16_t min_sport, max_sport, curr_sport, orig_sport;
> +    uint16_t min_dport, max_dport, curr_dport, orig_dport;
>      bool pat_proto = conn->key.nw_proto == IPPROTO_TCP ||
>                       conn->key.nw_proto == IPPROTO_UDP;
> -    uint16_t min_dport, max_dport, curr_dport;
> -    uint16_t min_sport, max_sport, curr_sport;
>  
>      min_addr = nat_info->min_addr;
>      max_addr = nat_info->max_addr;
> @@ -2439,9 +2457,9 @@ nat_get_unique_tuple(struct conntrack *ct, const struct conn *conn,
>       * we can stop once we reach it. */
>      guard_addr = curr_addr;
>  
> -    set_sport_range(nat_info, &conn->key, hash, &curr_sport,
> +    set_sport_range(nat_info, &conn->key, hash, &orig_sport,
>                      &min_sport, &max_sport);
> -    set_dport_range(nat_info, &conn->key, hash, &curr_dport,
> +    set_dport_range(nat_info, &conn->key, hash, &orig_dport,
>                      &min_dport, &max_dport);
>  
>  another_round:
> @@ -2457,17 +2475,30 @@ another_round:
>          goto next_addr;
>      }
>  
> -    FOR_EACH_PORT_IN_RANGE(curr_dport, min_dport, max_dport) {
> -        nat_conn->rev_key.src.port = htons(curr_dport);
> -        FOR_EACH_PORT_IN_RANGE(curr_sport, min_sport, max_sport) {
> -            nat_conn->rev_key.dst.port = htons(curr_sport);
> -            if (!conn_lookup(ct, &nat_conn->rev_key,
> -                             time_msec(), NULL, NULL)) {
> -                return true;
> -            }
> +    curr_sport = orig_sport;
> +    curr_dport = orig_dport;
> +
> +    nat_conn->rev_key.src.port = htons(curr_dport);
> +    nat_conn->rev_key.dst.port = htons(curr_sport);
> +
> +    bool found = false;
> +    if (nat_info->nat_action & NAT_ACTION_DST_PORT) {
> +        found = nat_get_unique_l4(ct, nat_conn, &nat_conn->rev_key.src.port,
> +                                  curr_dport, min_dport, max_dport);
> +        if (!found) {
> +            nat_conn->rev_key.src.port = htons(orig_dport);
>          }
>      }
>  
> +    if (!found) {
> +        found = nat_get_unique_l4(ct, nat_conn, &nat_conn->rev_key.dst.port,
> +                                  curr_sport, min_sport, max_sport);
> +    }
> +
> +    if (found) {
> +        return true;
> +    }
> +
>      /* Check if next IP is in range and respin. Otherwise, notify
>       * exhaustion to the caller. */
>  next_addr:
> -- 
> 1.8.3.1
diff mbox series

Patch

diff --git a/lib/conntrack.c b/lib/conntrack.c
index 44f99f3..dc29c9b 100644
--- a/lib/conntrack.c
+++ b/lib/conntrack.c
@@ -2397,6 +2397,22 @@  next_addr_in_range_guarded(union ct_addr *curr, union ct_addr *min,
     return exhausted;
 }
 
+static bool
+nat_get_unique_l4(struct conntrack *ct, struct conn *nat_conn,
+                  ovs_be16 *port, uint16_t curr, uint16_t min,
+                  uint16_t max)
+{
+    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;
+        }
+    }
+
+    return false;
+}
+
 /* This function tries to get a unique tuple.
  * Every iteration checks that the reverse tuple doesn't
  * collide with any existing one.
@@ -2411,9 +2427,11 @@  next_addr_in_range_guarded(union ct_addr *curr, union ct_addr *min,
  *
  * In case of DNAT:
  *    - For each dst IP address in the range (if any).
- *        - For each dport in range (if any).
- *             - Try to find a source port in the ephemeral range
- *               (after testing the port used by the sender).
+ *        - For each dport in range (if any) tries to find
+ *          an unique tuple.
+ *        - Eventually, if the previous attempt fails,
+ *          tries to find a source port in the ephemeral
+ *          range (after testing the port used by the sender).
  *
  * If none can be found, return exhaustion to the caller. */
 static bool
@@ -2424,10 +2442,10 @@  nat_get_unique_tuple(struct conntrack *ct, const struct conn *conn,
     union ct_addr min_addr = {0}, max_addr = {0}, curr_addr = {0},
                   guard_addr = {0};
     uint32_t hash = nat_range_hash(conn, ct->hash_basis, nat_info);
+    uint16_t min_sport, max_sport, curr_sport, orig_sport;
+    uint16_t min_dport, max_dport, curr_dport, orig_dport;
     bool pat_proto = conn->key.nw_proto == IPPROTO_TCP ||
                      conn->key.nw_proto == IPPROTO_UDP;
-    uint16_t min_dport, max_dport, curr_dport;
-    uint16_t min_sport, max_sport, curr_sport;
 
     min_addr = nat_info->min_addr;
     max_addr = nat_info->max_addr;
@@ -2439,9 +2457,9 @@  nat_get_unique_tuple(struct conntrack *ct, const struct conn *conn,
      * we can stop once we reach it. */
     guard_addr = curr_addr;
 
-    set_sport_range(nat_info, &conn->key, hash, &curr_sport,
+    set_sport_range(nat_info, &conn->key, hash, &orig_sport,
                     &min_sport, &max_sport);
-    set_dport_range(nat_info, &conn->key, hash, &curr_dport,
+    set_dport_range(nat_info, &conn->key, hash, &orig_dport,
                     &min_dport, &max_dport);
 
 another_round:
@@ -2457,17 +2475,30 @@  another_round:
         goto next_addr;
     }
 
-    FOR_EACH_PORT_IN_RANGE(curr_dport, min_dport, max_dport) {
-        nat_conn->rev_key.src.port = htons(curr_dport);
-        FOR_EACH_PORT_IN_RANGE(curr_sport, min_sport, max_sport) {
-            nat_conn->rev_key.dst.port = htons(curr_sport);
-            if (!conn_lookup(ct, &nat_conn->rev_key,
-                             time_msec(), NULL, NULL)) {
-                return true;
-            }
+    curr_sport = orig_sport;
+    curr_dport = orig_dport;
+
+    nat_conn->rev_key.src.port = htons(curr_dport);
+    nat_conn->rev_key.dst.port = htons(curr_sport);
+
+    bool found = false;
+    if (nat_info->nat_action & NAT_ACTION_DST_PORT) {
+        found = nat_get_unique_l4(ct, nat_conn, &nat_conn->rev_key.src.port,
+                                  curr_dport, min_dport, max_dport);
+        if (!found) {
+            nat_conn->rev_key.src.port = htons(orig_dport);
         }
     }
 
+    if (!found) {
+        found = nat_get_unique_l4(ct, nat_conn, &nat_conn->rev_key.dst.port,
+                                  curr_sport, min_sport, max_sport);
+    }
+
+    if (found) {
+        return true;
+    }
+
     /* Check if next IP is in range and respin. Otherwise, notify
      * exhaustion to the caller. */
 next_addr: