diff mbox series

[ovs-dev,1/5] ovn-util: Factor out struct sorted_addresses into sorted_array.

Message ID 169167147158.2447623.6554641432367089545.stgit@dceara.remote.csb
State Accepted
Headers show
Series Add port group incremental processing in northd. | expand

Checks

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

Commit Message

Dumitru Ceara Aug. 10, 2023, 12:44 p.m. UTC
It's actually a generic wrapper and will be useful for upcoming commits.
This commit doesn't perform any functional changes but cleans up a bit
the implementation unifying the sorted_array cleanup.  Before the change
the caller had to track whether it should free the internal 'arr' field
or not.  It's now taken care of inside the sorted_array_destroy() API
which the user always has to call.

Signed-off-by: Dumitru Ceara <dceara@redhat.com>
---
 lib/ovn-util.h      |   78 +++++++++++++++++++++++++++
 northd/en-sync-sb.c |  150 +++++++++++++++++----------------------------------
 2 files changed, 127 insertions(+), 101 deletions(-)

Comments

Han Zhou Aug. 22, 2023, 5:50 a.m. UTC | #1
On Thu, Aug 10, 2023 at 5:44 AM Dumitru Ceara <dceara@redhat.com> wrote:
>
> It's actually a generic wrapper and will be useful for upcoming commits.
> This commit doesn't perform any functional changes but cleans up a bit
> the implementation unifying the sorted_array cleanup.  Before the change
> the caller had to track whether it should free the internal 'arr' field
> or not.  It's now taken care of inside the sorted_array_destroy() API
> which the user always has to call.
>
> Signed-off-by: Dumitru Ceara <dceara@redhat.com>
> ---
>  lib/ovn-util.h      |   78 +++++++++++++++++++++++++++
>  northd/en-sync-sb.c |  150
+++++++++++++++++----------------------------------
>  2 files changed, 127 insertions(+), 101 deletions(-)
>
> diff --git a/lib/ovn-util.h b/lib/ovn-util.h
> index 5ebdd8adb0..2de7725132 100644
> --- a/lib/ovn-util.h
> +++ b/lib/ovn-util.h
> @@ -18,6 +18,8 @@
>
>  #include "ovsdb-idl.h"
>  #include "lib/packets.h"
> +#include "lib/sset.h"
> +#include "lib/svec.h"
>  #include "include/ovn/version.h"
>
>  #define ovn_set_program_name(name) \
> @@ -409,4 +411,80 @@ void flow_collector_ids_clear(struct
flow_collector_ids *);
>   * The returned pointer has to be freed by caller. */
>  char *encode_fqdn_string(const char *fqdn, size_t *len);
>
> +/* A wrapper that holds sorted arrays of strings. */
> +struct sorted_array {
> +    const char **arr;
> +    bool owns_array;
> +    size_t n;
> +};
> +
> +static inline struct sorted_array
> +sorted_array_create(const char **sorted_data, size_t n, bool
take_ownership)
> +{
> +    return (struct sorted_array) {
> +        .arr = sorted_data,
> +        .owns_array = take_ownership,
> +        .n = n,
> +    };
> +}
> +
> +static inline void
> +sorted_array_destroy(struct sorted_array *a)
> +{
> +    if (a->owns_array) {
> +        free(a->arr);
> +    }
> +}
> +
> +static inline struct sorted_array
> +sorted_array_from_svec(struct svec *v)
> +{
> +    svec_sort(v);
> +    return sorted_array_create((const char **) v->names, v->n, false);
> +}
> +
> +static inline struct sorted_array
> +sorted_array_from_sset(struct sset *s)
> +{
> +    return sorted_array_create(sset_sort(s), sset_count(s), true);
> +}
> +
> +/* DB set columns are already sorted, just wrap them into a sorted
array. */
> +#define sorted_array_from_dbrec(dbrec, column)           \
> +    sorted_array_create((const char **) (dbrec)->column, \
> +                        (dbrec)->n_##column, false)
> +
> +static inline void
> +sorted_array_apply_diff(const struct sorted_array *a1,
> +                        const struct sorted_array *a2,
> +                        void (*apply_callback)(const void *arg,
> +                                               const char *item,
> +                                               bool add),
> +                        const void *arg)
> +{
> +    size_t idx1, idx2;
> +
> +    for (idx1 = idx2 = 0; idx1 < a1->n && idx2 < a2->n;) {
> +        int cmp = strcmp(a1->arr[idx1], a2->arr[idx2]);
> +        if (cmp < 0) {
> +            apply_callback(arg, a1->arr[idx1], true);
> +            idx1++;
> +        } else if (cmp > 0) {
> +            apply_callback(arg, a2->arr[idx2], false);
> +            idx2++;
> +        } else {
> +            idx1++;
> +            idx2++;
> +        }
> +    }
> +
> +    for (; idx1 < a1->n; idx1++) {
> +        apply_callback(arg, a1->arr[idx1], true);
> +    }
> +
> +    for (; idx2 < a2->n; idx2++) {
> +        apply_callback(arg, a2->arr[idx2], false);
> +    }
> +}

It would be better to move this function to the C file instead of inline
here.
With this addressed:

Acked-by: Han Zhou <hzhou@ovn.org>

> +
>  #endif /* OVN_UTIL_H */
> diff --git a/northd/en-sync-sb.c b/northd/en-sync-sb.c
> index d7fea981f2..f97771b3b4 100644
> --- a/northd/en-sync-sb.c
> +++ b/northd/en-sync-sb.c
> @@ -33,15 +33,8 @@
>
>  VLOG_DEFINE_THIS_MODULE(en_sync_to_sb);
>
> -/* This is just a type wrapper to enforce that it has to be sorted. */
> -struct sorted_addresses {
> -    const char **arr;
> -    size_t n;
> -};
> -
> -
>  static void sync_addr_set(struct ovsdb_idl_txn *ovnsb_txn, const char
*name,
> -                          struct sorted_addresses *addresses,
> +                          struct sorted_array *addresses,
>                            struct shash *sb_address_sets);
>  static void sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
>                             const struct nbrec_address_set_table *,
> @@ -50,17 +43,11 @@ static void sync_addr_sets(struct ovsdb_idl_txn
*ovnsb_txn,
>                             const struct ovn_datapaths *lr_datapaths);
>  static const struct sbrec_address_set *sb_address_set_lookup_by_name(
>      struct ovsdb_idl_index *, const char *name);
> -static void update_sb_addr_set(struct sorted_addresses *,
> +static void update_sb_addr_set(struct sorted_array *,
>                                 const struct sbrec_address_set *);
>  static void build_port_group_address_set(const struct nbrec_port_group *,
>                                           struct svec *ipv4_addrs,
>                                           struct svec *ipv6_addrs);
> -static struct sorted_addresses
> -sorted_addresses_from_nbrec(const struct nbrec_address_set *nb_as);
> -static struct sorted_addresses
> -sorted_addresses_from_svec(struct svec *addresses);
> -static struct sorted_addresses
> -sorted_addresses_from_sset(struct sset *addresses);
>
>  void *
>  en_sync_to_sb_init(struct engine_node *node OVS_UNUSED,
> @@ -145,9 +132,10 @@ sync_to_sb_addr_set_nb_address_set_handler(struct
engine_node *node,
>          if (!sb_addr_set) {
>              return false;
>          }
> -        struct sorted_addresses addrs =
> -                sorted_addresses_from_nbrec(nb_addr_set);
> +        struct sorted_array addrs =
> +            sorted_array_from_dbrec(nb_addr_set, addresses);
>          update_sb_addr_set(&addrs, sb_addr_set);
> +        sorted_array_destroy(&addrs);
>      }
>
>      return true;
> @@ -194,18 +182,20 @@ sync_to_sb_addr_set_nb_port_group_handler(struct
engine_node *node,
>          struct svec ipv6_addrs = SVEC_EMPTY_INITIALIZER;
>          build_port_group_address_set(nb_pg, &ipv4_addrs, &ipv6_addrs);
>
> -        struct sorted_addresses ipv4_addrs_sorted =
> -                sorted_addresses_from_svec(&ipv4_addrs);
> -        struct sorted_addresses ipv6_addrs_sorted =
> -                sorted_addresses_from_svec(&ipv6_addrs);
> +        struct sorted_array ipv4_addrs_sorted =
> +                sorted_array_from_svec(&ipv4_addrs);
> +        struct sorted_array ipv6_addrs_sorted =
> +                sorted_array_from_svec(&ipv6_addrs);
>
>          update_sb_addr_set(&ipv4_addrs_sorted, sb_addr_set_v4);
>          update_sb_addr_set(&ipv6_addrs_sorted, sb_addr_set_v6);
>
> -        free(ipv4_addrs_name);
> -        free(ipv6_addrs_name);
> +        sorted_array_destroy(&ipv4_addrs_sorted);
> +        sorted_array_destroy(&ipv6_addrs_sorted);
>          svec_destroy(&ipv4_addrs);
>          svec_destroy(&ipv6_addrs);
> +        free(ipv4_addrs_name);
> +        free(ipv6_addrs_name);
>      }
>
>      return true;
> @@ -214,7 +204,7 @@ sync_to_sb_addr_set_nb_port_group_handler(struct
engine_node *node,
>  /* static functions. */
>  static void
>  sync_addr_set(struct ovsdb_idl_txn *ovnsb_txn, const char *name,
> -              struct sorted_addresses *addresses,
> +              struct sorted_array *addresses,
>                struct shash *sb_address_sets)
>  {
>      const struct sbrec_address_set *sb_address_set;
> @@ -261,11 +251,9 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
>
>      /* Service monitor MAC. */
>      const char *svc_monitor_macp = northd_get_svc_monitor_mac();
> -    struct sorted_addresses svc = {
> -            .arr = &svc_monitor_macp,
> -            .n = 1,
> -    };
> +    struct sorted_array svc = sorted_array_create(&svc_monitor_macp, 1,
false);
>      sync_addr_set(ovnsb_txn, "svc_monitor_mac", &svc, &sb_address_sets);
> +    sorted_array_destroy(&svc);
>
>      /* sync port group generated address sets first */
>      const struct nbrec_port_group *nb_port_group;
> @@ -277,19 +265,21 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
>          char *ipv4_addrs_name = xasprintf("%s_ip4", nb_port_group->name);
>          char *ipv6_addrs_name = xasprintf("%s_ip6", nb_port_group->name);
>
> -        struct sorted_addresses ipv4_addrs_sorted =
> -                sorted_addresses_from_svec(&ipv4_addrs);
> -        struct sorted_addresses ipv6_addrs_sorted =
> -                sorted_addresses_from_svec(&ipv6_addrs);
> +        struct sorted_array ipv4_addrs_sorted =
> +                sorted_array_from_svec(&ipv4_addrs);
> +        struct sorted_array ipv6_addrs_sorted =
> +                sorted_array_from_svec(&ipv6_addrs);
>
>          sync_addr_set(ovnsb_txn, ipv4_addrs_name,
>                        &ipv4_addrs_sorted, &sb_address_sets);
>          sync_addr_set(ovnsb_txn, ipv6_addrs_name,
>                        &ipv6_addrs_sorted, &sb_address_sets);
> -        free(ipv4_addrs_name);
> -        free(ipv6_addrs_name);
> +        sorted_array_destroy(&ipv4_addrs_sorted);
> +        sorted_array_destroy(&ipv6_addrs_sorted);
>          svec_destroy(&ipv4_addrs);
>          svec_destroy(&ipv6_addrs);
> +        free(ipv4_addrs_name);
> +        free(ipv6_addrs_name);
>      }
>
>      /* Sync router load balancer VIP generated address sets. */
> @@ -301,24 +291,24 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
>              char *ipv4_addrs_name =
lr_lb_address_set_name(od->tunnel_key,
>                                                             AF_INET);
>
> -            struct sorted_addresses ipv4_addrs_sorted =
> -
 sorted_addresses_from_sset(&od->lb_ips->ips_v4_reachable);
> +            struct sorted_array ipv4_addrs_sorted =
> +
 sorted_array_from_sset(&od->lb_ips->ips_v4_reachable);
>
>              sync_addr_set(ovnsb_txn, ipv4_addrs_name,
>                            &ipv4_addrs_sorted, &sb_address_sets);
> -            free(ipv4_addrs_sorted.arr);
> +            sorted_array_destroy(&ipv4_addrs_sorted);
>              free(ipv4_addrs_name);
>          }
>
>          if (sset_count(&od->lb_ips->ips_v6_reachable)) {
>              char *ipv6_addrs_name =
lr_lb_address_set_name(od->tunnel_key,
>                                                             AF_INET6);
> -            struct sorted_addresses ipv6_addrs_sorted =
> -
 sorted_addresses_from_sset(&od->lb_ips->ips_v6_reachable);
> +            struct sorted_array ipv6_addrs_sorted =
> +
 sorted_array_from_sset(&od->lb_ips->ips_v6_reachable);
>
>              sync_addr_set(ovnsb_txn, ipv6_addrs_name,
>                            &ipv6_addrs_sorted, &sb_address_sets);
> -            free(ipv6_addrs_sorted.arr);
> +            sorted_array_destroy(&ipv6_addrs_sorted);
>              free(ipv6_addrs_name);
>          }
>      }
> @@ -328,10 +318,11 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
>      const struct nbrec_address_set *nb_address_set;
>      NBREC_ADDRESS_SET_TABLE_FOR_EACH (nb_address_set,
>                                        nb_address_set_table) {
> -        struct sorted_addresses addrs =
> -                sorted_addresses_from_nbrec(nb_address_set);
> +        struct sorted_array addrs =
> +                sorted_array_from_dbrec(nb_address_set, addresses);
>          sync_addr_set(ovnsb_txn, nb_address_set->name,
>                        &addrs, &sb_address_sets);
> +        sorted_array_destroy(&addrs);
>      }
>
>      struct shash_node *node;
> @@ -343,39 +334,25 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
>  }
>
>  static void
> -update_sb_addr_set(struct sorted_addresses *nb_addresses,
> -                   const struct sbrec_address_set *sb_as)
> +sb_addr_set_apply_diff(const void *arg, const char *item, bool add)
>  {
> -    size_t nb_index, sb_index;
> -
> -    const char **nb_arr = nb_addresses->arr;
> -    char **sb_arr = sb_as->addresses;
> -    size_t nb_n = nb_addresses->n;
> -    size_t sb_n = sb_as->n_addresses;
> -
> -    for (nb_index = sb_index = 0; nb_index < nb_n && sb_index < sb_n;) {
> -        int cmp = strcmp(nb_arr[nb_index], sb_arr[sb_index]);
> -        if (cmp < 0) {
> -            sbrec_address_set_update_addresses_addvalue(sb_as,
> -
 nb_arr[nb_index]);
> -            nb_index++;
> -        } else if (cmp > 0) {
> -            sbrec_address_set_update_addresses_delvalue(sb_as,
> -
 sb_arr[sb_index]);
> -            sb_index++;
> -        } else {
> -            nb_index++;
> -            sb_index++;
> -        }
> -    }
> -
> -    for (; nb_index < nb_n; nb_index++) {
> -        sbrec_address_set_update_addresses_addvalue(sb_as,
nb_arr[nb_index]);
> +    const struct sbrec_address_set *as = arg;
> +    if (add) {
> +        sbrec_address_set_update_addresses_addvalue(as, item);
> +    } else {
> +        sbrec_address_set_update_addresses_delvalue(as, item);
>      }
> +}
>
> -    for (; sb_index < sb_n; sb_index++) {
> -        sbrec_address_set_update_addresses_delvalue(sb_as,
sb_arr[sb_index]);
> -    }
> +static void
> +update_sb_addr_set(struct sorted_array *nb_addresses,
> +                   const struct sbrec_address_set *sb_as)
> +{
> +    struct sorted_array sb_addresses =
> +        sorted_array_from_dbrec(sb_as, addresses);
> +    sorted_array_apply_diff(nb_addresses, &sb_addresses,
> +                            sb_addr_set_apply_diff, sb_as);
> +    sorted_array_destroy(&sb_addresses);
>  }
>
>  static void
> @@ -414,32 +391,3 @@ sb_address_set_lookup_by_name(struct ovsdb_idl_index
*sbrec_addr_set_by_name,
>
>      return retval;
>  }
> -
> -static struct sorted_addresses
> -sorted_addresses_from_nbrec(const struct nbrec_address_set *nb_as)
> -{
> -    /* The DB is already sorted. */
> -    return (struct sorted_addresses) {
> -        .arr = (const char **) nb_as->addresses,
> -        .n = nb_as->n_addresses,
> -    };
> -}
> -
> -static struct sorted_addresses
> -sorted_addresses_from_svec(struct svec *addresses)
> -{
> -    svec_sort(addresses);
> -    return (struct sorted_addresses) {
> -        .arr = (const char **) addresses->names,
> -        .n = addresses->n,
> -    };
> -}
> -
> -static struct sorted_addresses
> -sorted_addresses_from_sset(struct sset *addresses)
> -{
> -    return (struct sorted_addresses) {
> -        .arr = sset_sort(addresses),
> -        .n = sset_count(addresses),
> -    };
> -}
>
Ales Musil Aug. 22, 2023, 6:08 a.m. UTC | #2
On Thu, Aug 10, 2023 at 2:44 PM Dumitru Ceara <dceara@redhat.com> wrote:

> It's actually a generic wrapper and will be useful for upcoming commits.
> This commit doesn't perform any functional changes but cleans up a bit
> the implementation unifying the sorted_array cleanup.  Before the change
> the caller had to track whether it should free the internal 'arr' field
> or not.  It's now taken care of inside the sorted_array_destroy() API
> which the user always has to call.
>
> Signed-off-by: Dumitru Ceara <dceara@redhat.com>
> ---
>  lib/ovn-util.h      |   78 +++++++++++++++++++++++++++
>  northd/en-sync-sb.c |  150
> +++++++++++++++++----------------------------------
>  2 files changed, 127 insertions(+), 101 deletions(-)
>
> diff --git a/lib/ovn-util.h b/lib/ovn-util.h
> index 5ebdd8adb0..2de7725132 100644
> --- a/lib/ovn-util.h
> +++ b/lib/ovn-util.h
> @@ -18,6 +18,8 @@
>
>  #include "ovsdb-idl.h"
>  #include "lib/packets.h"
> +#include "lib/sset.h"
> +#include "lib/svec.h"
>  #include "include/ovn/version.h"
>
>  #define ovn_set_program_name(name) \
> @@ -409,4 +411,80 @@ void flow_collector_ids_clear(struct
> flow_collector_ids *);
>   * The returned pointer has to be freed by caller. */
>  char *encode_fqdn_string(const char *fqdn, size_t *len);
>
> +/* A wrapper that holds sorted arrays of strings. */
> +struct sorted_array {
> +    const char **arr;
> +    bool owns_array;
> +    size_t n;
> +};
> +
> +static inline struct sorted_array
> +sorted_array_create(const char **sorted_data, size_t n, bool
> take_ownership)
> +{
> +    return (struct sorted_array) {
> +        .arr = sorted_data,
> +        .owns_array = take_ownership,
> +        .n = n,
> +    };
> +}
> +
> +static inline void
> +sorted_array_destroy(struct sorted_array *a)
> +{
> +    if (a->owns_array) {
> +        free(a->arr);
> +    }
> +}
> +
> +static inline struct sorted_array
> +sorted_array_from_svec(struct svec *v)
> +{
> +    svec_sort(v);
> +    return sorted_array_create((const char **) v->names, v->n, false);
> +}
> +
> +static inline struct sorted_array
> +sorted_array_from_sset(struct sset *s)
> +{
> +    return sorted_array_create(sset_sort(s), sset_count(s), true);
> +}
> +
> +/* DB set columns are already sorted, just wrap them into a sorted array.
> */
> +#define sorted_array_from_dbrec(dbrec, column)           \
> +    sorted_array_create((const char **) (dbrec)->column, \
> +                        (dbrec)->n_##column, false)
> +
> +static inline void
> +sorted_array_apply_diff(const struct sorted_array *a1,
> +                        const struct sorted_array *a2,
> +                        void (*apply_callback)(const void *arg,
> +                                               const char *item,
> +                                               bool add),
> +                        const void *arg)
> +{
> +    size_t idx1, idx2;
> +
> +    for (idx1 = idx2 = 0; idx1 < a1->n && idx2 < a2->n;) {
> +        int cmp = strcmp(a1->arr[idx1], a2->arr[idx2]);
> +        if (cmp < 0) {
> +            apply_callback(arg, a1->arr[idx1], true);
> +            idx1++;
> +        } else if (cmp > 0) {
> +            apply_callback(arg, a2->arr[idx2], false);
> +            idx2++;
> +        } else {
> +            idx1++;
> +            idx2++;
> +        }
> +    }
> +
> +    for (; idx1 < a1->n; idx1++) {
> +        apply_callback(arg, a1->arr[idx1], true);
> +    }
> +
> +    for (; idx2 < a2->n; idx2++) {
> +        apply_callback(arg, a2->arr[idx2], false);
> +    }
> +}
> +
>  #endif /* OVN_UTIL_H */
> diff --git a/northd/en-sync-sb.c b/northd/en-sync-sb.c
> index d7fea981f2..f97771b3b4 100644
> --- a/northd/en-sync-sb.c
> +++ b/northd/en-sync-sb.c
> @@ -33,15 +33,8 @@
>
>  VLOG_DEFINE_THIS_MODULE(en_sync_to_sb);
>
> -/* This is just a type wrapper to enforce that it has to be sorted. */
> -struct sorted_addresses {
> -    const char **arr;
> -    size_t n;
> -};
> -
> -
>  static void sync_addr_set(struct ovsdb_idl_txn *ovnsb_txn, const char
> *name,
> -                          struct sorted_addresses *addresses,
> +                          struct sorted_array *addresses,
>                            struct shash *sb_address_sets);
>  static void sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
>                             const struct nbrec_address_set_table *,
> @@ -50,17 +43,11 @@ static void sync_addr_sets(struct ovsdb_idl_txn
> *ovnsb_txn,
>                             const struct ovn_datapaths *lr_datapaths);
>  static const struct sbrec_address_set *sb_address_set_lookup_by_name(
>      struct ovsdb_idl_index *, const char *name);
> -static void update_sb_addr_set(struct sorted_addresses *,
> +static void update_sb_addr_set(struct sorted_array *,
>                                 const struct sbrec_address_set *);
>  static void build_port_group_address_set(const struct nbrec_port_group *,
>                                           struct svec *ipv4_addrs,
>                                           struct svec *ipv6_addrs);
> -static struct sorted_addresses
> -sorted_addresses_from_nbrec(const struct nbrec_address_set *nb_as);
> -static struct sorted_addresses
> -sorted_addresses_from_svec(struct svec *addresses);
> -static struct sorted_addresses
> -sorted_addresses_from_sset(struct sset *addresses);
>
>  void *
>  en_sync_to_sb_init(struct engine_node *node OVS_UNUSED,
> @@ -145,9 +132,10 @@ sync_to_sb_addr_set_nb_address_set_handler(struct
> engine_node *node,
>          if (!sb_addr_set) {
>              return false;
>          }
> -        struct sorted_addresses addrs =
> -                sorted_addresses_from_nbrec(nb_addr_set);
> +        struct sorted_array addrs =
> +            sorted_array_from_dbrec(nb_addr_set, addresses);
>          update_sb_addr_set(&addrs, sb_addr_set);
> +        sorted_array_destroy(&addrs);
>      }
>
>      return true;
> @@ -194,18 +182,20 @@ sync_to_sb_addr_set_nb_port_group_handler(struct
> engine_node *node,
>          struct svec ipv6_addrs = SVEC_EMPTY_INITIALIZER;
>          build_port_group_address_set(nb_pg, &ipv4_addrs, &ipv6_addrs);
>
> -        struct sorted_addresses ipv4_addrs_sorted =
> -                sorted_addresses_from_svec(&ipv4_addrs);
> -        struct sorted_addresses ipv6_addrs_sorted =
> -                sorted_addresses_from_svec(&ipv6_addrs);
> +        struct sorted_array ipv4_addrs_sorted =
> +                sorted_array_from_svec(&ipv4_addrs);
> +        struct sorted_array ipv6_addrs_sorted =
> +                sorted_array_from_svec(&ipv6_addrs);
>
>          update_sb_addr_set(&ipv4_addrs_sorted, sb_addr_set_v4);
>          update_sb_addr_set(&ipv6_addrs_sorted, sb_addr_set_v6);
>
> -        free(ipv4_addrs_name);
> -        free(ipv6_addrs_name);
> +        sorted_array_destroy(&ipv4_addrs_sorted);
> +        sorted_array_destroy(&ipv6_addrs_sorted);
>          svec_destroy(&ipv4_addrs);
>          svec_destroy(&ipv6_addrs);
> +        free(ipv4_addrs_name);
> +        free(ipv6_addrs_name);
>      }
>
>      return true;
> @@ -214,7 +204,7 @@ sync_to_sb_addr_set_nb_port_group_handler(struct
> engine_node *node,
>  /* static functions. */
>  static void
>  sync_addr_set(struct ovsdb_idl_txn *ovnsb_txn, const char *name,
> -              struct sorted_addresses *addresses,
> +              struct sorted_array *addresses,
>                struct shash *sb_address_sets)
>  {
>      const struct sbrec_address_set *sb_address_set;
> @@ -261,11 +251,9 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
>
>      /* Service monitor MAC. */
>      const char *svc_monitor_macp = northd_get_svc_monitor_mac();
> -    struct sorted_addresses svc = {
> -            .arr = &svc_monitor_macp,
> -            .n = 1,
> -    };
> +    struct sorted_array svc = sorted_array_create(&svc_monitor_macp, 1,
> false);
>      sync_addr_set(ovnsb_txn, "svc_monitor_mac", &svc, &sb_address_sets);
> +    sorted_array_destroy(&svc);
>
>      /* sync port group generated address sets first */
>      const struct nbrec_port_group *nb_port_group;
> @@ -277,19 +265,21 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
>          char *ipv4_addrs_name = xasprintf("%s_ip4", nb_port_group->name);
>          char *ipv6_addrs_name = xasprintf("%s_ip6", nb_port_group->name);
>
> -        struct sorted_addresses ipv4_addrs_sorted =
> -                sorted_addresses_from_svec(&ipv4_addrs);
> -        struct sorted_addresses ipv6_addrs_sorted =
> -                sorted_addresses_from_svec(&ipv6_addrs);
> +        struct sorted_array ipv4_addrs_sorted =
> +                sorted_array_from_svec(&ipv4_addrs);
> +        struct sorted_array ipv6_addrs_sorted =
> +                sorted_array_from_svec(&ipv6_addrs);
>
>          sync_addr_set(ovnsb_txn, ipv4_addrs_name,
>                        &ipv4_addrs_sorted, &sb_address_sets);
>          sync_addr_set(ovnsb_txn, ipv6_addrs_name,
>                        &ipv6_addrs_sorted, &sb_address_sets);
> -        free(ipv4_addrs_name);
> -        free(ipv6_addrs_name);
> +        sorted_array_destroy(&ipv4_addrs_sorted);
> +        sorted_array_destroy(&ipv6_addrs_sorted);
>          svec_destroy(&ipv4_addrs);
>          svec_destroy(&ipv6_addrs);
> +        free(ipv4_addrs_name);
> +        free(ipv6_addrs_name);
>      }
>
>      /* Sync router load balancer VIP generated address sets. */
> @@ -301,24 +291,24 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
>              char *ipv4_addrs_name = lr_lb_address_set_name(od->tunnel_key,
>                                                             AF_INET);
>
> -            struct sorted_addresses ipv4_addrs_sorted =
> -
> sorted_addresses_from_sset(&od->lb_ips->ips_v4_reachable);
> +            struct sorted_array ipv4_addrs_sorted =
> +                    sorted_array_from_sset(&od->lb_ips->ips_v4_reachable);
>
>              sync_addr_set(ovnsb_txn, ipv4_addrs_name,
>                            &ipv4_addrs_sorted, &sb_address_sets);
> -            free(ipv4_addrs_sorted.arr);
> +            sorted_array_destroy(&ipv4_addrs_sorted);
>              free(ipv4_addrs_name);
>          }
>
>          if (sset_count(&od->lb_ips->ips_v6_reachable)) {
>              char *ipv6_addrs_name = lr_lb_address_set_name(od->tunnel_key,
>                                                             AF_INET6);
> -            struct sorted_addresses ipv6_addrs_sorted =
> -
> sorted_addresses_from_sset(&od->lb_ips->ips_v6_reachable);
> +            struct sorted_array ipv6_addrs_sorted =
> +                    sorted_array_from_sset(&od->lb_ips->ips_v6_reachable);
>
>              sync_addr_set(ovnsb_txn, ipv6_addrs_name,
>                            &ipv6_addrs_sorted, &sb_address_sets);
> -            free(ipv6_addrs_sorted.arr);
> +            sorted_array_destroy(&ipv6_addrs_sorted);
>              free(ipv6_addrs_name);
>          }
>      }
> @@ -328,10 +318,11 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
>      const struct nbrec_address_set *nb_address_set;
>      NBREC_ADDRESS_SET_TABLE_FOR_EACH (nb_address_set,
>                                        nb_address_set_table) {
> -        struct sorted_addresses addrs =
> -                sorted_addresses_from_nbrec(nb_address_set);
> +        struct sorted_array addrs =
> +                sorted_array_from_dbrec(nb_address_set, addresses);
>          sync_addr_set(ovnsb_txn, nb_address_set->name,
>                        &addrs, &sb_address_sets);
> +        sorted_array_destroy(&addrs);
>      }
>
>      struct shash_node *node;
> @@ -343,39 +334,25 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
>  }
>
>  static void
> -update_sb_addr_set(struct sorted_addresses *nb_addresses,
> -                   const struct sbrec_address_set *sb_as)
> +sb_addr_set_apply_diff(const void *arg, const char *item, bool add)
>  {
> -    size_t nb_index, sb_index;
> -
> -    const char **nb_arr = nb_addresses->arr;
> -    char **sb_arr = sb_as->addresses;
> -    size_t nb_n = nb_addresses->n;
> -    size_t sb_n = sb_as->n_addresses;
> -
> -    for (nb_index = sb_index = 0; nb_index < nb_n && sb_index < sb_n;) {
> -        int cmp = strcmp(nb_arr[nb_index], sb_arr[sb_index]);
> -        if (cmp < 0) {
> -            sbrec_address_set_update_addresses_addvalue(sb_as,
> -                                                        nb_arr[nb_index]);
> -            nb_index++;
> -        } else if (cmp > 0) {
> -            sbrec_address_set_update_addresses_delvalue(sb_as,
> -                                                        sb_arr[sb_index]);
> -            sb_index++;
> -        } else {
> -            nb_index++;
> -            sb_index++;
> -        }
> -    }
> -
> -    for (; nb_index < nb_n; nb_index++) {
> -        sbrec_address_set_update_addresses_addvalue(sb_as,
> nb_arr[nb_index]);
> +    const struct sbrec_address_set *as = arg;
> +    if (add) {
> +        sbrec_address_set_update_addresses_addvalue(as, item);
> +    } else {
> +        sbrec_address_set_update_addresses_delvalue(as, item);
>      }
> +}
>
> -    for (; sb_index < sb_n; sb_index++) {
> -        sbrec_address_set_update_addresses_delvalue(sb_as,
> sb_arr[sb_index]);
> -    }
> +static void
> +update_sb_addr_set(struct sorted_array *nb_addresses,
> +                   const struct sbrec_address_set *sb_as)
> +{
> +    struct sorted_array sb_addresses =
> +        sorted_array_from_dbrec(sb_as, addresses);
> +    sorted_array_apply_diff(nb_addresses, &sb_addresses,
> +                            sb_addr_set_apply_diff, sb_as);
> +    sorted_array_destroy(&sb_addresses);
>  }
>
>  static void
> @@ -414,32 +391,3 @@ sb_address_set_lookup_by_name(struct ovsdb_idl_index
> *sbrec_addr_set_by_name,
>
>      return retval;
>  }
> -
> -static struct sorted_addresses
> -sorted_addresses_from_nbrec(const struct nbrec_address_set *nb_as)
> -{
> -    /* The DB is already sorted. */
> -    return (struct sorted_addresses) {
> -        .arr = (const char **) nb_as->addresses,
> -        .n = nb_as->n_addresses,
> -    };
> -}
> -
> -static struct sorted_addresses
> -sorted_addresses_from_svec(struct svec *addresses)
> -{
> -    svec_sort(addresses);
> -    return (struct sorted_addresses) {
> -        .arr = (const char **) addresses->names,
> -        .n = addresses->n,
> -    };
> -}
> -
> -static struct sorted_addresses
> -sorted_addresses_from_sset(struct sset *addresses)
> -{
> -    return (struct sorted_addresses) {
> -        .arr = sset_sort(addresses),
> -        .n = sset_count(addresses),
> -    };
> -}
>
>
Happy to see that it has other uses besides the address sets.

Acked-by: Ales Musil <amusil@redhat.com>
diff mbox series

Patch

diff --git a/lib/ovn-util.h b/lib/ovn-util.h
index 5ebdd8adb0..2de7725132 100644
--- a/lib/ovn-util.h
+++ b/lib/ovn-util.h
@@ -18,6 +18,8 @@ 
 
 #include "ovsdb-idl.h"
 #include "lib/packets.h"
+#include "lib/sset.h"
+#include "lib/svec.h"
 #include "include/ovn/version.h"
 
 #define ovn_set_program_name(name) \
@@ -409,4 +411,80 @@  void flow_collector_ids_clear(struct flow_collector_ids *);
  * The returned pointer has to be freed by caller. */
 char *encode_fqdn_string(const char *fqdn, size_t *len);
 
+/* A wrapper that holds sorted arrays of strings. */
+struct sorted_array {
+    const char **arr;
+    bool owns_array;
+    size_t n;
+};
+
+static inline struct sorted_array
+sorted_array_create(const char **sorted_data, size_t n, bool take_ownership)
+{
+    return (struct sorted_array) {
+        .arr = sorted_data,
+        .owns_array = take_ownership,
+        .n = n,
+    };
+}
+
+static inline void
+sorted_array_destroy(struct sorted_array *a)
+{
+    if (a->owns_array) {
+        free(a->arr);
+    }
+}
+
+static inline struct sorted_array
+sorted_array_from_svec(struct svec *v)
+{
+    svec_sort(v);
+    return sorted_array_create((const char **) v->names, v->n, false);
+}
+
+static inline struct sorted_array
+sorted_array_from_sset(struct sset *s)
+{
+    return sorted_array_create(sset_sort(s), sset_count(s), true);
+}
+
+/* DB set columns are already sorted, just wrap them into a sorted array. */
+#define sorted_array_from_dbrec(dbrec, column)           \
+    sorted_array_create((const char **) (dbrec)->column, \
+                        (dbrec)->n_##column, false)
+
+static inline void
+sorted_array_apply_diff(const struct sorted_array *a1,
+                        const struct sorted_array *a2,
+                        void (*apply_callback)(const void *arg,
+                                               const char *item,
+                                               bool add),
+                        const void *arg)
+{
+    size_t idx1, idx2;
+
+    for (idx1 = idx2 = 0; idx1 < a1->n && idx2 < a2->n;) {
+        int cmp = strcmp(a1->arr[idx1], a2->arr[idx2]);
+        if (cmp < 0) {
+            apply_callback(arg, a1->arr[idx1], true);
+            idx1++;
+        } else if (cmp > 0) {
+            apply_callback(arg, a2->arr[idx2], false);
+            idx2++;
+        } else {
+            idx1++;
+            idx2++;
+        }
+    }
+
+    for (; idx1 < a1->n; idx1++) {
+        apply_callback(arg, a1->arr[idx1], true);
+    }
+
+    for (; idx2 < a2->n; idx2++) {
+        apply_callback(arg, a2->arr[idx2], false);
+    }
+}
+
 #endif /* OVN_UTIL_H */
diff --git a/northd/en-sync-sb.c b/northd/en-sync-sb.c
index d7fea981f2..f97771b3b4 100644
--- a/northd/en-sync-sb.c
+++ b/northd/en-sync-sb.c
@@ -33,15 +33,8 @@ 
 
 VLOG_DEFINE_THIS_MODULE(en_sync_to_sb);
 
-/* This is just a type wrapper to enforce that it has to be sorted. */
-struct sorted_addresses {
-    const char **arr;
-    size_t n;
-};
-
-
 static void sync_addr_set(struct ovsdb_idl_txn *ovnsb_txn, const char *name,
-                          struct sorted_addresses *addresses,
+                          struct sorted_array *addresses,
                           struct shash *sb_address_sets);
 static void sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
                            const struct nbrec_address_set_table *,
@@ -50,17 +43,11 @@  static void sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
                            const struct ovn_datapaths *lr_datapaths);
 static const struct sbrec_address_set *sb_address_set_lookup_by_name(
     struct ovsdb_idl_index *, const char *name);
-static void update_sb_addr_set(struct sorted_addresses *,
+static void update_sb_addr_set(struct sorted_array *,
                                const struct sbrec_address_set *);
 static void build_port_group_address_set(const struct nbrec_port_group *,
                                          struct svec *ipv4_addrs,
                                          struct svec *ipv6_addrs);
-static struct sorted_addresses
-sorted_addresses_from_nbrec(const struct nbrec_address_set *nb_as);
-static struct sorted_addresses
-sorted_addresses_from_svec(struct svec *addresses);
-static struct sorted_addresses
-sorted_addresses_from_sset(struct sset *addresses);
 
 void *
 en_sync_to_sb_init(struct engine_node *node OVS_UNUSED,
@@ -145,9 +132,10 @@  sync_to_sb_addr_set_nb_address_set_handler(struct engine_node *node,
         if (!sb_addr_set) {
             return false;
         }
-        struct sorted_addresses addrs =
-                sorted_addresses_from_nbrec(nb_addr_set);
+        struct sorted_array addrs =
+            sorted_array_from_dbrec(nb_addr_set, addresses);
         update_sb_addr_set(&addrs, sb_addr_set);
+        sorted_array_destroy(&addrs);
     }
 
     return true;
@@ -194,18 +182,20 @@  sync_to_sb_addr_set_nb_port_group_handler(struct engine_node *node,
         struct svec ipv6_addrs = SVEC_EMPTY_INITIALIZER;
         build_port_group_address_set(nb_pg, &ipv4_addrs, &ipv6_addrs);
 
-        struct sorted_addresses ipv4_addrs_sorted =
-                sorted_addresses_from_svec(&ipv4_addrs);
-        struct sorted_addresses ipv6_addrs_sorted =
-                sorted_addresses_from_svec(&ipv6_addrs);
+        struct sorted_array ipv4_addrs_sorted =
+                sorted_array_from_svec(&ipv4_addrs);
+        struct sorted_array ipv6_addrs_sorted =
+                sorted_array_from_svec(&ipv6_addrs);
 
         update_sb_addr_set(&ipv4_addrs_sorted, sb_addr_set_v4);
         update_sb_addr_set(&ipv6_addrs_sorted, sb_addr_set_v6);
 
-        free(ipv4_addrs_name);
-        free(ipv6_addrs_name);
+        sorted_array_destroy(&ipv4_addrs_sorted);
+        sorted_array_destroy(&ipv6_addrs_sorted);
         svec_destroy(&ipv4_addrs);
         svec_destroy(&ipv6_addrs);
+        free(ipv4_addrs_name);
+        free(ipv6_addrs_name);
     }
 
     return true;
@@ -214,7 +204,7 @@  sync_to_sb_addr_set_nb_port_group_handler(struct engine_node *node,
 /* static functions. */
 static void
 sync_addr_set(struct ovsdb_idl_txn *ovnsb_txn, const char *name,
-              struct sorted_addresses *addresses,
+              struct sorted_array *addresses,
               struct shash *sb_address_sets)
 {
     const struct sbrec_address_set *sb_address_set;
@@ -261,11 +251,9 @@  sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
 
     /* Service monitor MAC. */
     const char *svc_monitor_macp = northd_get_svc_monitor_mac();
-    struct sorted_addresses svc = {
-            .arr = &svc_monitor_macp,
-            .n = 1,
-    };
+    struct sorted_array svc = sorted_array_create(&svc_monitor_macp, 1, false);
     sync_addr_set(ovnsb_txn, "svc_monitor_mac", &svc, &sb_address_sets);
+    sorted_array_destroy(&svc);
 
     /* sync port group generated address sets first */
     const struct nbrec_port_group *nb_port_group;
@@ -277,19 +265,21 @@  sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
         char *ipv4_addrs_name = xasprintf("%s_ip4", nb_port_group->name);
         char *ipv6_addrs_name = xasprintf("%s_ip6", nb_port_group->name);
 
-        struct sorted_addresses ipv4_addrs_sorted =
-                sorted_addresses_from_svec(&ipv4_addrs);
-        struct sorted_addresses ipv6_addrs_sorted =
-                sorted_addresses_from_svec(&ipv6_addrs);
+        struct sorted_array ipv4_addrs_sorted =
+                sorted_array_from_svec(&ipv4_addrs);
+        struct sorted_array ipv6_addrs_sorted =
+                sorted_array_from_svec(&ipv6_addrs);
 
         sync_addr_set(ovnsb_txn, ipv4_addrs_name,
                       &ipv4_addrs_sorted, &sb_address_sets);
         sync_addr_set(ovnsb_txn, ipv6_addrs_name,
                       &ipv6_addrs_sorted, &sb_address_sets);
-        free(ipv4_addrs_name);
-        free(ipv6_addrs_name);
+        sorted_array_destroy(&ipv4_addrs_sorted);
+        sorted_array_destroy(&ipv6_addrs_sorted);
         svec_destroy(&ipv4_addrs);
         svec_destroy(&ipv6_addrs);
+        free(ipv4_addrs_name);
+        free(ipv6_addrs_name);
     }
 
     /* Sync router load balancer VIP generated address sets. */
@@ -301,24 +291,24 @@  sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
             char *ipv4_addrs_name = lr_lb_address_set_name(od->tunnel_key,
                                                            AF_INET);
 
-            struct sorted_addresses ipv4_addrs_sorted =
-                    sorted_addresses_from_sset(&od->lb_ips->ips_v4_reachable);
+            struct sorted_array ipv4_addrs_sorted =
+                    sorted_array_from_sset(&od->lb_ips->ips_v4_reachable);
 
             sync_addr_set(ovnsb_txn, ipv4_addrs_name,
                           &ipv4_addrs_sorted, &sb_address_sets);
-            free(ipv4_addrs_sorted.arr);
+            sorted_array_destroy(&ipv4_addrs_sorted);
             free(ipv4_addrs_name);
         }
 
         if (sset_count(&od->lb_ips->ips_v6_reachable)) {
             char *ipv6_addrs_name = lr_lb_address_set_name(od->tunnel_key,
                                                            AF_INET6);
-            struct sorted_addresses ipv6_addrs_sorted =
-                    sorted_addresses_from_sset(&od->lb_ips->ips_v6_reachable);
+            struct sorted_array ipv6_addrs_sorted =
+                    sorted_array_from_sset(&od->lb_ips->ips_v6_reachable);
 
             sync_addr_set(ovnsb_txn, ipv6_addrs_name,
                           &ipv6_addrs_sorted, &sb_address_sets);
-            free(ipv6_addrs_sorted.arr);
+            sorted_array_destroy(&ipv6_addrs_sorted);
             free(ipv6_addrs_name);
         }
     }
@@ -328,10 +318,11 @@  sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
     const struct nbrec_address_set *nb_address_set;
     NBREC_ADDRESS_SET_TABLE_FOR_EACH (nb_address_set,
                                       nb_address_set_table) {
-        struct sorted_addresses addrs =
-                sorted_addresses_from_nbrec(nb_address_set);
+        struct sorted_array addrs =
+                sorted_array_from_dbrec(nb_address_set, addresses);
         sync_addr_set(ovnsb_txn, nb_address_set->name,
                       &addrs, &sb_address_sets);
+        sorted_array_destroy(&addrs);
     }
 
     struct shash_node *node;
@@ -343,39 +334,25 @@  sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn,
 }
 
 static void
-update_sb_addr_set(struct sorted_addresses *nb_addresses,
-                   const struct sbrec_address_set *sb_as)
+sb_addr_set_apply_diff(const void *arg, const char *item, bool add)
 {
-    size_t nb_index, sb_index;
-
-    const char **nb_arr = nb_addresses->arr;
-    char **sb_arr = sb_as->addresses;
-    size_t nb_n = nb_addresses->n;
-    size_t sb_n = sb_as->n_addresses;
-
-    for (nb_index = sb_index = 0; nb_index < nb_n && sb_index < sb_n;) {
-        int cmp = strcmp(nb_arr[nb_index], sb_arr[sb_index]);
-        if (cmp < 0) {
-            sbrec_address_set_update_addresses_addvalue(sb_as,
-                                                        nb_arr[nb_index]);
-            nb_index++;
-        } else if (cmp > 0) {
-            sbrec_address_set_update_addresses_delvalue(sb_as,
-                                                        sb_arr[sb_index]);
-            sb_index++;
-        } else {
-            nb_index++;
-            sb_index++;
-        }
-    }
-
-    for (; nb_index < nb_n; nb_index++) {
-        sbrec_address_set_update_addresses_addvalue(sb_as, nb_arr[nb_index]);
+    const struct sbrec_address_set *as = arg;
+    if (add) {
+        sbrec_address_set_update_addresses_addvalue(as, item);
+    } else {
+        sbrec_address_set_update_addresses_delvalue(as, item);
     }
+}
 
-    for (; sb_index < sb_n; sb_index++) {
-        sbrec_address_set_update_addresses_delvalue(sb_as, sb_arr[sb_index]);
-    }
+static void
+update_sb_addr_set(struct sorted_array *nb_addresses,
+                   const struct sbrec_address_set *sb_as)
+{
+    struct sorted_array sb_addresses =
+        sorted_array_from_dbrec(sb_as, addresses);
+    sorted_array_apply_diff(nb_addresses, &sb_addresses,
+                            sb_addr_set_apply_diff, sb_as);
+    sorted_array_destroy(&sb_addresses);
 }
 
 static void
@@ -414,32 +391,3 @@  sb_address_set_lookup_by_name(struct ovsdb_idl_index *sbrec_addr_set_by_name,
 
     return retval;
 }
-
-static struct sorted_addresses
-sorted_addresses_from_nbrec(const struct nbrec_address_set *nb_as)
-{
-    /* The DB is already sorted. */
-    return (struct sorted_addresses) {
-        .arr = (const char **) nb_as->addresses,
-        .n = nb_as->n_addresses,
-    };
-}
-
-static struct sorted_addresses
-sorted_addresses_from_svec(struct svec *addresses)
-{
-    svec_sort(addresses);
-    return (struct sorted_addresses) {
-        .arr = (const char **) addresses->names,
-        .n = addresses->n,
-    };
-}
-
-static struct sorted_addresses
-sorted_addresses_from_sset(struct sset *addresses)
-{
-    return (struct sorted_addresses) {
-        .arr = sset_sort(addresses),
-        .n = sset_count(addresses),
-    };
-}