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. ovn-bridge-mappings unit test fails due to the fact that patch ports will not be created on local bridge if there is no port binded to the logical datapath on the local host. Signed-off-by: Liran Schour <lir...@il.ibm.com> --- ovn/controller/binding.c | 114 +++++++++++++++++++++++++++++++++++- ovn/controller/binding.h | 4 +- ovn/controller/lport.c | 124 ++++++++++++++++++++++++++++++++++++++-- ovn/controller/lport.h | 10 +++- ovn/controller/ovn-controller.c | 54 ++++++++++++++--- ovn/controller/ovn-controller.h | 8 +++ 6 files changed, 297 insertions(+), 17 deletions(-) diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c index a0d8b96..9681fcb 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); @@ -146,10 +148,114 @@ update_qos(const struct ovsrec_interface *iface_rec, ovsrec_interface_set_ingress_policing_burst(iface_rec, MAX(0, burst)); } +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->binding_cond, + OVSDB_IDL_F_EQ, + lports_array[i]); + sbrec_port_binding_remove_clause_parent_port(ctx->binding_cond, + OVSDB_IDL_F_EQ, + lports_array[i]); + ctx->binding_cond_updated = true; + 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->binding_cond, + OVSDB_IDL_F_EQ, + tmp_lports_array[j]); + sbrec_port_binding_add_clause_parent_port(ctx->binding_cond, + OVSDB_IDL_F_EQ, + tmp_lports_array[j]); + ctx->binding_cond_updated = true; + 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->binding_cond, + OVSDB_IDL_F_EQ, + lports_array[i]); + sbrec_port_binding_remove_clause_parent_port(ctx->binding_cond, + OVSDB_IDL_F_EQ, + lports_array[i]); + ctx->binding_cond_updated = true; + 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->binding_cond, + OVSDB_IDL_F_EQ, + tmp_lports_array[j]); + sbrec_port_binding_add_clause_parent_port(ctx->binding_cond, + OVSDB_IDL_F_EQ, + tmp_lports_array[j]); + ctx->binding_cond_updated = true; + sset_add(&g_lports, tmp_lports_array[j]); + } + } + + free(lports_array); + free(tmp_lports_array); + + return; +} + +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->binding_cond, + OVSDB_IDL_F_EQ, + lport); + sbrec_port_binding_add_clause_parent_port(ctx->binding_cond, + OVSDB_IDL_F_EQ, + lport); + sbrec_mac_binding_add_clause_logical_port(ctx->mac_binding_cond, + OVSDB_IDL_F_EQ, + lport); + ctx->binding_cond_updated = true; + ctx->mac_binding_cond_updated = true; + } +} + void binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int, const char *chassis_id, struct simap *ct_zones, - unsigned long *ct_zone_bitmap, struct hmap *local_datapaths) + unsigned long *ct_zone_bitmap, struct hmap *local_datapaths, + const struct lport_index *lport_indexes) { const struct sbrec_chassis *chassis_rec; const struct sbrec_port_binding *binding_rec; @@ -170,10 +276,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 6e19c10..74f2f3b 100644 --- a/ovn/controller/binding.h +++ b/ovn/controller/binding.h @@ -24,11 +24,13 @@ struct hmap; struct ovsdb_idl; struct ovsrec_bridge; struct simap; +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 simap *ct_zones, - unsigned long *ct_zone_bitmap, struct hmap *local_datapaths); + unsigned long *ct_zone_bitmap, 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..1315c05 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,123 @@ 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->binding_cond, + OVSDB_IDL_F_EQ, binding); + sbrec_logical_flow_add_clause_logical_datapath(ctx->lflow_cond, + OVSDB_IDL_F_EQ, binding); + sbrec_multicast_group_add_clause_datapath(ctx->mgroup_cond, + OVSDB_IDL_F_EQ, binding); + ctx->binding_cond_updated = true; + ctx->lflow_cond_updated = true; + ctx->mgroup_cond_updated = true; + } + 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->binding_cond, + OVSDB_IDL_F_EQ, + datapath); + sbrec_logical_flow_remove_clause_logical_datapath(ctx->lflow_cond, + OVSDB_IDL_F_EQ, + datapath); + sbrec_multicast_group_remove_clause_datapath(ctx->mgroup_cond, + OVSDB_IDL_F_EQ, + datapath); + ctx->binding_cond_updated = true; + ctx->lflow_cond_updated = true; + ctx->mgroup_cond_updated = true; + } + 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 +155,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 +179,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 +218,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 +237,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 511b184..016abca 100644 --- a/ovn/controller/ovn-controller.c +++ b/ovn/controller/ovn-controller.c @@ -313,6 +313,23 @@ 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)); + + struct ovsdb_idl_condition binding_cond; + ovsdb_idl_condition_init(&binding_cond, &sbrec_table_port_binding); + sbrec_port_binding_add_clause_false(&binding_cond); + ovsdb_idl_cond_update(ovnsb_idl_loop.idl, &binding_cond); + struct ovsdb_idl_condition lflow_cond; + ovsdb_idl_condition_init(&lflow_cond, &sbrec_table_logical_flow); + sbrec_logical_flow_add_clause_false(&lflow_cond); + ovsdb_idl_cond_update(ovnsb_idl_loop.idl, &lflow_cond); + struct ovsdb_idl_condition mgroup_cond; + ovsdb_idl_condition_init(&mgroup_cond, &sbrec_table_multicast_group); + sbrec_multicast_group_add_clause_false(&mgroup_cond); + ovsdb_idl_cond_update(ovnsb_idl_loop.idl, &mgroup_cond); + struct ovsdb_idl_condition mac_binding_cond; + ovsdb_idl_condition_init(&mac_binding_cond, &sbrec_table_mac_binding); + sbrec_mac_binding_add_clause_false(&mac_binding_cond); + ovsdb_idl_cond_update(ovnsb_idl_loop.idl, &mac_binding_cond); ovsdb_idl_get_initial_snapshot(ovnsb_idl_loop.idl); int probe_interval = 0; @@ -346,6 +363,14 @@ 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), + .binding_cond = &binding_cond, + .binding_cond_updated = false, + .lflow_cond = &lflow_cond, + .lflow_cond_updated = false, + .mgroup_cond = &mgroup_cond, + .mgroup_cond_updated = false, + .mac_binding_cond = &mac_binding_cond, + .mac_binding_cond_updated = false, }; /* Contains "struct local_datpath" nodes whose hash values are the @@ -356,22 +381,21 @@ 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, &ct_zones, ct_zone_bitmap, - &local_datapaths); + &local_datapaths, &lports); } if (br_int) { patch_run(&ctx, br_int, &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); @@ -386,9 +410,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); struct local_datapath *cur_node, *next_node; HMAP_FOR_EACH_SAFE (cur_node, next_node, hmap_node, &local_datapaths) { @@ -418,6 +442,20 @@ main(int argc, char *argv[]) } ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop); ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop); + + if (ctx.binding_cond_updated) { + ovsdb_idl_cond_update(ctx.ovnsb_idl, ctx.binding_cond); + } + if (ctx.lflow_cond_updated) { + ovsdb_idl_cond_update(ctx.ovnsb_idl, ctx.lflow_cond); + } + if (ctx.mgroup_cond_updated) { + ovsdb_idl_cond_update(ctx.ovnsb_idl, ctx.mgroup_cond); + } + if (ctx.mac_binding_cond_updated) { + ovsdb_idl_cond_update(ctx.ovnsb_idl, ctx.mac_binding_cond); + } + poll_block(); if (should_service_stop()) { exiting = true; diff --git a/ovn/controller/ovn-controller.h b/ovn/controller/ovn-controller.h index 9af7959..17df6a8 100644 --- a/ovn/controller/ovn-controller.h +++ b/ovn/controller/ovn-controller.h @@ -29,6 +29,14 @@ struct controller_ctx { struct ovsdb_idl *ovs_idl; struct ovsdb_idl_txn *ovs_idl_txn; + struct ovsdb_idl_condition *binding_cond; + bool binding_cond_updated; + struct ovsdb_idl_condition *lflow_cond; + bool lflow_cond_updated; + struct ovsdb_idl_condition *mgroup_cond; + bool mgroup_cond_updated; + struct ovsdb_idl_condition *mac_binding_cond; + bool mac_binding_cond_updated; }; /* Contains hmap_node whose hash values are the tunnel_key of datapaths -- 2.1.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev