From b86f476778ea373f1c968cfc1b3054f18120d220 Mon Sep 17 00:00:00 2001 From: "majopela@redhat.com" Date: Thu, 13 Jul 2017 17:02:36 +0000 Subject: [PATCH] ovn: l3ha, ovn-northd gateway chassis propagation The redirect-chassis option of logical router ports is now translated to Gateway_Chassis entries for backwards compatibility. Gateway_Chassis entries in nbdb are copied over to sbdb and linked them to the Chassis entry. Co-authored-by: Anil Venkata Signed-off-by: Miguel Angel Ajo Signed-off-by: Anil Venkata Signed-off-by: Russell Bryant --- ovn/lib/automake.mk | 2 + ovn/lib/chassis-index.c | 77 +++++++++++++ ovn/lib/chassis-index.h | 40 +++++++ ovn/northd/ovn-northd.c | 247 ++++++++++++++++++++++++++++++++++++++-- tests/automake.mk | 1 + tests/ovn-northd.at | 87 ++++++++++++++ tests/testsuite.at | 1 + 7 files changed, 446 insertions(+), 9 deletions(-) create mode 100644 ovn/lib/chassis-index.c create mode 100644 ovn/lib/chassis-index.h create mode 100644 tests/ovn-northd.at diff --git a/ovn/lib/automake.mk b/ovn/lib/automake.mk index b86237eb7..9ad8b6af7 100644 --- a/ovn/lib/automake.mk +++ b/ovn/lib/automake.mk @@ -5,6 +5,8 @@ ovn_lib_libovn_la_LDFLAGS = \ $(AM_LDFLAGS) ovn_lib_libovn_la_SOURCES = \ ovn/lib/actions.c \ + ovn/lib/chassis-index.c \ + ovn/lib/chassis-index.h \ ovn/lib/expr.c \ ovn/lib/lex.c \ ovn/lib/ovn-dhcp.h \ diff --git a/ovn/lib/chassis-index.c b/ovn/lib/chassis-index.c new file mode 100644 index 000000000..ae65375f0 --- /dev/null +++ b/ovn/lib/chassis-index.c @@ -0,0 +1,77 @@ +/* Copyright (c) 2016, 2017 Red Hat, 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 + +#include "openvswitch/hmap.h" +#include "openvswitch/vlog.h" +#include "ovn/actions.h" +#include "ovn/lib/chassis-index.h" +#include "ovn/lib/ovn-sb-idl.h" + +VLOG_DEFINE_THIS_MODULE(chassis_index); + +struct chassis { + struct hmap_node name_node; + const struct sbrec_chassis *db; +}; + +const struct sbrec_chassis * +chassis_lookup_by_name(const struct chassis_index *chassis_index, + const char *name) +{ + const struct chassis *chassis; + HMAP_FOR_EACH_WITH_HASH (chassis, name_node, hash_string(name, 0), + &chassis_index->by_name) { + if (!strcmp(chassis->db->name, name)) { + return chassis->db; + } + } + return NULL; +} + +void +chassis_index_init(struct chassis_index *chassis_index, + struct ovsdb_idl *sb_idl) +{ + hmap_init(&chassis_index->by_name); + + const struct sbrec_chassis *chassis; + SBREC_CHASSIS_FOR_EACH (chassis, sb_idl) { + if (!chassis->name) { + continue; + } + struct chassis *c = xmalloc(sizeof *c); + hmap_insert(&chassis_index->by_name, &c->name_node, + hash_string(chassis->name, 0)); + c->db = chassis; + } +} + +void +chassis_index_destroy(struct chassis_index *chassis_index) +{ + if (!chassis_index) { + return; + } + + /* Destroy all of the "struct chassis"s. */ + struct chassis *chassis, *next; + HMAP_FOR_EACH_SAFE (chassis, next, name_node, &chassis_index->by_name) { + hmap_remove(&chassis_index->by_name, &chassis->name_node); + free(chassis); + } + + hmap_destroy(&chassis_index->by_name); +} diff --git a/ovn/lib/chassis-index.h b/ovn/lib/chassis-index.h new file mode 100644 index 000000000..a490cbb78 --- /dev/null +++ b/ovn/lib/chassis-index.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2017, Red Hat, 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_CHASSIS_INDEX_H +#define OVN_CHASSIS_INDEX_H 1 + +#include "openvswitch/hmap.h" + +struct chassis_index { + struct hmap by_name; +}; + +struct ovsdb_idl; + +/* Finds and returns the chassis with the given 'name', or NULL if no such + * chassis exists. */ +const struct sbrec_chassis * +chassis_lookup_by_name(const struct chassis_index *chassis_index, + const char *name); + +/* Initializes the chassis index out of the ovsdb_idl to SBDB */ +void chassis_index_init(struct chassis_index *chassis_index, + struct ovsdb_idl *sb_idl); + +/* Free a chassis index from memory */ +void chassis_index_destroy(struct chassis_index *chassis_index); + +#endif /* ovn/lib/chassis-index.h */ diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index be3b371c2..92385adc0 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -28,6 +28,7 @@ #include "openvswitch/hmap.h" #include "openvswitch/json.h" #include "ovn/lex.h" +#include "ovn/lib/chassis-index.h" #include "ovn/lib/logical-fields.h" #include "ovn/lib/ovn-dhcp.h" #include "ovn/lib/ovn-nb-idl.h" @@ -1453,7 +1454,7 @@ join_logical_ports(struct northd_context *ctx, const char *redirect_chassis = smap_get(&op->nbrp->options, "redirect-chassis"); - if (redirect_chassis) { + if (redirect_chassis || op->nbrp->n_gateway_chassis) { /* Additional "derived" ovn_port crp represents the * instance of op on the "redirect-chassis". */ const char *gw_chassis = smap_get(&op->od->nbr->options, @@ -1678,8 +1679,157 @@ get_nat_addresses(const struct ovn_port *op, size_t *n) return addresses; } +static bool +gateway_chassis_equal(const struct nbrec_gateway_chassis *nb_gwc, + const struct sbrec_chassis *nb_gwc_c, + const struct sbrec_gateway_chassis *sb_gwc) +{ + return !strcmp(nb_gwc->name, sb_gwc->name) + && !strcmp(nb_gwc_c->name, sb_gwc->chassis->name) + && nb_gwc->priority == sb_gwc->priority + && smap_equal(&nb_gwc->options, &sb_gwc->options) + && smap_equal(&nb_gwc->external_ids, &sb_gwc->external_ids); +} + +static bool +sbpb_gw_chassis_needs_update( + const struct sbrec_port_binding *port_binding, + const struct nbrec_logical_router_port *lrp, + const struct chassis_index *chassis_index) +{ + if (!lrp || !port_binding) { + return false; + } + + /* These arrays are used to collect valid Gateway_Chassis and valid + * Chassis records from the Logical_Router_Port Gateway_Chassis list, + * we ignore the ones we can't match on the SBDB */ + struct nbrec_gateway_chassis **lrp_gwc = xzalloc(lrp->n_gateway_chassis * + sizeof *lrp_gwc); + const struct sbrec_chassis **lrp_gwc_c = xzalloc(lrp->n_gateway_chassis * + sizeof *lrp_gwc_c); + + /* Count the number of gateway chassis chassis names from the logical + * router port that we are able to match on the southbound database */ + int lrp_n_gateway_chassis = 0; + int n; + for (n = 0; n < lrp->n_gateway_chassis; n++) { + + if (!lrp->gateway_chassis[n]->chassis_name) { + continue; + } + + const struct sbrec_chassis *chassis = + chassis_lookup_by_name(chassis_index, + lrp->gateway_chassis[n]->chassis_name); + + if (chassis) { + lrp_gwc_c[lrp_n_gateway_chassis] = chassis; + lrp_gwc[lrp_n_gateway_chassis] = lrp->gateway_chassis[n]; + lrp_n_gateway_chassis++; + } else { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_WARN_RL( + &rl, "Chassis name %s referenced in NBDB via Gateway_Chassis " + "on logical router port %s does not exist in SBDB", + lrp->gateway_chassis[n]->chassis_name, lrp->name); + } + } + + /* Basic check, different amount of Gateway_Chassis means that we + * need to update southbound database Port_Binding */ + if (lrp_n_gateway_chassis != port_binding->n_gateway_chassis) { + free(lrp_gwc_c); + free(lrp_gwc); + return true; + } + + for (n = 0; n < lrp_n_gateway_chassis; n++) { + int i; + /* For each of the valid gw chassis on the lrp, check if there's + * a match on the Port_Binding list, we assume order is not + * persisted */ + for (i = 0; i < port_binding->n_gateway_chassis; i++) { + if (gateway_chassis_equal(lrp_gwc[n], + lrp_gwc_c[n], + port_binding->gateway_chassis[i])) { + break; /* we found a match */ + } + } + + /* if no Port_Binding gateway chassis matched for the entry... */ + if (i == port_binding->n_gateway_chassis) { + free(lrp_gwc_c); + free(lrp_gwc); + return true; /* found no match for this gateway chassis on lrp */ + } + } + + /* no need for update, all ports matched */ + free(lrp_gwc_c); + free(lrp_gwc); + return false; +} + +/* This functions translates the gw chassis on the nb database + * to sb database entries, the only difference is that SB database + * Gateway_Chassis table references the chassis directly instead + * of using the name */ static void -ovn_port_update_sbrec(const struct ovn_port *op, +copy_gw_chassis_from_nbrp_to_sbpb( + struct northd_context *ctx, + const struct nbrec_logical_router_port *lrp, + const struct chassis_index *chassis_index, + const struct sbrec_port_binding *port_binding) { + + if (!lrp || !port_binding || !lrp->n_gateway_chassis) { + return; + } + + struct sbrec_gateway_chassis **gw_chassis = NULL; + int n_gwc = 0; + int n; + + /* XXX: This can be improved. This code will generate a set of new + * Gateway_Chassis and push them all in a single transaction, instead + * this would be more optimal if we just add/update/remove the rows in + * the southbound db that need to change. We don't expect lots of + * changes to the Gateway_Chassis table, but if that proves to be wrong + * we should optimize this. */ + for (n = 0; n < lrp->n_gateway_chassis; n++) { + struct nbrec_gateway_chassis *lrp_gwc = lrp->gateway_chassis[n]; + if (!lrp_gwc->chassis_name) { + continue; + } + + const struct sbrec_chassis *chassis = + chassis_lookup_by_name(chassis_index, lrp_gwc->chassis_name); + + if (!chassis) { + continue; + } + + gw_chassis = xrealloc(gw_chassis, (n_gwc + 1) * sizeof *gw_chassis); + + struct sbrec_gateway_chassis *pb_gwc = + sbrec_gateway_chassis_insert(ctx->ovnsb_txn); + + sbrec_gateway_chassis_set_name(pb_gwc, lrp_gwc->name); + sbrec_gateway_chassis_set_priority(pb_gwc, lrp_gwc->priority); + sbrec_gateway_chassis_set_chassis(pb_gwc, chassis); + sbrec_gateway_chassis_set_options(pb_gwc, &lrp_gwc->options); + sbrec_gateway_chassis_set_external_ids(pb_gwc, &lrp_gwc->external_ids); + + gw_chassis[n_gwc++] = pb_gwc; + } + sbrec_port_binding_set_gateway_chassis(port_binding, gw_chassis, n_gwc); + free(gw_chassis); +} + +static void +ovn_port_update_sbrec(struct northd_context *ctx, + const struct ovn_port *op, + const struct chassis_index *chassis_index, struct hmap *chassis_qdisc_queues) { sbrec_port_binding_set_datapath(op->sb, op->od->sb); @@ -1700,8 +1850,69 @@ ovn_port_update_sbrec(const struct ovn_port *op, if (op->derived) { const char *redirect_chassis = smap_get(&op->nbrp->options, "redirect-chassis"); - if (redirect_chassis) { + if (op->nbrp->n_gateway_chassis && redirect_chassis) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_WARN_RL( + &rl, "logical router port %s has both options:" + "redirect-chassis and gateway_chassis populated " + "redirect-chassis will be ignored in favour of " + "gateway chassis", op->nbrp->name); + } + + if (op->nbrp->n_gateway_chassis) { + if (sbpb_gw_chassis_needs_update(op->sb, op->nbrp, + chassis_index)) { + copy_gw_chassis_from_nbrp_to_sbpb(ctx, op->nbrp, + chassis_index, op->sb); + } + + } else if (redirect_chassis) { + /* XXX: Keep the "redirect-chassis" option on the Port_Binding + * for compatibility purposes until ovn-controller implements + * Gateway_Chassis handling */ smap_add(&new, "redirect-chassis", redirect_chassis); + + /* Handle ports that had redirect-chassis option attached + * to them for backwards compatibility */ + const struct sbrec_chassis *chassis = + chassis_lookup_by_name(chassis_index, redirect_chassis); + if (chassis) { + /* If we found the chassis, and the gw chassis on record + * differs from what we expect go ahead and update */ + if (op->sb->n_gateway_chassis !=1 + || strcmp(op->sb->gateway_chassis[0]->chassis->name, + chassis->name) + || op->sb->gateway_chassis[0]->priority != 0) { + /* Construct a single Gateway_Chassis entry on the + * Port_Binding attached to the redirect_chassis + * name */ + struct sbrec_gateway_chassis *gw_chassis = + sbrec_gateway_chassis_insert(ctx->ovnsb_txn); + + char *gwc_name = xasprintf("%s_%s", op->nbrp->name, + chassis->name); + + /* XXX: Again, here, we could just update an existing + * Gateway_Chassis, instead of creating a new one + * and replacing it */ + sbrec_gateway_chassis_set_name(gw_chassis, gwc_name); + sbrec_gateway_chassis_set_priority(gw_chassis, 0); + sbrec_gateway_chassis_set_chassis(gw_chassis, chassis); + sbrec_gateway_chassis_set_external_ids(gw_chassis, + &op->nbrp->external_ids); + sbrec_port_binding_set_gateway_chassis(op->sb, + &gw_chassis, 1); + free(gwc_name); + } + } else { + VLOG_WARN("chassis name '%s' from redirect from logical " + " router port '%s' redirect-chassis not found", + redirect_chassis, op->nbrp->name); + if (op->sb->n_gateway_chassis) { + sbrec_port_binding_set_gateway_chassis(op->sb, NULL, + 0); + } + } } smap_add(&new, "distributed-port", op->nbrp->name); } else { @@ -1845,7 +2056,7 @@ cleanup_mac_bindings(struct northd_context *ctx, struct hmap *ports) * datapaths. */ static void build_ports(struct northd_context *ctx, struct hmap *datapaths, - struct hmap *ports) + const struct chassis_index *chassis_index, struct hmap *ports) { struct ovs_list sb_only, nb_only, both; struct hmap tag_alloc_table = HMAP_INITIALIZER(&tag_alloc_table); @@ -1863,7 +2074,7 @@ build_ports(struct northd_context *ctx, struct hmap *datapaths, if (op->nbsp) { tag_alloc_create_new_tag(&tag_alloc_table, op->nbsp); } - ovn_port_update_sbrec(op, &chassis_qdisc_queues); + ovn_port_update_sbrec(ctx, op, chassis_index, &chassis_qdisc_queues); add_tnlid(&op->od->port_tnlids, op->sb->tunnel_key); if (op->sb->tunnel_key > op->od->port_key_hint) { @@ -1879,7 +2090,7 @@ build_ports(struct northd_context *ctx, struct hmap *datapaths, } op->sb = sbrec_port_binding_insert(ctx->ovnsb_txn); - ovn_port_update_sbrec(op, &chassis_qdisc_queues); + ovn_port_update_sbrec(ctx, op, chassis_index, &chassis_qdisc_queues); sbrec_port_binding_set_logical_port(op->sb, op->key); sbrec_port_binding_set_tunnel_key(op->sb, tunnel_key); @@ -5606,14 +5817,15 @@ sync_dns_entries(struct northd_context *ctx, struct hmap *datapaths) static void -ovnnb_db_run(struct northd_context *ctx, struct ovsdb_idl_loop *sb_loop) +ovnnb_db_run(struct northd_context *ctx, struct chassis_index *chassis_index, + struct ovsdb_idl_loop *sb_loop) { if (!ctx->ovnsb_txn || !ctx->ovnnb_txn) { return; } struct hmap datapaths, ports; build_datapaths(ctx, &datapaths); - build_ports(ctx, &datapaths, &ports); + build_ports(ctx, &datapaths, chassis_index, &ports); build_ipam(&datapaths, &ports); build_lflows(ctx, &datapaths, &ports); @@ -6183,6 +6395,17 @@ main(int argc, char *argv[]) add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_nat_addresses); ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_port_binding_col_chassis); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_port_binding_col_gateway_chassis); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_gateway_chassis_col_chassis); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_gateway_chassis_col_name); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_gateway_chassis_col_priority); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_gateway_chassis_col_external_ids); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_gateway_chassis_col_options); add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_external_ids); ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_mac_binding); @@ -6223,6 +6446,7 @@ main(int argc, char *argv[]) ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis); ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_nb_cfg); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_name); /* Main loop. */ exiting = false; @@ -6234,7 +6458,10 @@ main(int argc, char *argv[]) .ovnsb_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop), }; - ovnnb_db_run(&ctx, &ovnsb_idl_loop); + struct chassis_index chassis_index; + chassis_index_init(&chassis_index, ctx.ovnsb_idl); + + ovnnb_db_run(&ctx, &chassis_index, &ovnsb_idl_loop); ovnsb_db_run(&ctx, &ovnsb_idl_loop); if (ctx.ovnsb_txn) { check_and_add_supported_dhcp_opts_to_sb_db(&ctx); @@ -6254,6 +6481,8 @@ main(int argc, char *argv[]) if (should_service_stop()) { exiting = true; } + + chassis_index_destroy(&chassis_index); } unixctl_server_destroy(unixctl); diff --git a/tests/automake.mk b/tests/automake.mk index 3118bbc27..58520a8f9 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -94,6 +94,7 @@ TESTSUITE_AT = \ tests/vtep-ctl.at \ tests/auto-attach.at \ tests/ovn.at \ + tests/ovn-northd.at \ tests/ovn-nbctl.at \ tests/ovn-sbctl.at \ tests/ovn-controller.at \ diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at new file mode 100644 index 000000000..d0e8bcd88 --- /dev/null +++ b/tests/ovn-northd.at @@ -0,0 +1,87 @@ +AT_BANNER([OVN northd]) +AT_SETUP([ovn -- check Gateway_Chassis propagation from NBDB to SBDB]) +AT_SKIP_IF([test $HAVE_PYTHON = no]) +ovn_start + +ovn-nbctl create Logical_Router name=R1 +ovn-sbctl chassis-add gw1 geneve 127.0.0.1 +ovn-sbctl chassis-add gw2 geneve 1.2.4.8 + +# Connect alice to R1 as distributed router gateway port on hv2 +ovn-nbctl lrp-add R1 alice 00:00:02:01:02:03 172.16.1.1/24 + +ovn-nbctl --wait=sb \ + --id=@gc0 create Gateway_Chassis name=alice_gw1 \ + chassis_name=gw1 \ + priority=20 -- \ + --id=@gc1 create Gateway_Chassis name=alice_gw2 \ + chassis_name=gw2 \ + priority=10 -- \ + set Logical_Router_Port alice 'gateway_chassis=[@gc0,@gc1]' + +nb_gwc1_uuid=`ovn-nbctl --bare --columns _uuid find Gateway_Chassis name="alice_gw1"` +gwc1_uuid=`ovn-sbctl --bare --columns _uuid find Gateway_Chassis name="alice_gw1"` +gwc2_uuid=`ovn-sbctl --bare --columns _uuid find Gateway_Chassis name="alice_gw2"` + + +echo "Port_Binding for cr-alice:" +ovn-sbctl find port_binding logical_port="cr-alice" +echo "Gateway_Chassis list:" +ovn-sbctl list Gateway_Chassis + +AT_CHECK([ovn-sbctl --bare --columns gateway_chassis find port_binding logical_port="cr-alice" | grep $gwc1_uuid | wc -l], [0], [1 +]) +AT_CHECK([ovn-sbctl --bare --columns gateway_chassis find port_binding logical_port="cr-alice" | grep $gwc2_uuid | wc -l], [0], [1 +]) + +# delete the 2nd Gateway_Chassis on NBDB for alice port + +ovn-nbctl --wait=sb set Logical_Router_Port alice gateway_chassis=${nb_gwc1_uuid} + +gwc1_uuid=`ovn-sbctl --bare --columns _uuid find Gateway_Chassis name="alice_gw1"` + +AT_CHECK([ovn-sbctl --bare --columns gateway_chassis find port_binding logical_port="cr-alice" | grep $gwc1_uuid | wc -l], [0], [1 +]) + +AT_CHECK([ovn-sbctl find Gateway_Chassis name=alice_gw2], [0], []) + +# delete all the gateway_chassis on NBDB for alice port + +ovn-nbctl --wait=sb clear Logical_Router_Port alice gateway_chassis + +# expect that the Gateway_Chassis doesn't exist anymore + +AT_CHECK([ovn-sbctl find Gateway_Chassis name=alice_gw1], [0], []) +AT_CHECK([ovn-sbctl find Gateway_Chassis name=alice_gw2], [0], []) + +AT_CLEANUP + +AT_SETUP([ovn -- check Gateway_Chassis propagation from NBDB to SBDB backwards compatibility]) +AT_SKIP_IF([test $HAVE_PYTHON = no]) +ovn_start + +ovn-nbctl create Logical_Router name=R1 +ovn-sbctl chassis-add gw1 geneve 127.0.0.1 +ovn-sbctl chassis-add gw2 geneve 1.2.4.8 + +ovn-nbctl --wait=sb lrp-add R1 bob 00:00:02:01:02:03 172.16.1.1/24 \ + -- set Logical_Router_Port bob options:redirect-chassis="gw1" + + +# It should be converted to Gateway_Chassis entries in SBDB, and +# still redirect-chassis is kept for backwards compatibility + +gwc1_uuid=`ovn-sbctl --bare --columns _uuid find Gateway_Chassis name="bob_gw1"` + +AT_CHECK([ovn-sbctl --bare --columns options find port_binding logical_port="cr-bob" | grep 'redirect-chassis=gw1' | wc -l], [0], [1 +]) +AT_CHECK([ovn-sbctl --bare --columns gateway_chassis find port_binding logical_port="cr-bob" | grep $gwc1_uuid | wc -l], [0], [1 +]) + +ovn-nbctl --wait=sb remove Logical_Router_Port bob options redirect-chassis + +# expect that the Gateway_Chassis doesn't exist anymore + +AT_CHECK([ovn-sbctl find Gateway_Chassis name=bob_gw1], [0], []) + +AT_CLEANUP diff --git a/tests/testsuite.at b/tests/testsuite.at index c7febc61c..3e2eb6dd9 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -72,6 +72,7 @@ m4_include([tests/vlog.at]) m4_include([tests/vtep-ctl.at]) m4_include([tests/auto-attach.at]) m4_include([tests/ovn.at]) +m4_include([tests/ovn-northd.at]) m4_include([tests/ovn-nbctl.at]) m4_include([tests/ovn-sbctl.at]) m4_include([tests/ovn-controller.at]) -- 2.39.5