These two pieces of code have different requirements and hardly anything in common, and I found it easier to understand and reasonably modify the overall structure of the program when they were separated.
Signed-off-by: Ben Pfaff <b...@nicira.com> --- ovn/controller/automake.mk | 2 + ovn/controller/chassis.c | 315 ++------------------------------- ovn/controller/chassis.h | 6 +- ovn/controller/{chassis.c => encaps.c} | 129 ++------------ ovn/controller/{chassis.h => encaps.h} | 12 +- ovn/controller/ovn-controller.c | 12 +- 6 files changed, 49 insertions(+), 427 deletions(-) copy ovn/controller/{chassis.c => encaps.c} (72%) copy ovn/controller/{chassis.h => encaps.h} (79%) diff --git a/ovn/controller/automake.mk b/ovn/controller/automake.mk index 25b5f8b..9ed6bec 100644 --- a/ovn/controller/automake.mk +++ b/ovn/controller/automake.mk @@ -4,6 +4,8 @@ ovn_controller_ovn_controller_SOURCES = \ ovn/controller/binding.h \ ovn/controller/chassis.c \ ovn/controller/chassis.h \ + ovn/controller/encaps.c \ + ovn/controller/encaps.h \ ovn/controller/ofctrl.c \ ovn/controller/ofctrl.h \ ovn/controller/ovn-controller.c \ diff --git a/ovn/controller/chassis.c b/ovn/controller/chassis.c index 4bd39e7..5f1c194 100644 --- a/ovn/controller/chassis.c +++ b/ovn/controller/chassis.c @@ -16,10 +16,6 @@ #include <config.h> #include "chassis.h" -#include "lib/hash.h" -#include "lib/poll-loop.h" -#include "lib/sset.h" -#include "lib/util.h" #include "lib/vswitch-idl.h" #include "openvswitch/vlog.h" #include "ovn/lib/ovn-sb-idl.h" @@ -32,21 +28,15 @@ chassis_init(struct controller_ctx *ctx) { ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_open_vswitch); ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_open_vswitch_col_external_ids); - ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_bridge); - ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_bridge_col_ports); - ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_port); - ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_port_col_name); - ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_port_col_interfaces); - ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_port_col_external_ids); - ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_interface); - ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_interface_col_name); - ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_interface_col_type); - ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_interface_col_options); } -static void -register_chassis(struct controller_ctx *ctx) +void +chassis_run(struct controller_ctx *ctx) { + if (!ctx->ovnsb_idl_txn) { + return; + } + const struct sbrec_chassis *chassis_rec; const struct ovsrec_open_vswitch *cfg; const char *encap_type, *encap_ip; @@ -109,303 +99,22 @@ register_chassis(struct controller_ctx *ctx) inited = true; } -/* Enough context to create a new tunnel, using tunnel_add(). */ -struct tunnel_ctx { - /* Contains "struct port_hash_node"s. Used to figure out what - * existing tunnels should be deleted: we index all of the OVN encap - * rows into this data structure, then as existing rows are - * generated we remove them. After generating all the rows, any - * remaining in 'tunnel_hmap' must be deleted from the database. */ - struct hmap tunnel_hmap; - - /* Names of all ports in the bridge, to allow checking uniqueness when - * adding a new tunnel. */ - struct sset port_names; - - struct ovsdb_idl_txn *ovs_txn; - const struct ovsrec_bridge *br_int; -}; - -struct port_hash_node { - struct hmap_node node; - const struct ovsrec_port *port; - const struct ovsrec_bridge *bridge; -}; - -static size_t -port_hash(const char *chassis_id, const char *type, const char *ip) -{ - size_t hash = hash_string(chassis_id, 0); - hash = hash_string(type, hash); - return hash_string(ip, hash); -} - -static size_t -port_hash_rec(const struct ovsrec_port *port) -{ - const char *chassis_id, *ip; - const struct ovsrec_interface *iface; - - chassis_id = smap_get(&port->external_ids, "ovn-chassis-id"); - - if (!chassis_id || !port->n_interfaces) { - /* This should not happen for an OVN-created port. */ - return 0; - } - - iface = port->interfaces[0]; - ip = smap_get(&iface->options, "remote_ip"); - - return port_hash(chassis_id, iface->type, ip); -} - -static char * -tunnel_create_name(struct tunnel_ctx *tc, const char *chassis_id) -{ - int i; - - for (i = 0; i < UINT16_MAX; i++) { - char *port_name; - port_name = xasprintf("ovn-%.6s-%x", chassis_id, i); - - if (!sset_contains(&tc->port_names, port_name)) { - return port_name; - } - - free(port_name); - } - - return NULL; -} - - -static void -tunnel_add(struct tunnel_ctx *tc, const char *new_chassis_id, - const struct sbrec_encap *encap) -{ - struct port_hash_node *hash_node; - - /* Check whether such a row already exists in OVS. If so, remove it - * from 'tc->tunnel_hmap' and we're done. */ - HMAP_FOR_EACH_WITH_HASH (hash_node, node, - port_hash(new_chassis_id, - encap->type, encap->ip), - &tc->tunnel_hmap) { - const struct ovsrec_port *port = hash_node->port; - const char *chassis_id = smap_get(&port->external_ids, - "ovn-chassis-id"); - const struct ovsrec_interface *iface; - const char *ip; - - if (!chassis_id || !port->n_interfaces) { - continue; - } - - iface = port->interfaces[0]; - ip = smap_get(&iface->options, "remote_ip"); - if (!ip) { - continue; - } - - if (!strcmp(new_chassis_id, chassis_id) - && !strcmp(encap->type, iface->type) - && !strcmp(encap->ip, ip)) { - hmap_remove(&tc->tunnel_hmap, &hash_node->node); - free(hash_node); - return; - } - } - - /* No such port, so add one. */ - struct smap external_ids = SMAP_INITIALIZER(&external_ids); - struct smap options = SMAP_INITIALIZER(&options); - struct ovsrec_port *port, **ports; - struct ovsrec_interface *iface; - char *port_name; - size_t i; - - port_name = tunnel_create_name(tc, new_chassis_id); - if (!port_name) { - VLOG_WARN("Unable to allocate unique name for '%s' tunnel", - new_chassis_id); - return; - } - - iface = ovsrec_interface_insert(tc->ovs_txn); - ovsrec_interface_set_name(iface, port_name); - ovsrec_interface_set_type(iface, encap->type); - smap_add(&options, "remote_ip", encap->ip); - smap_add(&options, "key", "flow"); - ovsrec_interface_set_options(iface, &options); - smap_destroy(&options); - - port = ovsrec_port_insert(tc->ovs_txn); - ovsrec_port_set_name(port, port_name); - ovsrec_port_set_interfaces(port, &iface, 1); - smap_add(&external_ids, "ovn-chassis-id", new_chassis_id); - ovsrec_port_set_external_ids(port, &external_ids); - smap_destroy(&external_ids); - - ports = xmalloc(sizeof *tc->br_int->ports * (tc->br_int->n_ports + 1)); - for (i = 0; i < tc->br_int->n_ports; i++) { - ports[i] = tc->br_int->ports[i]; - } - ports[tc->br_int->n_ports] = port; - ovsrec_bridge_verify_ports(tc->br_int); - ovsrec_bridge_set_ports(tc->br_int, ports, tc->br_int->n_ports + 1); - - sset_add(&tc->port_names, port_name); - free(port_name); - free(ports); -} - -static void -bridge_delete_port(const struct ovsrec_bridge *br, - const struct ovsrec_port *port) -{ - struct ovsrec_port **ports; - size_t i, n; - - ports = xmalloc(sizeof *br->ports * br->n_ports); - for (i = n = 0; i < br->n_ports; i++) { - if (br->ports[i] != port) { - ports[n++] = br->ports[i]; - } - } - ovsrec_bridge_verify_ports(br); - ovsrec_bridge_set_ports(br, ports, n); - free(ports); -} - -static struct sbrec_encap * -preferred_encap(const struct sbrec_chassis *chassis_rec) -{ - size_t i; - - /* For hypervisors, we only support Geneve and STT encapsulations. - * Sets are returned alphabetically, so "geneve" will be preferred - * over "stt". */ - for (i = 0; i < chassis_rec->n_encaps; i++) { - if (!strcmp(chassis_rec->encaps[i]->type, "geneve") - || !strcmp(chassis_rec->encaps[i]->type, "stt")) { - return chassis_rec->encaps[i]; - } - } - - return NULL; -} - -static void -update_encaps(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int) -{ - const struct sbrec_chassis *chassis_rec; - const struct ovsrec_bridge *br; - - struct tunnel_ctx tc = { - .tunnel_hmap = HMAP_INITIALIZER(&tc.tunnel_hmap), - .port_names = SSET_INITIALIZER(&tc.port_names), - .br_int = br_int - }; - - tc.ovs_txn = ctx->ovs_idl_txn; - ovsdb_idl_txn_add_comment(tc.ovs_txn, - "ovn-controller: modifying OVS tunnels '%s'", - ctx->chassis_id); - - /* Collect all port names into tc.port_names. - * - * Collect all the OVN-created tunnels into tc.tunnel_hmap. */ - OVSREC_BRIDGE_FOR_EACH(br, ctx->ovs_idl) { - size_t i; - - for (i = 0; i < br->n_ports; i++) { - const struct ovsrec_port *port = br->ports[i]; - - sset_add(&tc.port_names, port->name); - - if (smap_get(&port->external_ids, "ovn-chassis-id")) { - struct port_hash_node *hash_node = xzalloc(sizeof *hash_node); - hash_node->bridge = br; - hash_node->port = port; - hmap_insert(&tc.tunnel_hmap, &hash_node->node, - port_hash_rec(port)); - } - } - } - - SBREC_CHASSIS_FOR_EACH(chassis_rec, ctx->ovnsb_idl) { - if (strcmp(chassis_rec->name, ctx->chassis_id)) { - /* Create tunnels to the other chassis. */ - const struct sbrec_encap *encap = preferred_encap(chassis_rec); - if (!encap) { - VLOG_INFO("No supported encaps for '%s'", chassis_rec->name); - continue; - } - tunnel_add(&tc, chassis_rec->name, encap); - } - } - - /* Delete any existing OVN tunnels that were not still around. */ - struct port_hash_node *hash_node, *next_hash_node; - HMAP_FOR_EACH_SAFE (hash_node, next_hash_node, node, &tc.tunnel_hmap) { - hmap_remove(&tc.tunnel_hmap, &hash_node->node); - bridge_delete_port(hash_node->bridge, hash_node->port); - free(hash_node); - } - hmap_destroy(&tc.tunnel_hmap); - sset_destroy(&tc.port_names); -} - -void -chassis_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int) -{ - if (ctx->ovnsb_idl_txn) { - register_chassis(ctx); - } - - if (ctx->ovs_idl_txn) { - update_encaps(ctx, br_int); - } -} - /* Returns true if the database is all cleaned up, false if more work is * required. */ bool -chassis_cleanup(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int) +chassis_cleanup(struct controller_ctx *ctx) { - if (!ctx->ovnsb_idl_txn || !ctx->ovs_idl_txn) { - return false; - } - - bool any_changes = false; - /* Delete Chassis row. */ const struct sbrec_chassis *chassis_rec = get_chassis_by_name(ctx->ovnsb_idl, ctx->chassis_id); - if (chassis_rec) { + if (!chassis_rec) { + return true; + } + if (ctx->ovnsb_idl_txn) { ovsdb_idl_txn_add_comment(ctx->ovnsb_idl_txn, "ovn-controller: unregistering chassis '%s'", ctx->chassis_id); sbrec_chassis_delete(chassis_rec); - any_changes = true; - } - - /* Delete all the OVS-created tunnels from the integration bridge. */ - ovsdb_idl_txn_add_comment(ctx->ovs_idl_txn, - "ovn-controller: destroying tunnels"); - struct ovsrec_port **ports - = xmalloc(sizeof *br_int->ports * br_int->n_ports); - size_t n = 0; - for (size_t i = 0; i < br_int->n_ports; i++) { - if (!smap_get(&br_int->ports[i]->external_ids, - "ovn-chassis-id")) { - ports[n++] = br_int->ports[i]; - any_changes = true; - } } - ovsrec_bridge_verify_ports(br_int); - ovsrec_bridge_set_ports(br_int, ports, n); - free(ports); - - return !any_changes; + return false; } diff --git a/ovn/controller/chassis.h b/ovn/controller/chassis.h index bfacde1..18582ec 100644 --- a/ovn/controller/chassis.h +++ b/ovn/controller/chassis.h @@ -22,9 +22,7 @@ struct controller_ctx; struct ovsrec_bridge; void chassis_init(struct controller_ctx *); -void chassis_run(struct controller_ctx *, - const struct ovsrec_bridge *br_int); -bool chassis_cleanup(struct controller_ctx *, - const struct ovsrec_bridge *br_int); +void chassis_run(struct controller_ctx *); +bool chassis_cleanup(struct controller_ctx *); #endif /* ovn/chassis.h */ diff --git a/ovn/controller/chassis.c b/ovn/controller/encaps.c similarity index 72% copy from ovn/controller/chassis.c copy to ovn/controller/encaps.c index 4bd39e7..529bf1e 100644 --- a/ovn/controller/chassis.c +++ b/ovn/controller/encaps.c @@ -14,10 +14,9 @@ */ #include <config.h> -#include "chassis.h" +#include "encaps.h" #include "lib/hash.h" -#include "lib/poll-loop.h" #include "lib/sset.h" #include "lib/util.h" #include "lib/vswitch-idl.h" @@ -25,13 +24,11 @@ #include "ovn/lib/ovn-sb-idl.h" #include "ovn-controller.h" -VLOG_DEFINE_THIS_MODULE(chassis); +VLOG_DEFINE_THIS_MODULE(encaps); void -chassis_init(struct controller_ctx *ctx) +encaps_init(struct controller_ctx *ctx) { - ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_open_vswitch); - ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_open_vswitch_col_external_ids); ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_bridge); ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_bridge_col_ports); ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_port); @@ -44,71 +41,6 @@ chassis_init(struct controller_ctx *ctx) ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_interface_col_options); } -static void -register_chassis(struct controller_ctx *ctx) -{ - const struct sbrec_chassis *chassis_rec; - const struct ovsrec_open_vswitch *cfg; - const char *encap_type, *encap_ip; - struct sbrec_encap *encap_rec; - static bool inited = false; - - chassis_rec = get_chassis_by_name(ctx->ovnsb_idl, ctx->chassis_id); - - /* xxx Need to support more than one encap. Also need to support - * xxx encap options. */ - cfg = ovsrec_open_vswitch_first(ctx->ovs_idl); - if (!cfg) { - VLOG_INFO("No Open_vSwitch row defined."); - return; - } - - encap_type = smap_get(&cfg->external_ids, "ovn-encap-type"); - encap_ip = smap_get(&cfg->external_ids, "ovn-encap-ip"); - if (!encap_type || !encap_ip) { - VLOG_INFO("Need to specify an encap type and ip"); - return; - } - - if (chassis_rec) { - int i; - - for (i = 0; i < chassis_rec->n_encaps; i++) { - if (!strcmp(chassis_rec->encaps[i]->type, encap_type) - && !strcmp(chassis_rec->encaps[i]->ip, encap_ip)) { - /* Nothing changed. */ - inited = true; - return; - } else if (!inited) { - VLOG_WARN("Chassis config changing on startup, make sure " - "multiple chassis are not configured : %s/%s->%s/%s", - chassis_rec->encaps[i]->type, - chassis_rec->encaps[i]->ip, - encap_type, encap_ip); - } - - } - } - - ovsdb_idl_txn_add_comment(ctx->ovnsb_idl_txn, - "ovn-controller: registering chassis '%s'", - ctx->chassis_id); - - if (!chassis_rec) { - chassis_rec = sbrec_chassis_insert(ctx->ovnsb_idl_txn); - sbrec_chassis_set_name(chassis_rec, ctx->chassis_id); - } - - encap_rec = sbrec_encap_insert(ctx->ovnsb_idl_txn); - - sbrec_encap_set_type(encap_rec, encap_type); - sbrec_encap_set_ip(encap_rec, encap_ip); - - sbrec_chassis_set_encaps(chassis_rec, &encap_rec, 1); - - inited = true; -} - /* Enough context to create a new tunnel, using tunnel_add(). */ struct tunnel_ctx { /* Contains "struct port_hash_node"s. Used to figure out what @@ -295,9 +227,13 @@ preferred_encap(const struct sbrec_chassis *chassis_rec) return NULL; } -static void -update_encaps(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int) +void +encaps_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int) { + if (!ctx->ovs_idl_txn) { + return; + } + const struct sbrec_chassis *chassis_rec; const struct ovsrec_bridge *br; @@ -356,55 +292,28 @@ update_encaps(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int) sset_destroy(&tc.port_names); } -void -chassis_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int) -{ - if (ctx->ovnsb_idl_txn) { - register_chassis(ctx); - } - - if (ctx->ovs_idl_txn) { - update_encaps(ctx, br_int); - } -} - /* Returns true if the database is all cleaned up, false if more work is * required. */ bool -chassis_cleanup(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int) +encaps_cleanup(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int) { - if (!ctx->ovnsb_idl_txn || !ctx->ovs_idl_txn) { - return false; - } - - bool any_changes = false; - - /* Delete Chassis row. */ - const struct sbrec_chassis *chassis_rec - = get_chassis_by_name(ctx->ovnsb_idl, ctx->chassis_id); - if (chassis_rec) { - ovsdb_idl_txn_add_comment(ctx->ovnsb_idl_txn, - "ovn-controller: unregistering chassis '%s'", - ctx->chassis_id); - sbrec_chassis_delete(chassis_rec); - any_changes = true; - } - /* Delete all the OVS-created tunnels from the integration bridge. */ - ovsdb_idl_txn_add_comment(ctx->ovs_idl_txn, - "ovn-controller: destroying tunnels"); struct ovsrec_port **ports = xmalloc(sizeof *br_int->ports * br_int->n_ports); size_t n = 0; for (size_t i = 0; i < br_int->n_ports; i++) { - if (!smap_get(&br_int->ports[i]->external_ids, - "ovn-chassis-id")) { + if (!smap_get(&br_int->ports[i]->external_ids, "ovn-chassis-id")) { ports[n++] = br_int->ports[i]; - any_changes = true; } } - ovsrec_bridge_verify_ports(br_int); - ovsrec_bridge_set_ports(br_int, ports, n); + + bool any_changes = n != br_int->n_ports; + if (any_changes && ctx->ovs_idl_txn) { + ovsdb_idl_txn_add_comment(ctx->ovs_idl_txn, + "ovn-controller: destroying tunnels"); + ovsrec_bridge_verify_ports(br_int); + ovsrec_bridge_set_ports(br_int, ports, n); + } free(ports); return !any_changes; diff --git a/ovn/controller/chassis.h b/ovn/controller/encaps.h similarity index 79% copy from ovn/controller/chassis.h copy to ovn/controller/encaps.h index bfacde1..0ec132d 100644 --- a/ovn/controller/chassis.h +++ b/ovn/controller/encaps.h @@ -13,18 +13,18 @@ * limitations under the License. */ -#ifndef OVN_CHASSIS_H -#define OVN_CHASSIS_H 1 +#ifndef OVN_ENCAPS_H +#define OVN_ENCAPS_H 1 #include <stdbool.h> struct controller_ctx; struct ovsrec_bridge; -void chassis_init(struct controller_ctx *); -void chassis_run(struct controller_ctx *, +void encaps_init(struct controller_ctx *); +void encaps_run(struct controller_ctx *, const struct ovsrec_bridge *br_int); -bool chassis_cleanup(struct controller_ctx *, +bool encaps_cleanup(struct controller_ctx *, const struct ovsrec_bridge *br_int); -#endif /* ovn/chassis.h */ +#endif /* ovn/encaps.h */ diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c index 0657140..f3fb3a4 100644 --- a/ovn/controller/ovn-controller.c +++ b/ovn/controller/ovn-controller.c @@ -42,6 +42,7 @@ #include "ofctrl.h" #include "binding.h" #include "chassis.h" +#include "encaps.h" #include "physical.h" #include "pipeline.h" @@ -255,6 +256,7 @@ main(int argc, char *argv[]) ovsdb_idl_add_column(ctx.ovs_idl, &ovsrec_open_vswitch_col_external_ids); chassis_init(&ctx); + encaps_init(&ctx); binding_init(&ctx); physical_init(&ctx); pipeline_init(); @@ -286,7 +288,8 @@ main(int argc, char *argv[]) goto exit; } - chassis_run(&ctx, br_int); + chassis_run(&ctx); + encaps_run(&ctx, br_int); binding_run(&ctx, br_int); struct hmap flow_table = HMAP_INITIALIZER(&flow_table); @@ -324,10 +327,11 @@ main(int argc, char *argv[]) goto exit; } - /* Run both the binding and chassis cleanup, even if one of them - * returns false. We're done if both return true. */ + /* Run all of the cleanup functions, even if one of them returns false. + * We're done if all of them return true. */ done = binding_cleanup(&ctx); - done = chassis_cleanup(&ctx, br_int) && done; + done = chassis_cleanup(&ctx) && done; + done = encaps_cleanup(&ctx, br_int) && done; if (done) { poll_immediate_wake(); } -- 2.1.3 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev