diff mbox

[ovs-dev,monitor_cond,V8,11/11] RFC OVN: Implementation of conditional monitoring usage

Message ID 1467034384-21298-12-git-send-email-lirans@il.ibm.com
State Superseded
Headers show

Commit Message

Liran Schour June 27, 2016, 1:33 p.m. UTC
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.

Evaluation on simulated environment of 50 hosts and 1000 logical ports shows
the following results (cycles #):

LN spread over # hosts|    master    | patch        | change
-------------------------------------------------------------
            1         | 58855158082  | 38175941755  | 35.1%
            3         | 54816462604  | 40255584120  | 26.5%
            6         | 52972265506  | 39481653891  | 25.4%
           12         | 57036827284  | 42008285519  | 26.3%
           18         | 61900476558  | 45903107035  | 25.8%
           24         | 64281399690  | 55617752599  | 13.4%
           30         | 66905128558  | 61835913623  |  7.5%
           42         | 76763742331  | 70522724721  |  8.1%
           50         | 85372146321  | 80130285454  |  6.1%
---
 ovn/controller/automake.mk      |   4 +-
 ovn/controller/binding.c        |  27 +++++--
 ovn/controller/binding.h        |   2 +
 ovn/controller/filter.c         | 165 ++++++++++++++++++++++++++++++++++++++++
 ovn/controller/filter.h         |  30 ++++++++
 ovn/controller/ovn-controller.c |  23 ++++--
 ovn/controller/ovn-controller.h |   1 +
 ovn/controller/patch.c          |   7 +-
 tests/ovn-controller.at         |   3 +
 9 files changed, 246 insertions(+), 16 deletions(-)
 create mode 100644 ovn/controller/filter.c
 create mode 100644 ovn/controller/filter.h
diff mbox

Patch

diff --git a/ovn/controller/automake.mk b/ovn/controller/automake.mk
index cf57bbd..0318654 100644
--- a/ovn/controller/automake.mk
+++ b/ovn/controller/automake.mk
@@ -19,7 +19,9 @@  ovn_controller_ovn_controller_SOURCES = \
 	ovn/controller/ovn-controller.c \
 	ovn/controller/ovn-controller.h \
 	ovn/controller/physical.c \
-	ovn/controller/physical.h
+	ovn/controller/physical.h \
+	ovn/controller/filter.c \
+	ovn/controller/filter.h
 ovn_controller_ovn_controller_LDADD = ovn/lib/libovn.la lib/libopenvswitch.la
 man_MANS += ovn/controller/ovn-controller.8
 EXTRA_DIST += ovn/controller/ovn-controller.8.xml
diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c
index a07c327..7913809 100644
--- a/ovn/controller/binding.c
+++ b/ovn/controller/binding.c
@@ -24,6 +24,10 @@ 
 #include "openvswitch/vlog.h"
 #include "ovn/lib/ovn-sb-idl.h"
 #include "ovn-controller.h"
+#include "lport.h"
+#include "filter.h"
+#include "poll-loop.h"
+#include "timeval.h"
 
 VLOG_DEFINE_THIS_MODULE(binding);
 
@@ -50,7 +54,9 @@  binding_register_ovs_idl(struct ovsdb_idl *ovs_idl)
 }
 
 static void
-get_local_iface_ids(const struct ovsrec_bridge *br_int, struct shash *lports)
+get_local_iface_ids(const struct ovsrec_bridge *br_int, struct shash *lports,
+                    struct lport_index *lports_index,
+                    struct controller_ctx *ctx)
 {
     int i;
 
@@ -72,13 +78,17 @@  get_local_iface_ids(const struct ovsrec_bridge *br_int, struct shash *lports)
                 continue;
             }
             shash_add(lports, iface_id, iface_rec);
+            if (!lport_lookup_by_name(lports_index, iface_id)) {
+                filter_lport(ctx, iface_id);
+            }
         }
     }
 }
 
 static void
 add_local_datapath(struct hmap *local_datapaths,
-        const struct sbrec_port_binding *binding_rec)
+                   const struct sbrec_port_binding *binding_rec,
+                   struct controller_ctx *ctx)
 {
     if (get_local_datapath(local_datapaths,
                            binding_rec->datapath->tunnel_key)) {
@@ -88,6 +98,7 @@  add_local_datapath(struct hmap *local_datapaths,
     struct local_datapath *ld = xzalloc(sizeof *ld);
     hmap_insert(local_datapaths, &ld->hmap_node,
                 binding_rec->datapath->tunnel_key);
+    filter_datapath(ctx, binding_rec);
 }
 
 static void
@@ -104,7 +115,7 @@  update_qos(const struct ovsrec_interface *iface_rec,
 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 lport_index *lports_index, struct hmap *local_datapaths)
 {
     const struct sbrec_chassis *chassis_rec;
     const struct sbrec_port_binding *binding_rec;
@@ -113,7 +124,7 @@  binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,
 
     struct shash lports = SHASH_INITIALIZER(&lports);
     if (br_int) {
-        get_local_iface_ids(br_int, &lports);
+        get_local_iface_ids(br_int, &lports, lports_index, ctx);
     } else {
         /* We have no integration bridge, therefore no local logical ports.
          * We'll remove our chassis from all port binding records below. */
@@ -137,7 +148,7 @@  binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,
                 /* Add child logical port to the set of all local ports. */
                 sset_add(all_lports, binding_rec->logical_port);
             }
-            add_local_datapath(local_datapaths, binding_rec);
+            add_local_datapath(local_datapaths, binding_rec, ctx);
             if (iface_rec && ctx->ovs_idl_txn) {
                 update_qos(iface_rec, binding_rec);
             }
@@ -169,6 +180,12 @@  binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,
              * a patch port for each one. */
             sset_add(all_lports, binding_rec->logical_port);
         }
+        const char *peer = smap_get(&binding_rec->options, "peer");
+        if (peer) {
+            if (!lport_lookup_by_name(lports_index, peer)) {
+                filter_lport(ctx, peer);
+            }
+        }
     }
 
     SHASH_FOR_EACH (node, &lports) {
diff --git a/ovn/controller/binding.h b/ovn/controller/binding.h
index 25f8989..df861da 100644
--- a/ovn/controller/binding.h
+++ b/ovn/controller/binding.h
@@ -25,10 +25,12 @@  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 lport_index *lports_index,
                  struct hmap *local_datapaths);
 bool binding_cleanup(struct controller_ctx *, const char *chassis_id);
 
diff --git a/ovn/controller/filter.c b/ovn/controller/filter.c
new file mode 100644
index 0000000..929c4aa
--- /dev/null
+++ b/ovn/controller/filter.c
@@ -0,0 +1,165 @@ 
+/* Copyright (c) 2015, 2016 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "filter.h"
+
+#include "openvswitch/vlog.h"
+#include "ovn/lib/ovn-sb-idl.h"
+#include "ovn-controller.h"
+
+VLOG_DEFINE_THIS_MODULE(filter);
+
+static struct hmap filtered_dps = HMAP_INITIALIZER(&filtered_dps);
+static struct hmap filtered_lps = HMAP_INITIALIZER(&filtered_lps);
+
+struct filtered_dp {
+    struct hmap_node hmap_node;
+    int64_t tunnel_key;
+    struct sbrec_datapath_binding *datapath;
+    bool used;
+};
+
+struct filtered_lp {
+    struct hmap_node hmap_node;
+    const char *lport_name;
+    bool used;
+};
+
+void
+filter_init(struct ovsdb_idl *idl)
+{
+    sbrec_port_binding_add_clause_false(idl);
+    sbrec_mac_binding_add_clause_false(idl);
+    sbrec_logical_flow_add_clause_false(idl);
+    sbrec_multicast_group_add_clause_false(idl);
+    
+}
+
+void
+filter_mark_unused(void)
+{
+    struct filtered_lp *lp;
+    struct filtered_lp *dp;
+
+    HMAP_FOR_EACH(lp, hmap_node, &filtered_lps) {
+        lp->used = false;
+    }
+    HMAP_FOR_EACH(dp, hmap_node, &filtered_dps) {
+        dp->used = false;
+    }
+}
+
+void
+filter_remove_unused(struct controller_ctx *ctx)
+{
+    struct filtered_lp *lp, *next;
+    struct filtered_dp *dp, *next_dp;
+
+    HMAP_FOR_EACH_SAFE(lp, next, hmap_node, &filtered_lps) {
+        if (!lp->used) {
+            VLOG_INFO("Unfilter Port %s", lp->lport_name);
+            sbrec_port_binding_remove_clause_logical_port(ctx->ovnsb_idl,
+                                                          OVSDB_F_EQ,
+                                                          lp->lport_name);
+            hmap_remove(&filtered_lps, &lp->hmap_node);
+            free(lp);
+        }
+    }
+    HMAP_FOR_EACH_SAFE(dp, next_dp, hmap_node, &filtered_dps) {
+        if (!dp->used) {
+            VLOG_INFO("Unfilter DP "UUID_FMT,
+                      UUID_ARGS(&dp->datapath->header_.uuid));
+            sbrec_port_binding_remove_clause_datapath(ctx->ovnsb_idl,
+                                                      OVSDB_F_EQ,
+                                                      dp->datapath);
+            sbrec_mac_binding_remove_clause_datapath(ctx->ovnsb_idl,
+                                                     OVSDB_F_EQ,
+                                                     dp->datapath);
+            sbrec_logical_flow_remove_clause_logical_datapath(ctx->ovnsb_idl,
+                                                              OVSDB_F_EQ,
+                                                              dp->datapath);
+            sbrec_multicast_group_remove_clause_datapath(ctx->ovnsb_idl,
+                                                         OVSDB_F_EQ,
+                                                         dp->datapath);
+            hmap_remove(&filtered_lps, &lp->hmap_node);
+            free(lp);
+        }
+    }
+}
+
+void
+filter_lport(struct controller_ctx *ctx, const char *lport_name)
+{
+    struct filtered_lp *lp;
+    size_t hash = hash_bytes(lport_name, strlen(lport_name), 0);
+
+    HMAP_FOR_EACH_WITH_HASH(lp, hmap_node, hash, &filtered_lps) {
+        if (!strcmp(lp->lport_name, lport_name)) {
+            lp->used = true;
+            return;
+        }
+    }
+
+    VLOG_INFO("Filter Port %s", lport_name);
+    
+    sbrec_port_binding_add_clause_logical_port(ctx->ovnsb_idl,
+                                               OVSDB_F_EQ,
+                                               lport_name);
+    
+    char *name = xmalloc(strlen(lport_name));
+    lp = xmalloc(sizeof *lp);
+    
+    strcpy(name, lport_name);
+    lp->lport_name = name;
+    lp->used = true;
+    hmap_insert(&filtered_lps, &lp->hmap_node,
+                hash);
+}
+
+void
+filter_datapath(struct controller_ctx *ctx,
+             const struct sbrec_port_binding *pb)
+{
+    struct filtered_dp *dp;
+
+    HMAP_FOR_EACH_WITH_HASH(dp, hmap_node, pb->datapath->tunnel_key,
+                            &filtered_dps) {
+        if (dp->tunnel_key == pb->datapath->tunnel_key) {
+            dp->used = true;
+            return;
+        }
+    }
+
+    VLOG_INFO("Filter DP "UUID_FMT, UUID_ARGS(&pb->datapath->header_.uuid));
+    sbrec_port_binding_add_clause_datapath(ctx->ovnsb_idl,
+                                           OVSDB_F_EQ,
+                                           pb->datapath);
+    sbrec_mac_binding_add_clause_datapath(ctx->ovnsb_idl,
+                                          OVSDB_F_EQ,
+                                          pb->datapath);
+    sbrec_logical_flow_add_clause_logical_datapath(ctx->ovnsb_idl,
+                                                   OVSDB_F_EQ,
+                                                   pb->datapath);
+    sbrec_multicast_group_add_clause_datapath(ctx->ovnsb_idl,
+                                              OVSDB_F_EQ,
+                                              pb->datapath);
+
+    dp = xmalloc(sizeof *dp);
+    dp->tunnel_key = pb->datapath->tunnel_key;
+    dp->datapath = pb->datapath;
+    dp->used = true;
+    hmap_insert(&filtered_dps, &dp->hmap_node, pb->datapath->tunnel_key);
+}
diff --git a/ovn/controller/filter.h b/ovn/controller/filter.h
new file mode 100644
index 0000000..ef9eae8
--- /dev/null
+++ b/ovn/controller/filter.h
@@ -0,0 +1,30 @@ 
+/* Copyright (c) 2015 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OVN_FILTER_H
+#define OVN_FILTER_H 1
+
+struct controller_ctx;
+struct ovsdb_idl;
+struct sbrec_port_binding;
+
+void filter_init(struct ovsdb_idl *idl);
+void filter_mark_unused(void);
+void filter_remove_unused(struct controller_ctx *ctx);
+void filter_lport(struct controller_ctx *ctx, const char *lport_name);
+void filter_datapath(struct controller_ctx *ctx,
+                     const struct sbrec_port_binding *pb);
+
+#endif /* ovn/controller/filter.h */
diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c
index 356a94b..1428408 100644
--- a/ovn/controller/ovn-controller.c
+++ b/ovn/controller/ovn-controller.c
@@ -53,6 +53,7 @@ 
 #include "stream.h"
 #include "unixctl.h"
 #include "util.h"
+#include "filter.h"
 
 VLOG_DEFINE_THIS_MODULE(main);
 
@@ -383,6 +384,9 @@  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));
+
+    filter_init(ovnsb_idl_loop.idl);
+
     ovsdb_idl_get_initial_snapshot(ovnsb_idl_loop.idl);
 
     int probe_interval = 0;
@@ -416,6 +420,7 @@  main(int argc, char *argv[])
             .ovs_idl_txn = ovsdb_idl_loop_run(&ovs_idl_loop),
             .ovnsb_idl = ovnsb_idl_loop.idl,
             .ovnsb_idl_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),
+            .ovnsb_remote = ovnsb_remote,
         };
 
         /* Contains "struct local_datpath" nodes whose hash values are the
@@ -427,11 +432,16 @@  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(&lports, ctx.ovnsb_idl);
+        mcgroup_index_init(&mcgroups, ctx.ovnsb_idl);
+        filter_mark_unused();
 
         if (chassis_id) {
             chassis_run(&ctx, chassis_id);
             encaps_run(&ctx, br_int, chassis_id);
-            binding_run(&ctx, br_int, chassis_id, &all_lports,
+            binding_run(&ctx, br_int, chassis_id, &all_lports, &lports,
                         &local_datapaths);
         }
 
@@ -439,11 +449,6 @@  main(int argc, char *argv[])
             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,10 +465,12 @@  main(int argc, char *argv[])
             }
             ofctrl_put(&flow_table);
             hmap_destroy(&flow_table);
-            mcgroup_index_destroy(&mcgroups);
-            lport_index_destroy(&lports);
         }
 
+        filter_remove_unused(&ctx);
+        mcgroup_index_destroy(&mcgroups);
+        lport_index_destroy(&lports);
+
         sset_destroy(&all_lports);
 
         struct local_datapath *cur_node, *next_node;
diff --git a/ovn/controller/ovn-controller.h b/ovn/controller/ovn-controller.h
index ba50a98..c2fb22f 100644
--- a/ovn/controller/ovn-controller.h
+++ b/ovn/controller/ovn-controller.h
@@ -26,6 +26,7 @@ 
 struct controller_ctx {
     struct ovsdb_idl *ovnsb_idl;
     struct ovsdb_idl_txn *ovnsb_idl_txn;
+    char *ovnsb_remote;
 
     struct ovsdb_idl *ovs_idl;
     struct ovsdb_idl_txn *ovs_idl_txn;
diff --git a/ovn/controller/patch.c b/ovn/controller/patch.c
index 652466b..5c8cf10 100644
--- a/ovn/controller/patch.c
+++ b/ovn/controller/patch.c
@@ -22,6 +22,7 @@ 
 #include "lib/vswitch-idl.h"
 #include "openvswitch/vlog.h"
 #include "ovn-controller.h"
+#include "filter.h"
 
 VLOG_DEFINE_THIS_MODULE(patch);
 
@@ -230,7 +231,8 @@  add_bridge_mappings(struct controller_ctx *ctx,
 
 static void
 add_patched_datapath(struct hmap *patched_datapaths,
-                     const struct sbrec_port_binding *binding_rec, bool local)
+                     const struct sbrec_port_binding *binding_rec, bool local,
+                     struct controller_ctx *ctx)
 {
     if (get_patched_datapath(patched_datapaths,
                              binding_rec->datapath->tunnel_key)) {
@@ -242,6 +244,7 @@  add_patched_datapath(struct hmap *patched_datapaths,
     pd->port_binding = binding_rec;
     hmap_insert(patched_datapaths, &pd->hmap_node,
                 binding_rec->datapath->tunnel_key);
+    filter_datapath(ctx, binding_rec);
 }
 
 /* Add one OVS patch port for each OVN logical patch port.
@@ -304,7 +307,7 @@  add_logical_patch_ports(struct controller_ctx *ctx,
                               existing_ports);
             free(dst_name);
             free(src_name);
-            add_patched_datapath(patched_datapaths, binding, local_port);
+            add_patched_datapath(patched_datapaths, binding, local_port, ctx);
             if (local_port) {
                 if (binding->chassis != chassis_rec && ctx->ovnsb_idl_txn) {
                     sbrec_port_binding_set_chassis(binding, chassis_rec);
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' \