[ovs-dev] [PATCH monitor_cond V7 10/10] RFC OVN: Quick implementation of conditional monitoring

Liran Schour lirans at il.ibm.com
Mon Jun 13 11:19:35 UTC 2016


Conditional monitor of: Port_Binding, Logical_Flow, Multicast_Group
MAC_Binding tables. As a result ovn-controller will be notified only about
records belongs to a datapath that is being served by this hypervisor.

Hack: Ideally, logical datapath ID should be retrieved from Port_Binding table
and by that conditions should be composed only from logical datapath IDs.
In the meantime we first add the logical port to the conditions and on retrieval
of port binding record, we add the logical datapath to the conditions.

Signed-off-by: Liran Schour <lirans at il.ibm.com>
---
 ovn/controller/binding.c        | 108 ++++++++++++++++++++++++++++++++++-
 ovn/controller/binding.h        |   4 +-
 ovn/controller/lport.c          | 123 ++++++++++++++++++++++++++++++++++++++--
 ovn/controller/lport.h          |  10 +++-
 ovn/controller/ovn-controller.c |  23 +++++---
 tests/ovn-controller.at         |   3 +
 6 files changed, 254 insertions(+), 17 deletions(-)

diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c
index a07c327..d8af74c 100644
--- a/ovn/controller/binding.c
+++ b/ovn/controller/binding.c
@@ -21,9 +21,11 @@
 #include "lib/sset.h"
 #include "lib/util.h"
 #include "lib/vswitch-idl.h"
+#include "lib/hash.h"
 #include "openvswitch/vlog.h"
 #include "ovn/lib/ovn-sb-idl.h"
 #include "ovn-controller.h"
+#include "lport.h"
 
 VLOG_DEFINE_THIS_MODULE(binding);
 
@@ -101,10 +103,108 @@ update_qos(const struct ovsrec_interface *iface_rec,
     ovsrec_interface_set_ingress_policing_burst(iface_rec, MAX(0, burst));
 }
 
+static struct sset g_lports = SSET_INITIALIZER(&g_lports);
+
+static void
+update_lports(struct controller_ctx *ctx,
+              struct sset *tmp_lports,
+              const struct lport_index *lports)
+{
+    const char **lports_array, **tmp_lports_array;
+    struct sset_node *node;
+    int i, j;
+
+    lports_array = sset_sort(&g_lports);
+    tmp_lports_array = sset_sort(tmp_lports);
+    for (i = 0, j = 0; lports_array[i] && tmp_lports_array[j];) {
+        int cmp = strcmp(lports_array[i], tmp_lports_array[j]);
+        if (!cmp) {
+            i++;
+            j++;
+        } else if (cmp < 0) {
+            node = sset_find(&g_lports, lports_array[i]);
+            if (node) {
+                VLOG_INFO("Remove port %s from condition", lports_array[i]);
+                sbrec_port_binding_remove_clause_logical_port(ctx->ovnsb_idl,
+                                                              OVSDB_F_EQ,
+                                                              lports_array[i]);
+                sbrec_port_binding_remove_clause_parent_port(ctx->ovnsb_idl,
+                                                             OVSDB_F_EQ,
+                                                             lports_array[i]);
+                sset_delete(&g_lports, node);
+            }
+            i++;
+        } else if (cmp > 0) {
+            if (!lport_lookup_by_name(lports, tmp_lports_array[j])) {
+                VLOG_INFO("Add port %s", tmp_lports_array[j]);
+                sbrec_port_binding_add_clause_logical_port(ctx->ovnsb_idl,
+                                                           OVSDB_F_EQ,
+                                                           tmp_lports_array[j]);
+                sbrec_port_binding_add_clause_parent_port(ctx->ovnsb_idl,
+                                                          OVSDB_F_EQ,
+                                                          tmp_lports_array[j]);
+                sset_add(&g_lports, tmp_lports_array[j]);
+            }
+            j++;
+        }
+    }
+    for (; lports_array[i]; i++) {
+        node = sset_find(&g_lports, lports_array[i]);
+        if (node) {
+            VLOG_INFO("Remove port %s from condition", lports_array[i]);
+            sbrec_port_binding_remove_clause_logical_port(ctx->ovnsb_idl,
+                                                          OVSDB_F_EQ,
+                                                          lports_array[i]);
+            sbrec_port_binding_remove_clause_parent_port(ctx->ovnsb_idl,
+                                                         OVSDB_F_EQ,
+                                                         lports_array[i]);
+            sset_delete(&g_lports, node);
+        }
+    }
+    for (; tmp_lports_array[j]; j++) {
+        if (!lport_lookup_by_name(lports, tmp_lports_array[j])) {
+            VLOG_INFO("Add port %s", tmp_lports_array[j]);
+            sbrec_port_binding_add_clause_logical_port(ctx->ovnsb_idl,
+                                                       OVSDB_F_EQ,
+                                                       tmp_lports_array[j]);
+            sbrec_port_binding_add_clause_parent_port(ctx->ovnsb_idl,
+                                                      OVSDB_F_EQ,
+                                                      tmp_lports_array[j]);
+            sset_add(&g_lports, tmp_lports_array[j]);
+        }
+    }
+
+    free(lports_array);
+    free(tmp_lports_array);
+
+    return;
+}
+
+static struct sset g_peer_lports = SSET_INITIALIZER(&g_peer_lports);
+
+static void
+add_peer_port(struct controller_ctx *ctx, const char *lport)
+{
+    if (!sset_contains(&g_peer_lports, lport)) {
+        sset_add(&g_peer_lports, lport);
+        VLOG_INFO("Add peer %s", lport);
+        sbrec_port_binding_add_clause_logical_port(ctx->ovnsb_idl,
+                                                   OVSDB_F_EQ,
+                                                   lport);
+        sbrec_port_binding_add_clause_parent_port(ctx->ovnsb_idl,
+                                                  OVSDB_F_EQ,
+                                                  lport);
+        sbrec_mac_binding_add_clause_logical_port(ctx->ovnsb_idl,
+                                                  OVSDB_F_EQ,
+                                                  lport);
+    }
+}
+
 void
 binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,
             const char *chassis_id, struct sset *all_lports,
-            struct hmap *local_datapaths)
+            struct hmap *local_datapaths,
+            const struct lport_index *lport_indexes)
 {
     const struct sbrec_chassis *chassis_rec;
     const struct sbrec_port_binding *binding_rec;
@@ -124,10 +224,16 @@ binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,
         sset_add(all_lports, node->name);
     }
 
+    update_lports(ctx, all_lports, lport_indexes);
+
     /* Run through each binding record to see if it is resident on this
      * chassis and update the binding accordingly.  This includes both
      * directly connected logical ports and children of those ports. */
     SBREC_PORT_BINDING_FOR_EACH(binding_rec, ctx->ovnsb_idl) {
+        const char *peer = smap_get(&binding_rec->options, "peer");
+        if (peer) {
+            add_peer_port(ctx, peer);
+        }
         const struct ovsrec_interface *iface_rec
             = shash_find_and_delete(&lports, binding_rec->logical_port);
         if (iface_rec
diff --git a/ovn/controller/binding.h b/ovn/controller/binding.h
index 25f8989..dbe41c4 100644
--- a/ovn/controller/binding.h
+++ b/ovn/controller/binding.h
@@ -25,11 +25,13 @@ struct ovsdb_idl;
 struct ovsrec_bridge;
 struct simap;
 struct sset;
+struct lport_index;
 
 void binding_register_ovs_idl(struct ovsdb_idl *);
 void binding_run(struct controller_ctx *, const struct ovsrec_bridge *br_int,
                  const char *chassis_id, struct sset *all_lports,
-                 struct hmap *local_datapaths);
+                 struct hmap *local_datapaths,
+                 const struct lport_index *lport_indexes);
 bool binding_cleanup(struct controller_ctx *, const char *chassis_id);
 
 #endif /* ovn/binding.h */
diff --git a/ovn/controller/lport.c b/ovn/controller/lport.c
index a7ae320..5a0c597 100644
--- a/ovn/controller/lport.c
+++ b/ovn/controller/lport.c
@@ -19,6 +19,7 @@
 #include "hash.h"
 #include "openvswitch/vlog.h"
 #include "ovn/lib/ovn-sb-idl.h"
+#include "ovn-controller.h"
 
 VLOG_DEFINE_THIS_MODULE(lport);
 
@@ -29,12 +30,122 @@ struct lport {
     const struct sbrec_port_binding *pb;
 };
 
+/* Logical datapath that has been added to conditions */
+struct logical_datapath {
+    struct hmap_node hmap_node; /* Indexed on 'uuid'. */
+    struct uuid uuid;           /* UUID from Datapath_Binding row. */
+    uint32_t tunnel_key;        /* 'tunnel_key' from Datapath_Binding row. */
+    size_t n_ports;
+};
+
+/* Contains "struct logical_datapath"s. */
+static struct hmap logical_datapaths = HMAP_INITIALIZER(&logical_datapaths);
+
+/* Finds and returns the logical_datapath for 'binding', or NULL if no such
+ * logical_datapath exists. */
+static struct logical_datapath *
+ldp_lookup(const struct sbrec_datapath_binding *binding)
+{
+    struct logical_datapath *ldp;
+    HMAP_FOR_EACH_IN_BUCKET (ldp, hmap_node, uuid_hash(&binding->header_.uuid),
+                             &logical_datapaths) {
+        if (uuid_equals(&ldp->uuid, &binding->header_.uuid)) {
+            return ldp;
+        }
+    }
+    return NULL;
+}
+
+/* Creates a new logical_datapath for the given 'binding'. */
+static struct logical_datapath *
+ldp_create(const struct sbrec_datapath_binding *binding)
+{
+    struct logical_datapath *ldp;
+
+    ldp = xmalloc(sizeof *ldp);
+    hmap_insert(&logical_datapaths, &ldp->hmap_node,
+                uuid_hash(&binding->header_.uuid));
+    ldp->uuid = binding->header_.uuid;
+    ldp->tunnel_key = binding->tunnel_key;
+    ldp->n_ports = 0;
+    return ldp;
+}
+
+static struct logical_datapath *
+ldp_lookup_or_create(struct controller_ctx *ctx,
+                     const struct sbrec_datapath_binding *binding)
+{
+    struct logical_datapath *ldp = ldp_lookup(binding);
+
+    if (!ldp) {
+        ldp = ldp_create(binding);
+        VLOG_INFO("add logical datapath "UUID_FMT, UUID_ARGS(&ldp->uuid));
+        sbrec_port_binding_add_clause_datapath(ctx->ovnsb_idl,
+                                               OVSDB_F_EQ,
+                                               binding);
+        sbrec_logical_flow_add_clause_logical_datapath(
+                                               ctx->ovnsb_idl,
+                                               OVSDB_F_EQ,
+                                               binding);
+        sbrec_multicast_group_add_clause_datapath(
+                                               ctx->ovnsb_idl,
+                                               OVSDB_F_EQ,
+                                               binding);
+    }
+    ldp->n_ports++;
+    return ldp;
+}
+
+static void
+ldp_free(struct logical_datapath *ldp)
+{
+    hmap_remove(&logical_datapaths, &ldp->hmap_node);
+    free(ldp);
+}
+
+static void
+ldp_clear_n_ports(void)
+{
+    struct logical_datapath *ldp;
+    HMAP_FOR_EACH (ldp, hmap_node, &logical_datapaths) {
+        ldp->n_ports = 0;
+    }
+}
+
+static void
+ldp_remove_unused(struct controller_ctx *ctx)
+{
+    struct logical_datapath *ldp, *next_ldp;;
+
+    HMAP_FOR_EACH_SAFE (ldp, next_ldp, hmap_node, &logical_datapaths) {
+        if (ldp->n_ports == 0) {
+            const struct sbrec_datapath_binding *datapath =
+                sbrec_datapath_binding_get_for_uuid(ctx->ovnsb_idl, &ldp->uuid);
+            if (datapath) {
+                VLOG_INFO("Remove logical datapath "UUID_FMT, UUID_ARGS(&ldp->uuid));
+                sbrec_port_binding_remove_clause_datapath(ctx->ovnsb_idl,
+                                                          OVSDB_F_EQ,
+                                                          datapath);
+                sbrec_logical_flow_remove_clause_logical_datapath(ctx->ovnsb_idl,
+                                                                  OVSDB_F_EQ,
+                                                                  datapath);
+                sbrec_multicast_group_remove_clause_datapath(ctx->ovnsb_idl,
+                                                             OVSDB_F_EQ,
+                                                             datapath);
+            }
+            ldp_free(ldp);
+        }
+    }
+}
+
 void
-lport_index_init(struct lport_index *lports, struct ovsdb_idl *ovnsb_idl)
+lport_index_init(struct controller_ctx *ctx,
+                 struct lport_index *lports, struct ovsdb_idl *ovnsb_idl)
 {
     hmap_init(&lports->by_name);
     hmap_init(&lports->by_key);
 
+    ldp_clear_n_ports();
     const struct sbrec_port_binding *pb;
     SBREC_PORT_BINDING_FOR_EACH (pb, ovnsb_idl) {
         if (lport_lookup_by_name(lports, pb->logical_port)) {
@@ -43,18 +154,19 @@ lport_index_init(struct lport_index *lports, struct ovsdb_idl *ovnsb_idl)
                          pb->logical_port);
             continue;
         }
-
         struct lport *p = xmalloc(sizeof *p);
         hmap_insert(&lports->by_name, &p->name_node,
                     hash_string(pb->logical_port, 0));
         hmap_insert(&lports->by_key, &p->key_node,
                     hash_int(pb->tunnel_key, pb->datapath->tunnel_key));
         p->pb = pb;
+        ldp_lookup_or_create(ctx, pb->datapath);
     }
 }
 
 void
-lport_index_destroy(struct lport_index *lports)
+lport_index_destroy(struct controller_ctx *ctx,
+                    struct lport_index *lports)
 {
     /* Destroy all of the "struct lport"s.
      *
@@ -66,6 +178,7 @@ lport_index_destroy(struct lport_index *lports)
 
     hmap_destroy(&lports->by_name);
     hmap_destroy(&lports->by_key);
+    ldp_remove_unused(ctx);
 }
 
 /* Finds and returns the lport with the given 'name', or NULL if no such lport
@@ -104,7 +217,8 @@ struct mcgroup {
 };
 
 void
-mcgroup_index_init(struct mcgroup_index *mcgroups, struct ovsdb_idl *ovnsb_idl)
+mcgroup_index_init(struct controller_ctx *ctx,
+                   struct mcgroup_index *mcgroups, struct ovsdb_idl *ovnsb_idl)
 {
     hmap_init(&mcgroups->by_dp_name);
 
@@ -122,6 +236,7 @@ mcgroup_index_init(struct mcgroup_index *mcgroups, struct ovsdb_idl *ovnsb_idl)
         hmap_insert(&mcgroups->by_dp_name, &m->dp_name_node,
                     hash_string(mg->name, uuid_hash(dp_uuid)));
         m->mg = mg;
+        ldp_lookup_or_create(ctx, mg->datapath);
     }
 }
 
diff --git a/ovn/controller/lport.h b/ovn/controller/lport.h
index f09e2eb..f8f3e50 100644
--- a/ovn/controller/lport.h
+++ b/ovn/controller/lport.h
@@ -21,6 +21,7 @@
 
 struct ovsdb_idl;
 struct sbrec_datapath_binding;
+struct controller_ctx;
 
 /* Logical port and multicast group indexes
  * ========================================
@@ -34,8 +35,10 @@ struct lport_index {
     struct hmap by_key;
 };
 
-void lport_index_init(struct lport_index *, struct ovsdb_idl *);
-void lport_index_destroy(struct lport_index *);
+void lport_index_init(struct controller_ctx *ctx,
+                      struct lport_index *, struct ovsdb_idl *);
+void lport_index_destroy(struct controller_ctx *ctx,
+                         struct lport_index *);
 
 const struct sbrec_port_binding *lport_lookup_by_name(
     const struct lport_index *, const char *name);
@@ -56,7 +59,8 @@ struct mcgroup_index {
     struct hmap by_dp_name;
 };
 
-void mcgroup_index_init(struct mcgroup_index *, struct ovsdb_idl *);
+void mcgroup_index_init(struct controller_ctx *ctx,
+                        struct mcgroup_index *, struct ovsdb_idl *);
 void mcgroup_index_destroy(struct mcgroup_index *);
 
 const struct sbrec_multicast_group *mcgroup_lookup_by_dp_name(
diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c
index 356a94b..6780d90 100644
--- a/ovn/controller/ovn-controller.c
+++ b/ovn/controller/ovn-controller.c
@@ -383,6 +383,13 @@ main(int argc, char *argv[])
     char *ovnsb_remote = get_ovnsb_remote(ovs_idl_loop.idl);
     struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
         ovsdb_idl_create(ovnsb_remote, &sbrec_idl_class, true, true));
+
+    /* Start with false condition. */
+    sbrec_port_binding_add_clause_false(ovnsb_idl_loop.idl);
+    sbrec_logical_flow_add_clause_false(ovnsb_idl_loop.idl);
+    sbrec_multicast_group_add_clause_false(ovnsb_idl_loop.idl);
+    sbrec_mac_binding_add_clause_false(ovnsb_idl_loop.idl);
+
     ovsdb_idl_get_initial_snapshot(ovnsb_idl_loop.idl);
 
     int probe_interval = 0;
@@ -427,23 +434,22 @@ main(int argc, char *argv[])
 
         const struct ovsrec_bridge *br_int = get_br_int(&ctx);
         const char *chassis_id = get_chassis_id(ctx.ovs_idl);
+        struct lport_index lports;
+        struct mcgroup_index mcgroups;
+        lport_index_init(&ctx, &lports, ctx.ovnsb_idl);
+        mcgroup_index_init(&ctx, &mcgroups, ctx.ovnsb_idl);
 
         if (chassis_id) {
             chassis_run(&ctx, chassis_id);
             encaps_run(&ctx, br_int, chassis_id);
             binding_run(&ctx, br_int, chassis_id, &all_lports,
-                        &local_datapaths);
+                        &local_datapaths, &lports);
         }
 
         if (br_int && chassis_id) {
             patch_run(&ctx, br_int, chassis_id, &local_datapaths,
                       &patched_datapaths);
 
-            struct lport_index lports;
-            struct mcgroup_index mcgroups;
-            lport_index_init(&lports, ctx.ovnsb_idl);
-            mcgroup_index_init(&mcgroups, ctx.ovnsb_idl);
-
             enum mf_field_id mff_ovn_geneve = ofctrl_run(br_int);
 
             pinctrl_run(&ctx, &lports, br_int, chassis_id, &local_datapaths);
@@ -460,9 +466,9 @@ main(int argc, char *argv[])
             }
             ofctrl_put(&flow_table);
             hmap_destroy(&flow_table);
-            mcgroup_index_destroy(&mcgroups);
-            lport_index_destroy(&lports);
         }
+        mcgroup_index_destroy(&mcgroups);
+        lport_index_destroy(&ctx, &lports);
 
         sset_destroy(&all_lports);
 
@@ -494,6 +500,7 @@ main(int argc, char *argv[])
         }
         ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);
         ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop);
+
         poll_block();
         if (should_service_stop()) {
             exiting = true;
diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at
index d6daa24..c60d530 100644
--- a/tests/ovn-controller.at
+++ b/tests/ovn-controller.at
@@ -92,11 +92,14 @@ AT_CHECK([ovn-sbctl \
     -- --id=@dp2 create Datapath_Binding tunnel_key=2 \
     -- create Port_Binding datapath=@dp1 logical_port=foo tunnel_key=1 type=patch options:peer=bar \
     -- create Port_Binding datapath=@dp2 logical_port=bar tunnel_key=2 type=patch options:peer=foo \
+    -- create Port_Binding datapath=@dp1 logical_port=localvif3 tunnel_key=3 \
 | ${PERL} $srcdir/uuidfilt.pl], [0], [<0>
 <1>
 <2>
 <3>
+<4>
 ])
+ovs-vsctl add-port br-int localvif3 -- set Interface localvif3 external_ids:iface-id=localvif3
 check_patches \
     'br-int  patch-br-int-to-localnet2 patch-localnet2-to-br-int' \
     'br-eth0 patch-localnet2-to-br-int patch-br-int-to-localnet2' \
-- 
2.1.4




More information about the dev mailing list