Am Thu, Jun 18, 2026 at 04:25:01PM +0200 schrieb Felix Huettner:
> If a single zone creates a lot of churn we would have otherwise blocked
> the clean thread for quite a while.
> 
> The approach with cmap_position might have the drawback that we
> potentially skip some connections that have been inserted in the
> meantime, but cmap_cursor can not be used as we have a rcu quiesce
> period in between iterations.
> 
> When using the same testcases as in the previous commit
> Below lists the total time for the testrun with these various configs.
> |          | Without this patch | With this patch |
> | Config 1 | 17.9 s             | 31.7 s          |
> | Config 2 | 22.9 s             | 32.6 s          |
> | Config 3 | 19.2 s             | 42.2 s          |
> | Config 4 | 18.5 s             | 16.2 s          |
> | Config 5 | 47.0 s             | 45.3 s          |
> | Config 6 | 51.1 s             | 45.1 s          |
> 
> Obviously we are worse in most cases. However this patch is necessary to
> ensure even a single loaded zone will not cause the clean thread to
> take forever and thereby block rcu cleanup. Future commits will make
> this fast again.
> 
> Signed-off-by: Felix Huettner <[email protected]>
> ---
>  lib/conntrack-private.h | 11 ++++++++---
>  lib/conntrack.c         | 38 ++++++++++++++++++++++++++++----------
>  2 files changed, 36 insertions(+), 13 deletions(-)

Something strange happened in the CI in regards to installation of
dependencies.

Recheck-request: github-robot-_Build_and_Test

> 
> diff --git a/lib/conntrack-private.h b/lib/conntrack-private.h
> index 8282bbe5a..656222086 100644
> --- a/lib/conntrack-private.h
> +++ b/lib/conntrack-private.h
> @@ -215,9 +215,13 @@ struct conntrack {
>      atomic_uint32_t default_zone_limit;
>  
>      uint32_t hash_basis; /* Salt for hashing a connection key. */
> +
> +    /* Background cleanup thread. */
>      pthread_t clean_thread; /* Periodically cleans up connection tracker. */
>      struct latch clean_thread_exit; /* To destroy the 'clean_thread'. */
> -    unsigned int next_clean_zone; /* Next zone where the clean should run. */
> +    uint16_t current_clean_zone; /* Current zone where the clean should run. 
> */
> +    /* The position in the cmap of the current zone. */
> +    struct cmap_position *current_clean_position;
>  
>      /* Counting connections. */
>      atomic_count n_conn; /* Number of connections currently tracked. */
> @@ -239,8 +243,9 @@ struct conntrack {
>  
>  /* Lock acquisition order:
>   *    1. 'conn->lock'
> - *    2. 'ct_lock'
> - *    3. 'resources_lock'
> + *    2. 'zone_lock'
> + *    3. 'ct_lock'
> + *    4. 'resources_lock'
>   */
>  
>  extern struct ct_l4_proto ct_proto_tcp;
> diff --git a/lib/conntrack.c b/lib/conntrack.c
> index 6d28cffe3..7edcf8cc4 100644
> --- a/lib/conntrack.c
> +++ b/lib/conntrack.c
> @@ -519,6 +519,10 @@ conntrack_destroy(struct conntrack *ct)
>      ovs_mutex_unlock(&ct->resources_lock);
>      ovs_mutex_destroy(&ct->resources_lock);
>  
> +    if (ct->current_clean_position) {
> +        free(ct->current_clean_position);
> +    }
> +
>      ipf_destroy(ct->ipf);
>      free(ct);
>  }
> @@ -1485,18 +1489,32 @@ conntrack_get_sweep_interval(struct conntrack *ct)
>  
>  static size_t
>  ct_sweep_zone(struct conntrack *ct, uint16_t zone, long long now,
> -              size_t *cleaned_count)
> +              size_t *cleaned_count, size_t limit,
> +              struct cmap_position **current_position)
>      OVS_NO_THREAD_SAFETY_ANALYSIS
>  {
>      struct conn_key_node *keyn;
>      struct conntrack_zone *cz;
>      unsigned int conn_count = 0;
> -    unsigned int cleaned = 0;
>      struct conn *conn;
> +    struct cmap_node *node;
>      long long expiration;
>  
>      cz = zone_lookup(ct, zone);
> -    CMAP_FOR_EACH (keyn, cm_node, &cz->conns) {
> +    if (atomic_count_get(&cz->count) == 0) {
> +        return conn_count;
> +    }
> +
> +    if (!*current_position) {
> +        *current_position = xzalloc(sizeof(**current_position));
> +    }
> +
> +    while ((node = cmap_next_position(&cz->conns, *current_position))) {
> +        keyn = OBJECT_CONTAINING(node, keyn, cm_node);
> +        if (conn_count > limit) {
> +            return conn_count;
> +        }
> +
>          if (keyn->dir != CT_DIR_FWD) {
>              continue;
>          }
> @@ -1505,12 +1523,14 @@ ct_sweep_zone(struct conntrack *ct, uint16_t zone, 
> long long now,
>          expiration = conn_expiration(conn);
>          if (now >= expiration) {
>              conn_clean(ct, conn);
> -            cleaned++;
> +            (*cleaned_count)++;
>           }
>  
>          conn_count++;
>      }
> -    *cleaned_count = cleaned;
> +
> +    free(*current_position);
> +    *current_position = NULL;
>      return conn_count;
>  }
>  
> @@ -1524,7 +1544,6 @@ conntrack_clean(struct conntrack *ct, long long now)
>      unsigned int n_conn_limit, i;
>      size_t clean_end, count = 0;
>      size_t total_cleaned = 0;
> -    uint16_t current_zone = ct->next_clean_zone;
>  
>      atomic_read_relaxed(&ct->n_conn_limit, &n_conn_limit);
>      clean_end = n_conn_limit / 64;
> @@ -1537,16 +1556,15 @@ conntrack_clean(struct conntrack *ct, long long now)
>              break;
>          }
>  
> -        count += ct_sweep_zone(ct, current_zone, now, &cleaned);
> +        count += ct_sweep_zone(ct, ct->current_clean_zone, now, &cleaned,
> +                               clean_end - count, 
> &ct->current_clean_position);
>          total_cleaned += cleaned;
>  
>          /* This will overflow and thereby allow us to iterate through all
>           * zones. */
> -        current_zone++;
> +        ct->current_clean_zone++;
>      }
>  
> -    ct->next_clean_zone = current_zone + 1;
> -
>      VLOG_DBG("conntrack cleaned %"PRIuSIZE" entries out of %"PRIuSIZE
>               " entries in %lld msec", total_cleaned, count,
>               time_msec() - now);
> -- 
> 2.43.0
> 
> 
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to