[ovs-dev] [PATCH v6 2/3] conntrack: split the dst and src port range iterations

Paolo Valerio pvalerio at redhat.com
Wed Nov 17 15:09:29 UTC 2021


Hi wenxu,

wenxu at ucloud.cn writes:

> From: wenxu <wenxu at ucloud.cn>
>
> Splitting the two port range iterations instead of keeping it nested. And
> the dst port (in case of DNAT) range would have precedence over the src
> manipulation in the resolution.
>
> Signed-off-by: wenxu <wenxu at ucloud.cn>
> ---
>  lib/conntrack.c | 65 +++++++++++++++++++++++++++------------------------------
>  1 file changed, 31 insertions(+), 34 deletions(-)
>
> diff --git a/lib/conntrack.c b/lib/conntrack.c
> index 44f99f3..a6784ba 100644
> --- a/lib/conntrack.c
> +++ b/lib/conntrack.c
> @@ -1036,6 +1036,17 @@ conn_not_found(struct conntrack *ct, struct dp_packet *pkt,
>                                                      nat_action_info);
>  
>                  if (!nat_res) {
> +                    if (nat_action_info->nat_action & NAT_ACTION_DST) {
> +                        struct nat_action_info_t tmp_nat_info;
> +
> +                        memset(&tmp_nat_info, 0, sizeof tmp_nat_info);
> +                        tmp_nat_info.nat_action = NAT_ACTION_SRC;
> +                        nat_res = nat_get_unique_tuple(ct, nc, nat_conn,
> +                                                       &tmp_nat_info);
> +                        if (!nat_res) {
> +                            goto nat_res_exhaustion;
> +                        }
> +                    }
>                      goto nat_res_exhaustion;
>                  }

is there any particular reason that brought you to call
nat_get_unique_tuple() twice instead of splitting the FOR_EACH with a
single call of nat_get_unique_tuple() ?

Something like:

FOR_EACH_PORT_IN_RANGE(curr_dport, min_dport, max_dport) {
   ...
}

FOR_EACH_PORT_IN_RANGE(curr_sport, min_sport, max_sport) {
   ...
}

That was my initial understanding. I suspect that approach would require
fewer changes as well.

>  
> @@ -2258,12 +2269,12 @@ nat_range_hash(const struct conn *conn, uint32_t basis,
>  
>  /* Ports are stored in host byte order for convenience. */
>  static void
> -set_sport_range(const struct nat_action_info_t *ni, const struct conn_key *k,
> -                uint32_t hash, uint16_t *curr, uint16_t *min,
> -                uint16_t *max)
> +set_port_range(const struct nat_action_info_t *ni, const struct conn_key *k,
> +               uint32_t hash, uint16_t *curr, uint16_t *min,
> +               uint16_t *max)
>  {
> -    if (((ni->nat_action & NAT_ACTION_SNAT_ALL) == NAT_ACTION_SRC) ||
> -        ((ni->nat_action & NAT_ACTION_DST))) {
> +    if ((ni->nat_action & NAT_ACTION_SRC) &&
> +        (!(ni->nat_action & NAT_ACTION_SRC_PORT))) {
>          *curr = ntohs(k->src.port);
>          if (*curr < 512) {
>              *min = 1;
> @@ -2275,6 +2286,10 @@ set_sport_range(const struct nat_action_info_t *ni, const struct conn_key *k,
>              *min = MIN_NAT_EPHEMERAL_PORT;
>              *max = MAX_NAT_EPHEMERAL_PORT;
>          }
> +    } else if ((ni->nat_action & NAT_ACTION_DST) &&
> +               (!(ni->nat_action & NAT_ACTION_DST_PORT))) {
> +        *curr = ntohs(k->dst.port);
> +        *min = *max = *curr;
>      } else {
>          *min = ni->min_port;
>          *max = ni->max_port;
> @@ -2282,21 +2297,6 @@ set_sport_range(const struct nat_action_info_t *ni, const struct conn_key *k,
>      }
>  }
>  
> -static void
> -set_dport_range(const struct nat_action_info_t *ni, const struct conn_key *k,
> -                uint32_t hash, uint16_t *curr, uint16_t *min,
> -                uint16_t *max)
> -{
> -    if (ni->nat_action & NAT_ACTION_DST_PORT) {
> -        *min = ni->min_port;
> -        *max = ni->max_port;
> -        *curr = *min + (hash % ((*max - *min) + 1));
> -    } else {
> -        *curr = ntohs(k->dst.port);
> -        *min = *max = *curr;
> -    }
> -}
> -
>  /* Gets the initial in range address based on the hash.
>   * Addresses are kept in network order. */
>  static void
> @@ -2426,8 +2426,7 @@ nat_get_unique_tuple(struct conntrack *ct, const struct conn *conn,
>      uint32_t hash = nat_range_hash(conn, ct->hash_basis, nat_info);
>      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;
> +    uint16_t min_port, max_port, curr_port;
>  
>      min_addr = nat_info->min_addr;
>      max_addr = nat_info->max_addr;
> @@ -2439,10 +2438,8 @@ 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,
> -                    &min_sport, &max_sport);
> -    set_dport_range(nat_info, &conn->key, hash, &curr_dport,
> -                    &min_dport, &max_dport);
> +    set_port_range(nat_info, &conn->key, hash, &curr_port,
> +                   &min_port, &max_port);
>  
>  another_round:
>      store_addr_to_key(&curr_addr, &nat_conn->rev_key,
> @@ -2457,14 +2454,14 @@ 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;
> -            }
> +    FOR_EACH_PORT_IN_RANGE(curr_port, min_port, max_port) {
> +        if (nat_info->nat_action & NAT_ACTION_SRC) {
> +            nat_conn->rev_key.dst.port = htons(curr_port);
> +        } else {
> +            nat_conn->rev_key.src.port = htons(curr_port);
> +        }
> +        if (!conn_lookup(ct, &nat_conn->rev_key, time_msec(), NULL, NULL)) {
> +            return true;
>          }
>      }
>  
> -- 
> 1.8.3.1



More information about the dev mailing list