From: RYAN D. MOATS <rmo...@us.ibm.com> As a side effect, tunnel context is persisted.
Signed-off-by: RYAN D. MOATS <rmo...@us.ibm.com> --- ovn/controller/encaps.c | 159 +++++++++++++++++++++++++++------------ ovn/controller/ovn-controller.c | 5 + 2 files changed, 117 insertions(+), 47 deletions(-) diff --git a/ovn/controller/encaps.c b/ovn/controller/encaps.c index dfb11c0..0d64e6a 100644 --- a/ovn/controller/encaps.c +++ b/ovn/controller/encaps.c @@ -15,6 +15,7 @@ #include <config.h> #include "encaps.h" +#include "lflow.h" #include "lib/hash.h" #include "lib/sset.h" @@ -49,6 +50,7 @@ struct tunnel_ctx { * generated we remove them. After generating all the rows, any * remaining in 'tunnel_hmap' must be deleted from the database. */ struct hmap tunnel_hmap; + struct hmap tunnel_hmap_by_uuid; /* Names of all ports in the bridge, to allow checking uniqueness when * adding a new tunnel. */ @@ -58,8 +60,18 @@ struct tunnel_ctx { const struct ovsrec_bridge *br_int; }; +struct tunnel_ctx tc = { + .tunnel_hmap = HMAP_INITIALIZER(&tc.tunnel_hmap), + .tunnel_hmap_by_uuid = HMAP_INITIALIZER(&tc.tunnel_hmap_by_uuid), + .port_names = SSET_INITIALIZER(&tc.port_names), +}; + +bool process_full_encaps = false; + struct port_hash_node { struct hmap_node node; + struct hmap_node uuid_node; + const struct uuid *uuid; const struct ovsrec_port *port; const struct ovsrec_bridge *bridge; }; @@ -92,7 +104,7 @@ port_hash_rec(const struct ovsrec_port *port) } static char * -tunnel_create_name(struct tunnel_ctx *tc, const char *chassis_id) +tunnel_create_name(const char *chassis_id) { int i; @@ -100,7 +112,7 @@ tunnel_create_name(struct tunnel_ctx *tc, const char *chassis_id) char *port_name; port_name = xasprintf("ovn-%.6s-%x", chassis_id, i); - if (!sset_contains(&tc->port_names, port_name)) { + if (!sset_contains(&tc.port_names, port_name)) { return port_name; } @@ -110,19 +122,32 @@ tunnel_create_name(struct tunnel_ctx *tc, const char *chassis_id) return NULL; } +static struct port_hash_node * +port_lookup_by_uuid(const struct uuid *uuid) +{ + struct hmap_node *node = hmap_first_with_hash(&tc.tunnel_hmap_by_uuid, + uuid_hash(uuid)); + if (node) { + return CONTAINER_OF(node, struct port_hash_node, uuid_node); + } + return NULL; +} static void -tunnel_add(struct tunnel_ctx *tc, const char *new_chassis_id, +tunnel_add(const struct sbrec_chassis *chassis_rec, const struct sbrec_encap *encap) { struct port_hash_node *hash_node; + const char *new_chassis_id = chassis_rec->name; + + /* Check whether such a row already exists in OVS. If so, update + * the uuid field and insert into the by uuid hashmap. If not, + * create the tunnel */ - /* 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) { + &tc.tunnel_hmap) { const struct ovsrec_port *port = hash_node->port; const char *chassis_id = smap_get(&port->external_ids, "ovn-chassis-id"); @@ -142,8 +167,12 @@ tunnel_add(struct tunnel_ctx *tc, const char *new_chassis_id, 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); + + hash_node->uuid = &chassis_rec->header_.uuid; + if (!port_lookup_by_uuid(hash_node->uuid)) { + hmap_insert(&tc.tunnel_hmap_by_uuid, &hash_node->uuid_node, + uuid_hash(hash_node->uuid)); + } return; } } @@ -155,14 +184,14 @@ tunnel_add(struct tunnel_ctx *tc, const char *new_chassis_id, char *port_name; size_t i; - port_name = tunnel_create_name(tc, new_chassis_id); + port_name = tunnel_create_name(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); + 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); @@ -170,23 +199,25 @@ tunnel_add(struct tunnel_ctx *tc, const char *new_chassis_id, ovsrec_interface_set_options(iface, &options); smap_destroy(&options); - port = ovsrec_port_insert(tc->ovs_txn); + port = ovsrec_port_insert(tc.ovs_txn); ovsrec_port_set_name(port, port_name); ovsrec_port_set_interfaces(port, &iface, 1); const struct smap id = SMAP_CONST1(&id, "ovn-chassis-id", new_chassis_id); ovsrec_port_set_external_ids(port, &id); - 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 = 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); + 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); + sset_add(&tc.port_names, port_name); free(port_name); free(ports); + // reset_flow_processing(); + process_full_encaps = true; } static void @@ -224,6 +255,21 @@ preferred_encap(const struct sbrec_chassis *chassis_rec) return best_encap; } +static void +check_and_add_tunnel(const struct sbrec_chassis *chassis_rec, + const char *chassis_id) +{ + if (strcmp(chassis_rec->name, 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); + return; + } + tunnel_add(chassis_rec, encap); + } +} + void encaps_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int, const char *chassis_id) @@ -235,12 +281,7 @@ encaps_run(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.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'", @@ -257,37 +298,61 @@ encaps_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int, 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)); + const char *old_chassis_id = smap_get(&port->external_ids, + "ovn-chassis-id"); + if (old_chassis_id) { + if (!hmap_first_with_hash(&tc.tunnel_hmap, + port_hash_rec(port))) { + 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)); + process_full_encaps = true; + } } } } - SBREC_CHASSIS_FOR_EACH(chassis_rec, ctx->ovnsb_idl) { - if (strcmp(chassis_rec->name, 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); + if (process_full_encaps) { + SBREC_CHASSIS_FOR_EACH (chassis_rec, ctx->ovnsb_idl) { + check_and_add_tunnel(chassis_rec, chassis_id); + } + process_full_encaps = false; + } else { + SBREC_CHASSIS_FOR_EACH_TRACKED (chassis_rec, ctx->ovnsb_idl) { + bool is_deleted = sbrec_chassis_row_get_seqno(chassis_rec, + OVSDB_IDL_CHANGE_DELETE) > 0; + bool is_new = sbrec_chassis_row_get_seqno(chassis_rec, + OVSDB_IDL_CHANGE_MODIFY) == 0; + + if (is_deleted) { + /* lookup the tunnel by row uuid and remove it */ + struct port_hash_node *port_hash = + port_lookup_by_uuid(&chassis_rec->header_.uuid); + if (port_hash) { + bridge_delete_port(port_hash->bridge, port_hash->port); + sset_find_and_delete(&tc.port_names, + port_hash->port->name); + hmap_remove(&tc.tunnel_hmap, &port_hash->node); + hmap_remove(&tc.tunnel_hmap_by_uuid, + &port_hash->uuid_node); + free(port_hash); + } continue; } - tunnel_add(&tc, chassis_rec->name, encap); + if (!is_new) { + if (strcmp(chassis_rec->name, chassis_id)) { + /* TODO: find the tunnel by looking it up based on its + * uuid and then change it. */ + ; + } + } else { + check_and_add_tunnel(chassis_rec, chassis_id); + } } } - - /* 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); } /* Returns true if the database is all cleaned up, false if more work is diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c index 7c68c9d..16731a4 100644 --- a/ovn/controller/ovn-controller.c +++ b/ovn/controller/ovn-controller.c @@ -304,6 +304,10 @@ 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)); + + /* track the southbound idl */ + ovsdb_idl_track_add_all(ovnsb_idl_loop.idl); + ovsdb_idl_get_initial_snapshot(ovnsb_idl_loop.idl); int probe_interval = 0; @@ -398,6 +402,7 @@ main(int argc, char *argv[]) } ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop); ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop); + ovsdb_idl_track_clear(ovnsb_idl_loop.idl); poll_block(); if (should_service_stop()) { exiting = true; -- 1.7.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev