This patch tracks the added and removed addresses for each updated address sets.
Signed-off-by: Han Zhou <hz...@ovn.org> --- controller/ovn-controller.c | 174 +++++++++++++++++++++--------------- include/ovn/expr.h | 10 ++- lib/expr.c | 133 ++++++++++++++++++++++++--- 3 files changed, 234 insertions(+), 83 deletions(-) diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index e73523ce2..24e09f78f 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -1393,7 +1393,7 @@ struct ed_type_addr_sets { bool change_tracked; struct sset new; struct sset deleted; - struct sset updated; + struct shash updated; }; static void * @@ -1406,19 +1406,44 @@ en_addr_sets_init(struct engine_node *node OVS_UNUSED, as->change_tracked = false; sset_init(&as->new); sset_init(&as->deleted); - sset_init(&as->updated); + shash_init(&as->updated); return as; } +struct addr_set_diff { + struct expr_constant_set *added; + struct expr_constant_set *deleted; +}; + +static void +en_addr_sets_clear_tracked_data(void *data) +{ + struct ed_type_addr_sets *as = data; + sset_clear(&as->new); + sset_clear(&as->deleted); + struct shash_node *node, *next; + SHASH_FOR_EACH_SAFE (node, next, &as->updated) { + struct addr_set_diff *asd = node->data; + expr_constant_set_destroy(asd->added); + free(asd->added); + expr_constant_set_destroy(asd->deleted); + free(asd->deleted); + } + shash_clear_free_data(&as->updated); + as->change_tracked = false; +} + static void en_addr_sets_cleanup(void *data) { + en_addr_sets_clear_tracked_data(data); + struct ed_type_addr_sets *as = data; expr_const_sets_destroy(&as->addr_sets); shash_destroy(&as->addr_sets); sset_destroy(&as->new); sset_destroy(&as->deleted); - sset_destroy(&as->updated); + shash_destroy(&as->updated); } /* Iterate address sets in the southbound database. Create and update the @@ -1437,8 +1462,8 @@ addr_sets_init(const struct sbrec_address_set_table *address_set_table, static void addr_sets_update(const struct sbrec_address_set_table *address_set_table, - struct shash *addr_sets, struct sset *new, - struct sset *deleted, struct sset *updated) + struct shash *addr_sets, struct sset *added, + struct sset *deleted, struct shash *updated) { const struct sbrec_address_set *as; SBREC_ADDRESS_SET_TABLE_FOR_EACH_TRACKED (as, address_set_table) { @@ -1446,13 +1471,23 @@ addr_sets_update(const struct sbrec_address_set_table *address_set_table, expr_const_sets_remove(addr_sets, as->name); sset_add(deleted, as->name); } else { - expr_const_sets_add_integers(addr_sets, as->name, - (const char *const *) as->addresses, - as->n_addresses); - if (sbrec_address_set_is_new(as)) { - sset_add(new, as->name); + struct expr_constant_set *cs_old = shash_find_data(addr_sets, + as->name); + if (!cs_old) { + sset_add(added, as->name); + expr_const_sets_add_integers(addr_sets, as->name, + (const char *const *) as->addresses, as->n_addresses); } else { - sset_add(updated, as->name); + /* Find out the diff for the updated address set. */ + struct expr_constant_set *cs_new = + expr_constant_set_create_integers( + (const char *const *) as->addresses, as->n_addresses); + struct addr_set_diff *as_diff = xmalloc(sizeof *as_diff); + expr_constant_set_integers_diff(cs_old, cs_new, + &as_diff->added, + &as_diff->deleted); + shash_add(updated, as->name, as_diff); + expr_const_sets_add(addr_sets, as->name, cs_new); } } } @@ -1463,9 +1498,6 @@ en_addr_sets_run(struct engine_node *node, void *data) { struct ed_type_addr_sets *as = data; - sset_clear(&as->new); - sset_clear(&as->deleted); - sset_clear(&as->updated); expr_const_sets_destroy(&as->addr_sets); struct sbrec_address_set_table *as_table = @@ -1483,10 +1515,6 @@ addr_sets_sb_address_set_handler(struct engine_node *node, void *data) { struct ed_type_addr_sets *as = data; - sset_clear(&as->new); - sset_clear(&as->deleted); - sset_clear(&as->updated); - struct sbrec_address_set_table *as_table = (struct sbrec_address_set_table *)EN_OVSDB_GET( engine_get_input("SB_address_set", node)); @@ -1495,7 +1523,7 @@ addr_sets_sb_address_set_handler(struct engine_node *node, void *data) &as->deleted, &as->updated); if (!sset_is_empty(&as->new) || !sset_is_empty(&as->deleted) || - !sset_is_empty(&as->updated)) { + !shash_is_empty(&as->updated)) { engine_set_node_state(node, EN_UPDATED); } else { engine_set_node_state(node, EN_UNCHANGED); @@ -2486,15 +2514,11 @@ lflow_output_sb_port_binding_handler(struct engine_node *node, void *data) } static bool -_lflow_output_resource_ref_handler(struct engine_node *node, void *data, - enum ref_type ref_type) +lflow_output_addr_sets_handler(struct engine_node *node, void *data) { struct ed_type_addr_sets *as_data = engine_get_input_data("addr_sets", node); - struct ed_type_port_groups *pg_data = - engine_get_input_data("port_groups", node); - struct ed_type_lflow_output *fo = data; struct lflow_ctx_in l_ctx_in; @@ -2503,42 +2527,13 @@ _lflow_output_resource_ref_handler(struct engine_node *node, void *data, bool changed; const char *ref_name; - struct sset *new, *updated, *deleted; - - switch (ref_type) { - case REF_TYPE_ADDRSET: - /* XXX: The change_tracked check may be added to inc-proc - * framework. */ - if (!as_data->change_tracked) { - return false; - } - new = &as_data->new; - updated = &as_data->updated; - deleted = &as_data->deleted; - break; - case REF_TYPE_PORTGROUP: - if (!pg_data->change_tracked) { - return false; - } - new = &pg_data->new; - updated = &pg_data->updated; - deleted = &pg_data->deleted; - break; - case REF_TYPE_PORTBINDING: - /* This ref type is handled in: - * - flow_output_runtime_data_handler - * - flow_output_sb_port_binding_handler. */ - case REF_TYPE_MC_GROUP: - /* This ref type is handled in the - * flow_output_sb_multicast_group_handler. */ - default: - OVS_NOT_REACHED(); + if (!as_data->change_tracked) { + return false; } - - SSET_FOR_EACH (ref_name, deleted) { - if (!lflow_handle_changed_ref(ref_type, ref_name, &l_ctx_in, + SSET_FOR_EACH (ref_name, &as_data->deleted) { + if (!lflow_handle_changed_ref(REF_TYPE_ADDRSET, ref_name, &l_ctx_in, &l_ctx_out, &changed)) { return false; } @@ -2546,17 +2541,18 @@ _lflow_output_resource_ref_handler(struct engine_node *node, void *data, engine_set_node_state(node, EN_UPDATED); } } - SSET_FOR_EACH (ref_name, updated) { - if (!lflow_handle_changed_ref(ref_type, ref_name, &l_ctx_in, - &l_ctx_out, &changed)) { + struct shash_node *shash_node; + SHASH_FOR_EACH (shash_node, &as_data->updated) { + if (!lflow_handle_changed_ref(REF_TYPE_ADDRSET, shash_node->name, + &l_ctx_in, &l_ctx_out, &changed)) { return false; } if (changed) { engine_set_node_state(node, EN_UPDATED); } } - SSET_FOR_EACH (ref_name, new) { - if (!lflow_handle_changed_ref(ref_type, ref_name, &l_ctx_in, + SSET_FOR_EACH (ref_name, &as_data->new) { + if (!lflow_handle_changed_ref(REF_TYPE_ADDRSET, ref_name, &l_ctx_in, &l_ctx_out, &changed)) { return false; } @@ -2568,16 +2564,54 @@ _lflow_output_resource_ref_handler(struct engine_node *node, void *data, return true; } -static bool -lflow_output_addr_sets_handler(struct engine_node *node, void *data) -{ - return _lflow_output_resource_ref_handler(node, data, REF_TYPE_ADDRSET); -} - static bool lflow_output_port_groups_handler(struct engine_node *node, void *data) { - return _lflow_output_resource_ref_handler(node, data, REF_TYPE_PORTGROUP); + struct ed_type_port_groups *pg_data = + engine_get_input_data("port_groups", node); + + struct ed_type_lflow_output *fo = data; + + struct lflow_ctx_in l_ctx_in; + struct lflow_ctx_out l_ctx_out; + init_lflow_ctx(node, fo, &l_ctx_in, &l_ctx_out); + + bool changed; + const char *ref_name; + + if (!pg_data->change_tracked) { + return false; + } + + SSET_FOR_EACH (ref_name, &pg_data->deleted) { + if (!lflow_handle_changed_ref(REF_TYPE_PORTGROUP, ref_name, &l_ctx_in, + &l_ctx_out, &changed)) { + return false; + } + if (changed) { + engine_set_node_state(node, EN_UPDATED); + } + } + SSET_FOR_EACH (ref_name, &pg_data->updated) { + if (!lflow_handle_changed_ref(REF_TYPE_PORTGROUP, ref_name, &l_ctx_in, + &l_ctx_out, &changed)) { + return false; + } + if (changed) { + engine_set_node_state(node, EN_UPDATED); + } + } + SSET_FOR_EACH (ref_name, &pg_data->new) { + if (!lflow_handle_changed_ref(REF_TYPE_PORTGROUP, ref_name, &l_ctx_in, + &l_ctx_out, &changed)) { + return false; + } + if (changed) { + engine_set_node_state(node, EN_UPDATED); + } + } + + return true; } static bool @@ -3170,7 +3204,7 @@ main(int argc, char *argv[]) ENGINE_NODE(pflow_output, "physical_flow_output"); ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lflow_output, "logical_flow_output"); ENGINE_NODE(flow_output, "flow_output"); - ENGINE_NODE(addr_sets, "addr_sets"); + ENGINE_NODE_WITH_CLEAR_TRACK_DATA(addr_sets, "addr_sets"); ENGINE_NODE_WITH_CLEAR_TRACK_DATA(port_groups, "port_groups"); #define SB_NODE(NAME, NAME_STR) ENGINE_NODE_SB(NAME, NAME_STR); diff --git a/include/ovn/expr.h b/include/ovn/expr.h index 5572a1071..5b232c246 100644 --- a/include/ovn/expr.h +++ b/include/ovn/expr.h @@ -540,6 +540,13 @@ struct expr_constant_set { bool expr_constant_set_parse(struct lexer *, struct expr_constant_set *); void expr_constant_set_format(const struct expr_constant_set *, struct ds *); void expr_constant_set_destroy(struct expr_constant_set *cs); +struct expr_constant_set * expr_constant_set_create_integers( + const char *const *values, size_t n_values); +void expr_constant_set_integers_diff( + struct expr_constant_set *old, + struct expr_constant_set *new, + struct expr_constant_set **p_diff_added, + struct expr_constant_set **p_diff_deleted); /* Constant sets. @@ -553,7 +560,8 @@ void expr_constant_set_destroy(struct expr_constant_set *cs); * integer/masked-integer values. The values that don't qualify * are ignored. */ - +void expr_const_sets_add(struct shash *const_sets, const char *name, + struct expr_constant_set *); void expr_const_sets_add_integers(struct shash *const_sets, const char *name, const char * const *values, size_t n_values); void expr_const_sets_add_strings(struct shash *const_sets, const char *name, diff --git a/lib/expr.c b/lib/expr.c index af083190f..2fdb7e3bb 100644 --- a/lib/expr.c +++ b/lib/expr.c @@ -1084,17 +1084,33 @@ expr_constant_set_destroy(struct expr_constant_set *cs) } } -/* Adds an constant set named 'name' to 'const_sets', replacing any existing - * constant set entry with the given name. The 'values' must be strings that +static int +compare_expr_constant_integer_cb(const void *a_, const void *b_) +{ + const union expr_constant *a = a_; + const union expr_constant *b = b_; + + int d = memcmp(&a->value, &b->value, sizeof a->value); + if (d) { + return d; + } + + if (!a->masked && !b->masked) { + return 0; + } else if (a->masked && !b->masked) { + return -1; + } else if (!a->masked && b->masked) { + return 1; + } + return memcmp(&a->mask, &b->mask, sizeof a->mask); +} + +/* Create an integer type constant set. The 'values' must be strings that * can be converted to integers or masked integers, such as IP addresses. * Values that can't be converted are skipped. */ -void -expr_const_sets_add_integers(struct shash *const_sets, const char *name, - const char *const *values, size_t n_values) +struct expr_constant_set * +expr_constant_set_create_integers(const char *const *values, size_t n_values) { - /* Replace any existing entry for this name. */ - expr_const_sets_remove(const_sets, name); - struct expr_constant_set *cs = xzalloc(sizeof *cs); cs->in_curlies = true; cs->n_values = 0; @@ -1122,9 +1138,105 @@ expr_const_sets_add_integers(struct shash *const_sets, const char *name, lexer_destroy(&lex); } + /* Sort the result, so that it is efficient to generate diffs in the + * function expr_constant_set_diff */ + qsort(cs->values, cs->n_values, sizeof *cs->values, + compare_expr_constant_integer_cb); + + return cs; +} + +static void +expr_constant_set_add_value(struct expr_constant_set **p_cs, + union expr_constant *c, size_t *allocated) +{ + struct expr_constant_set *cs = *p_cs; + if (!cs) { + cs = xzalloc(sizeof *cs); + *p_cs = cs; + } + + if (cs->n_values >= *allocated) { + cs->values = x2nrealloc(cs->values, allocated, + sizeof *cs->values); + } + cs->values[cs->n_values++] = *c; +} + +/* Find the differences between old and new. Both old and new must be integer + * type and must be sorted (which is true if they are generated by + * expr_constant_set_create_integers() or expr_const_sets_add_integers(). + * + * The differences, added and deleted elements, are stored in p_diff_added and + * p_diff_deleted respectively. Caller takes the ownership of these. + * + * *p_diff_added and *p_diff_deleted can be NULL, if no such elements found. */ +void +expr_constant_set_integers_diff(struct expr_constant_set *old, + struct expr_constant_set *new, + struct expr_constant_set **p_diff_added, + struct expr_constant_set **p_diff_deleted) +{ + struct expr_constant_set *diff_added = NULL; + struct expr_constant_set *diff_deleted = NULL; + + size_t oi, ni, added_n_allocated, deleted_n_allocated; + added_n_allocated = deleted_n_allocated = 0; + + for (oi = ni = 0; oi < old->n_values && ni < new->n_values;) { + int d = compare_expr_constant_integer_cb(&old->values[oi], + &new->values[ni]); + if (d < 0) { + expr_constant_set_add_value(&diff_deleted, &old->values[oi], + &deleted_n_allocated); + oi++; + } else if (d > 0) { + expr_constant_set_add_value(&diff_added, &new->values[ni], + &added_n_allocated); + ni++; + } else { + oi++; ni++; + } + } + + for (; oi < old->n_values; oi++) { + expr_constant_set_add_value(&diff_deleted, &old->values[oi], + &deleted_n_allocated); + } + + for (; ni < new->n_values; ni++) { + expr_constant_set_add_value(&diff_added, &new->values[ni], + &added_n_allocated); + } + + *p_diff_added = diff_added; + *p_diff_deleted = diff_deleted; +} + + +/* Adds an constant set named 'name' to 'const_sets', replacing any existing + * constant set entry with the given name. */ +void +expr_const_sets_add(struct shash *const_sets, const char *name, + struct expr_constant_set *cs) +{ + expr_const_sets_remove(const_sets, name); shash_add(const_sets, name, cs); } +/* Adds an constant set named 'name' to 'const_sets', replacing any existing + * constant set entry with the given name. The 'values' must be strings that + * can be converted to integers or masked integers, such as IP addresses. + * Values that can't be converted are skipped. */ +void +expr_const_sets_add_integers(struct shash *const_sets, const char *name, + const char *const *values, size_t n_values) +{ + struct expr_constant_set *cs = expr_constant_set_create_integers(values, + n_values); + expr_const_sets_add(const_sets, name, cs); +} + /* Adds an constant set named 'name' to 'const_sets', replacing any existing * constant set entry with the given name. Unlike expr_const_sets_add_integers, * the 'values' will not be converted but stored as is. @@ -1135,9 +1247,6 @@ expr_const_sets_add_strings(struct shash *const_sets, const char *name, const char *const *values, size_t n_values, const struct sset *filter) { - /* Replace any existing entry for this name. */ - expr_const_sets_remove(const_sets, name); - struct expr_constant_set *cs = xzalloc(sizeof *cs); cs->in_curlies = true; cs->n_values = 0; @@ -1154,7 +1263,7 @@ expr_const_sets_add_strings(struct shash *const_sets, const char *name, c->string = xstrdup(values[i]); } - shash_add(const_sets, name, cs); + expr_const_sets_add(const_sets, name, cs); } void -- 2.30.2 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev