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

Reply via email to