On Wed, May 24, 2023 at 11:27 PM Ales Musil <amu...@redhat.com> wrote: > > The incremental processing is broken for addresses > that have mask which could "erase" portion of the address > itself e.g. 10.16.0.47/4, after applying the mask with token > parser the address becomes 0.0.0.0/4, which is fine for > logical flows. However, for the deletion/addition to database > we need the original string representation which cannot be > built from the parsed token. > > Use strcmp over already sorted lists which should give > us the needed diff. The time complexity didn't change, > but the performance was slightly improved, see the numbers > below. The setup was created by the scale script from Han [0]. > > Numbers with expr: > Time spent on processing nb_cfg 1: > ovn-northd delay before processing: 21ms > ovn-northd completion: 544ms > ovn-controller(s) completion: 544ms > Time spent on processing nb_cfg 2: > ovn-northd delay before processing: 17ms > ovn-northd completion: 537ms > ovn-controller(s) completion: 535ms > Time spent on processing nb_cfg 3: > ovn-northd delay before processing: 20ms > ovn-northd completion: 552ms > ovn-controller(s) completion: 550ms > Time spent on processing nb_cfg 4: > ovn-northd delay before processing: 16ms > ovn-northd completion: 529ms > ovn-controller(s) completion: 528ms > > Numbers with the strcmp: > Time spent on processing nb_cfg 1: > ovn-northd delay before processing: 24ms > ovn-northd completion: 521ms > ovn-controller(s) completion: 521ms > Time spent on processing nb_cfg 2: > ovn-northd delay before processing: 17ms > ovn-northd completion: 500ms > ovn-controller(s) completion: 500ms > Time spent on processing nb_cfg 3: > ovn-northd delay before processing: 17ms > ovn-northd completion: 496ms > ovn-controller(s) completion: 497ms > Time spent on processing nb_cfg 4: > ovn-northd delay before processing: 18ms > ovn-northd completion: 502ms > ovn-controller(s) completion: 500ms > > [0] https://github.com/hzhou8/ovn-test-script/blob/e1149318201309db6d96ae8d5a33fcfbbe1872a3/test_ov
n_controller_scale.sh > > Fixes: 0d5e0a6ced49 ("northd: Add I-P for syncing SB address sets.") > Reported-at: https://bugzilla.redhat.com/2196885 > Reported-at: https://mail.openvswitch.org/pipermail/ovs-discuss/2023-May/052426.html > Reported-By: 张祖建 <zhangzujia...@gmail.com> > Signed-off-by: Ales Musil <amu...@redhat.com> > --- > v2: Address comments from Ilya: > Use "custom" algorithm to prevent a ton of allocations with svec. > Add original reporter. > --- > northd/en-sync-sb.c | 183 +++++++++++++++++++++++++++----------------- > 1 file changed, 112 insertions(+), 71 deletions(-) > > diff --git a/northd/en-sync-sb.c b/northd/en-sync-sb.c > index 758f00bfd..87402d6fb 100644 > --- a/northd/en-sync-sb.c > +++ b/northd/en-sync-sb.c > @@ -22,7 +22,6 @@ > #include "openvswitch/util.h" > > #include "en-sync-sb.h" > -#include "include/ovn/expr.h" > #include "lib/inc-proc-eng.h" > #include "lib/lb.h" > #include "lib/ovn-nb-idl.h" > @@ -34,8 +33,15 @@ > > 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, > - const char **addrs, size_t n_addrs, > + struct sorted_addresses *addresses, > struct shash *sb_address_sets); > static void sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, > const struct nbrec_address_set_table *, > @@ -44,11 +50,17 @@ 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(const char **nb_addresses, size_t n_addresses, > +static void update_sb_addr_set(struct sorted_addresses *, > 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, > @@ -133,8 +145,9 @@ sync_to_sb_addr_set_nb_address_set_handler(struct engine_node *node, > if (!sb_addr_set) { > return false; > } > - update_sb_addr_set((const char **) nb_addr_set->addresses, > - nb_addr_set->n_addresses, sb_addr_set); > + struct sorted_addresses addrs = > + sorted_addresses_from_nbrec(nb_addr_set); > + update_sb_addr_set(&addrs, sb_addr_set); > } > > return true; > @@ -180,10 +193,14 @@ sync_to_sb_addr_set_nb_port_group_handler(struct engine_node *node, > struct svec ipv4_addrs = SVEC_EMPTY_INITIALIZER; > struct svec ipv6_addrs = SVEC_EMPTY_INITIALIZER; > build_port_group_address_set(nb_pg, &ipv4_addrs, &ipv6_addrs); > - update_sb_addr_set((const char **) ipv4_addrs.names, ipv4_addrs.n, > - sb_addr_set_v4); > - update_sb_addr_set((const char **) ipv6_addrs.names, ipv6_addrs.n, > - sb_addr_set_v6); > + > + struct sorted_addresses ipv4_addrs_sorted = > + sorted_addresses_from_svec(&ipv4_addrs); > + struct sorted_addresses ipv6_addrs_sorted = > + sorted_addresses_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); > @@ -197,7 +214,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, > - const char **addrs, size_t n_addrs, > + struct sorted_addresses *addresses, > struct shash *sb_address_sets) > { > const struct sbrec_address_set *sb_address_set; > @@ -206,10 +223,10 @@ sync_addr_set(struct ovsdb_idl_txn *ovnsb_txn, const char *name, > if (!sb_address_set) { > sb_address_set = sbrec_address_set_insert(ovnsb_txn); > sbrec_address_set_set_name(sb_address_set, name); > - sbrec_address_set_set_addresses(sb_address_set, > - addrs, n_addrs); > + sbrec_address_set_set_addresses(sb_address_set, addresses->arr, > + addresses->n); > } else { > - update_sb_addr_set(addrs, n_addrs, sb_address_set); > + update_sb_addr_set(addresses, sb_address_set); > } > } > > @@ -244,8 +261,11 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, > > /* Service monitor MAC. */ > const char *svc_monitor_macp = northd_get_svc_monitor_mac(); > - sync_addr_set(ovnsb_txn, "svc_monitor_mac", &svc_monitor_macp, 1, > - &sb_address_sets); > + struct sorted_addresses svc = { > + .arr = &svc_monitor_macp, > + .n = 1, > + }; > + sync_addr_set(ovnsb_txn, "svc_monitor_mac", &svc, &sb_address_sets); > > /* sync port group generated address sets first */ > const struct nbrec_port_group *nb_port_group; > @@ -256,14 +276,16 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, > build_port_group_address_set(nb_port_group, &ipv4_addrs, &ipv6_addrs); > 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); > + > sync_addr_set(ovnsb_txn, ipv4_addrs_name, > - /* "char **" is not compatible with "const char **" */ > - (const char **) ipv4_addrs.names, > - ipv4_addrs.n, &sb_address_sets); > + &ipv4_addrs_sorted, &sb_address_sets); > sync_addr_set(ovnsb_txn, ipv6_addrs_name, > - /* "char **" is not compatible with "const char **" */ > - (const char **) ipv6_addrs.names, > - ipv6_addrs.n, &sb_address_sets); > + &ipv6_addrs_sorted, &sb_address_sets); > free(ipv4_addrs_name); > free(ipv6_addrs_name); > svec_destroy(&ipv4_addrs); > @@ -278,27 +300,26 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, > if (sset_count(&od->lb_ips->ips_v4_reachable)) { > char *ipv4_addrs_name = lr_lb_address_set_name(od->tunnel_key, > AF_INET); > - const char **ipv4_addrs = > - sset_array(&od->lb_ips->ips_v4_reachable); > > - sync_addr_set(ovnsb_txn, ipv4_addrs_name, ipv4_addrs, > - sset_count(&od->lb_ips->ips_v4_reachable), > - &sb_address_sets); > + struct sorted_addresses ipv4_addrs_sorted = > + sorted_addresses_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); > free(ipv4_addrs_name); > - free(ipv4_addrs); > } > > if (sset_count(&od->lb_ips->ips_v6_reachable)) { > char *ipv6_addrs_name = lr_lb_address_set_name(od->tunnel_key, > AF_INET6); > - const char **ipv6_addrs = > - sset_array(&od->lb_ips->ips_v6_reachable); > + struct sorted_addresses ipv6_addrs_sorted = > + sorted_addresses_from_sset(&od->lb_ips->ips_v6_reachable); > > - sync_addr_set(ovnsb_txn, ipv6_addrs_name, ipv6_addrs, > - sset_count(&od->lb_ips->ips_v6_reachable), > - &sb_address_sets); > + sync_addr_set(ovnsb_txn, ipv6_addrs_name, > + &ipv6_addrs_sorted, &sb_address_sets); > + free(ipv6_addrs_sorted.arr); > free(ipv6_addrs_name); > - free(ipv6_addrs); > } > } > > @@ -307,10 +328,10 @@ 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); > sync_addr_set(ovnsb_txn, nb_address_set->name, > - /* "char **" is not compatible with "const char **" */ > - (const char **) nb_address_set->addresses, > - nb_address_set->n_addresses, &sb_address_sets); > + &addrs, &sb_address_sets); > } > > struct shash_node *node; > @@ -322,48 +343,39 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, > } > > static void > -update_sb_addr_set(const char **nb_addresses, size_t n_addresses, > +update_sb_addr_set(struct sorted_addresses *nb_addresses, > const struct sbrec_address_set *sb_as) > { > - struct expr_constant_set *cs_nb_as = > - expr_constant_set_create_integers( > - (const char *const *) nb_addresses, n_addresses); > - struct expr_constant_set *cs_sb_as = > - expr_constant_set_create_integers( > - (const char *const *) sb_as->addresses, sb_as->n_addresses); > - > - struct expr_constant_set *addr_added = NULL; > - struct expr_constant_set *addr_deleted = NULL; > - expr_constant_set_integers_diff(cs_sb_as, cs_nb_as, &addr_added, > - &addr_deleted); > - > - struct ds ds = DS_EMPTY_INITIALIZER; > - if (addr_added && addr_added->n_values) { > - for (size_t i = 0; i < addr_added->n_values; i++) { > - ds_clear(&ds); > - expr_constant_format(&addr_added->values[i], EXPR_C_INTEGER, &ds); > - sbrec_address_set_update_addresses_addvalue(sb_as, ds_cstr(&ds)); > + 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++; > } > } > > - if (addr_deleted && addr_deleted->n_values) { > - for (size_t i = 0; i < addr_deleted->n_values; i++) { > - ds_clear(&ds); > - expr_constant_format(&addr_deleted->values[i], > - EXPR_C_INTEGER, &ds); > - sbrec_address_set_update_addresses_delvalue(sb_as, ds_cstr(&ds)); > - } > + for (; nb_index < nb_n; nb_index++) { > + sbrec_address_set_update_addresses_addvalue(sb_as, nb_arr[nb_index]); > } > > - ds_destroy(&ds); > - expr_constant_set_destroy(cs_nb_as); > - free(cs_nb_as); > - expr_constant_set_destroy(cs_sb_as); > - free(cs_sb_as); > - expr_constant_set_destroy(addr_added); > - free(addr_added); > - expr_constant_set_destroy(addr_deleted); > - free(addr_deleted); > + for (; sb_index < sb_n; sb_index++) { > + sbrec_address_set_update_addresses_delvalue(sb_as, sb_arr[sb_index]); > + } > } > > static void > @@ -402,3 +414,32 @@ 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), > + }; > +} > -- > 2.40.1 > > _______________________________________________ > dev mailing list > d...@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev Thanks Ales for the fix and sorry for not being able to review v1 sooner. This fix is straightforward, but I have a different suggestion. In my opinion normalizing the addresses before writing to SB has important advantages. For example, we can avoid invalid address strings or duplicated addresses, which can make ovn-controller implementation more clean. In general, northd is a good place to cleanup dirty data before writing to SB when the cost is manageable. So, would it be better to keep the update_sb_addr_set() implementation but modify the sync_addr_set() so that it always write normalized addresses to SB, to be consistent with update_sb_addr_set()? Regards, Han _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev