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 --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' \ -- 2.1.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev