From patchwork Tue Mar 5 15:53:12 2019
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Numan Siddique
+ This column is ignored if the column
+ .
+ is set.
+
If set, this indicates that this logical router port represents
a distributed gateway port that connects this router to a logical
@@ -1549,6 +1555,24 @@
+ If set, this indicates that this logical router port represents
+ a distributed gateway port that connects this router to a logical
+ switch with a localnet port. There may be at most one such
+ logical router port on each logical router. The HA chassis which
+ are part of the HA chassis group will provide the gateway high
+ availability. Please see the for
+ more details.
+
+ When this column is set, the column
+ will
+ be ignored.
+
The IP addresses and netmasks of the router. For example,
@@ -2605,4 +2629,55 @@
+
+ This should only be populated for ports with
+ set to chassisredirect
.
+ This column defines the HA chassis group with a list of
+ HA chassis used as gateways where traffic will be redirected
+ through.
+
A number that represents the logical port in the key (e.g. STT key or
@@ -3339,4 +3349,57 @@ tcp.flags = RST;
ha-chassis-group-add
groupHA_Chassis_Group
+ table named group
.
+ ha-chassis-group-del
groupgroup
. It is an error if
+ group
does not exist.
+ ha-chassis-group-list
group
along with the
+ HA chassis
if any associated with it.
+ ha-chassis-group-add-chassis
group
+ chassis prioritychassis
to the
+ HA Chassis group group
with the specified priority.
+ If the chassis
already exists, then the
+ priority
is updated.
+ The chassis
should be the name of the chassis in the
+ OVN_Southbound
.
+ ha-chassis-group-remove-chassis
group
+ chassischassis
from the HA chassis
+ group group
. It is an error if chassis
does
+ not exist.
+ These commands query and modify the contents of ovsdb
tables.
They are a slight abstraction of the ovsdb
interface and
diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c
index 8a72e9574..8f4e96d6e 100644
--- a/ovn/utilities/ovn-nbctl.c
+++ b/ovn/utilities/ovn-nbctl.c
@@ -694,6 +694,15 @@ Port group commands:\n\
pg-set-ports PG PORTS Set PORTS on port group PG\n\
pg-del PG Delete port group PG\n\
\n\
+HA chassis group commands:\n\
+ ha-chassis-group-add GRP Create an HA chassis group GRP\n\
+ ha-chassis-group-del GRP Delete the HA chassis group GRP\n\
+ ha-chassis-group-list List the HA chassis groups\n\
+ ha-chassis-group-add-chassis GRP CHASSIS [PRIORITY] Adds an HA\
+chassis with optional PRIORITY to the HA chassis group GRP\n\
+ ha-chassis-group-del-chassis GRP CHASSIS Deletes the HA chassis\
+CHASSIS from the HA chassis group GRP\n\
+\n\
%s\
%s\
\n\
@@ -4756,6 +4765,201 @@ cmd_pg_del(struct ctl_context *ctx)
nbrec_port_group_delete(pg);
}
+static const struct nbrec_ha_chassis_group*
+ha_chassis_group_by_name_or_uuid(struct ctl_context *ctx, const char *id,
+ bool must_exist)
+{
+ struct uuid ch_grp_uuid;
+ const struct nbrec_ha_chassis_group *ha_ch_grp = NULL;
+ bool is_uuid = uuid_from_string(&ch_grp_uuid, id);
+ if (is_uuid) {
+ ha_ch_grp = nbrec_ha_chassis_group_get_for_uuid(ctx->idl,
+ &ch_grp_uuid);
+ }
+
+ if (!ha_ch_grp) {
+ const struct nbrec_ha_chassis_group *iter;
+ NBREC_HA_CHASSIS_GROUP_FOR_EACH (iter, ctx->idl) {
+ if (!strcmp(iter->name, id)) {
+ ha_ch_grp = iter;
+ break;
+ }
+ }
+ }
+
+ if (!ha_ch_grp && must_exist) {
+ ctx->error = xasprintf("%s: ha_chassi_group %s not found",
+ id, is_uuid ? "UUID" : "name");
+ }
+
+ return ha_ch_grp;
+}
+
+static void
+cmd_ha_ch_grp_add(struct ctl_context *ctx)
+{
+ const char *name = ctx->argv[1];
+ struct nbrec_ha_chassis_group *ha_ch_grp =
+ nbrec_ha_chassis_group_insert(ctx->txn);
+ nbrec_ha_chassis_group_set_name(ha_ch_grp, name);
+}
+
+static void
+cmd_ha_ch_grp_del(struct ctl_context *ctx)
+{
+ const char *name_or_id = ctx->argv[1];
+
+ const struct nbrec_ha_chassis_group *ha_ch_grp =
+ ha_chassis_group_by_name_or_uuid(ctx, name_or_id, true);
+
+ if (ha_ch_grp) {
+ nbrec_ha_chassis_group_delete(ha_ch_grp);
+ }
+}
+
+static void
+cmd_ha_ch_grp_list(struct ctl_context *ctx)
+{
+ const struct nbrec_ha_chassis_group *ha_ch_grp;
+
+ NBREC_HA_CHASSIS_GROUP_FOR_EACH (ha_ch_grp, ctx->idl) {
+ ds_put_format(&ctx->output, UUID_FMT " (%s)\n",
+ UUID_ARGS(&ha_ch_grp->header_.uuid), ha_ch_grp->name);
+ const struct nbrec_ha_chassis *ha_ch;
+ for (size_t i = 0; i < ha_ch_grp->n_ha_chassis; i++) {
+ ha_ch = ha_ch_grp->ha_chassis[i];
+ ds_put_format(&ctx->output,
+ " "UUID_FMT " (%s)\n"
+ " priority %lu\n\n",
+ UUID_ARGS(&ha_ch->header_.uuid), ha_ch->chassis_name,
+ ha_ch->priority);
+ }
+ ds_put_cstr(&ctx->output, "\n");
+ }
+}
+
+static void
+cmd_ha_ch_grp_add_chassis(struct ctl_context *ctx)
+{
+ const struct nbrec_ha_chassis_group *ha_ch_grp =
+ ha_chassis_group_by_name_or_uuid(ctx, ctx->argv[1], true);
+
+ if (!ha_ch_grp) {
+ return;
+ }
+
+ const char *chassis_name = ctx->argv[2];
+ int64_t priority;
+ char *error = parse_priority(ctx->argv[3], &priority);
+ if (error) {
+ ctx->error = error;
+ return;
+ }
+
+ struct nbrec_ha_chassis *ha_chassis = NULL;
+ for (size_t i = 0; i < ha_ch_grp->n_ha_chassis; i++) {
+ if (!strcmp(ha_ch_grp->ha_chassis[i]->chassis_name, chassis_name)) {
+ ha_chassis = ha_ch_grp->ha_chassis[i];
+ break;
+ }
+ }
+
+ if (ha_chassis) {
+ nbrec_ha_chassis_set_priority(ha_chassis, priority);
+ return;
+ }
+
+ ha_chassis = nbrec_ha_chassis_insert(ctx->txn);
+ nbrec_ha_chassis_set_chassis_name(ha_chassis, chassis_name);
+ nbrec_ha_chassis_set_priority(ha_chassis, priority);
+
+ nbrec_ha_chassis_group_verify_ha_chassis(ha_ch_grp);
+
+ struct nbrec_ha_chassis **new_ha_chs =
+ xmalloc(sizeof *new_ha_chs * (ha_ch_grp->n_ha_chassis + 1));
+ nullable_memcpy(new_ha_chs, ha_ch_grp->ha_chassis,
+ sizeof *new_ha_chs * ha_ch_grp->n_ha_chassis);
+ new_ha_chs[ha_ch_grp->n_ha_chassis] =
+ CONST_CAST(struct nbrec_ha_chassis *, ha_chassis);
+ nbrec_ha_chassis_group_set_ha_chassis(ha_ch_grp, new_ha_chs,
+ ha_ch_grp->n_ha_chassis + 1);
+ free(new_ha_chs);
+}
+
+static void
+cmd_ha_ch_grp_remove_chassis(struct ctl_context *ctx)
+{
+ const struct nbrec_ha_chassis_group *ha_ch_grp =
+ ha_chassis_group_by_name_or_uuid(ctx, ctx->argv[1], true);
+
+ if (!ha_ch_grp) {
+ return;
+ }
+
+ const char *chassis_name = ctx->argv[2];
+ struct nbrec_ha_chassis *ha_chassis = NULL;
+ size_t idx = 0;
+ for (size_t i = 0; i < ha_ch_grp->n_ha_chassis; i++) {
+ if (!strcmp(ha_ch_grp->ha_chassis[i]->chassis_name, chassis_name)) {
+ ha_chassis = ha_ch_grp->ha_chassis[i];
+ idx = i;
+ break;
+ }
+ }
+
+ if (!ha_chassis) {
+ ctx->error = xasprintf("%s: ha chassis not found in %s ha "
+ "chassis group", chassis_name, ctx->argv[1]);
+ return;
+ }
+
+ struct nbrec_ha_chassis **new_ha_ch
+ = xmemdup(ha_ch_grp->ha_chassis,
+ sizeof *new_ha_ch * ha_ch_grp->n_ha_chassis);
+ new_ha_ch[idx] = new_ha_ch[ha_ch_grp->n_ha_chassis - 1];
+ nbrec_ha_chassis_group_verify_ha_chassis(ha_ch_grp);
+ nbrec_ha_chassis_group_set_ha_chassis(ha_ch_grp, new_ha_ch,
+ ha_ch_grp->n_ha_chassis - 1);
+ free(new_ha_ch);
+ nbrec_ha_chassis_delete(ha_chassis);
+}
+
+static void
+cmd_ha_ch_grp_set_chassis_prio(struct ctl_context *ctx)
+{
+ const struct nbrec_ha_chassis_group *ha_ch_grp =
+ ha_chassis_group_by_name_or_uuid(ctx, ctx->argv[1], true);
+
+ if (!ha_ch_grp) {
+ return;
+ }
+
+ int64_t priority;
+ char *error = parse_priority(ctx->argv[3], &priority);
+ if (error) {
+ ctx->error = error;
+ return;
+ }
+
+ const char *chassis_name = ctx->argv[2];
+ struct nbrec_ha_chassis *ha_chassis = NULL;
+
+ for (size_t i = 0; i < ha_ch_grp->n_ha_chassis; i++) {
+ if (!strcmp(ha_ch_grp->ha_chassis[i]->chassis_name, chassis_name)) {
+ ha_chassis = ha_ch_grp->ha_chassis[i];
+ break;
+ }
+ }
+
+ if (!ha_chassis) {
+ ctx->error = xasprintf("%s: ha chassis not found in %s ha "
+ "chassis group", chassis_name, ctx->argv[1]);
+ return;
+ }
+
+ nbrec_ha_chassis_set_priority(ha_chassis, priority);
+}
+
static const struct ctl_table_class tables[NBREC_N_TABLES] = {
[NBREC_TABLE_DHCP_OPTIONS].row_ids
= {{&nbrec_logical_switch_port_col_name, NULL,
@@ -4790,6 +4994,9 @@ static const struct ctl_table_class tables[NBREC_N_TABLES] = {
= {&nbrec_port_group_col_name, NULL, NULL},
[NBREC_TABLE_ACL].row_ids[0] = {&nbrec_acl_col_name, NULL, NULL},
+
+ [NBREC_TABLE_HA_CHASSIS_GROUP].row_ids[0]
+ = {&nbrec_ha_chassis_group_col_name, NULL, NULL},
};
static char *
@@ -5230,6 +5437,20 @@ static const struct ctl_command_syntax nbctl_commands[] = {
{"pg-set-ports", 2, INT_MAX, "", NULL, cmd_pg_set_ports, NULL, "", RW },
{"pg-del", 1, 1, "", NULL, cmd_pg_del, NULL, "", RW },
+ /* HA chassis group commands. */
+ {"ha-chassis-group-add", 1, 1, "[CHASSIS GROUP]", NULL,
+ cmd_ha_ch_grp_add, NULL, "", RW },
+ {"ha-chassis-group-del", 1, 1, "[CHASSIS GROUP]", NULL,
+ cmd_ha_ch_grp_del, NULL, "", RW },
+ {"ha-chassis-group-list", 0, 0, "[CHASSIS GROUP]", NULL,
+ cmd_ha_ch_grp_list, NULL, "", RO },
+ {"ha-chassis-group-add-chassis", 3, 3, "[CHASSIS GROUP]", NULL,
+ cmd_ha_ch_grp_add_chassis, NULL, "", RW },
+ {"ha-chassis-group-remove-chassis", 2, 2, "[CHASSIS GROUP]", NULL,
+ cmd_ha_ch_grp_remove_chassis, NULL, "", RW },
+ {"ha-chassis-group-set-chassis-prio", 3, 3, "[CHASSIS GROUP]", NULL,
+ cmd_ha_ch_grp_set_chassis_prio, NULL, "", RW },
+
{NULL, 0, 0, NULL, NULL, NULL, NULL, "", RO},
};
diff --git a/ovn/utilities/ovn-sbctl.c b/ovn/utilities/ovn-sbctl.c
index ee97a4710..c5ff9318f 100644
--- a/ovn/utilities/ovn-sbctl.c
+++ b/ovn/utilities/ovn-sbctl.c
@@ -1189,6 +1189,12 @@ static const struct ctl_table_class tables[SBREC_N_TABLES] = {
[SBREC_TABLE_ADDRESS_SET].row_ids[0]
= {&sbrec_address_set_col_name, NULL, NULL},
+
+ [SBREC_TABLE_HA_CHASSIS_GROUP].row_ids[0]
+ = {&sbrec_ha_chassis_group_col_name, NULL, NULL},
+
+ [SBREC_TABLE_HA_CHASSIS].row_ids[0]
+ = {&sbrec_ha_chassis_col_chassis, NULL, NULL},
};
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 1878eb2df..b4e8995be 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -34,6 +34,33 @@ AT_CHECK([ovn-sbctl --bare --columns gateway_chassis find port_binding logical_p
AT_CHECK([ovn-sbctl --bare --columns gateway_chassis find port_binding logical_port="cr-alice" | grep $gwc2_uuid | wc -l], [0], [1
])
+# There should be one ha_chassis_group with the name "alice"
+ha_chassi_grp_name=`ovn-sbctl --bare --columns name find \
+ha_chassis_group name="alice"`
+
+AT_CHECK([test $ha_chassi_grp_name = alice])
+
+ha_chgrp_uuid=`ovn-sbctl --bare --columns _uuid find ha_chassis_group name=alice`
+
+AT_CHECK([ovn-sbctl --bare --columns ha_chassis_group find port_binding \
+logical_port="cr-alice" | grep $ha_chgrp_uuid | wc -l], [0], [1
+])
+
+ha_ch=`ovn-sbctl --bare --columns ha_chassis find ha_chassis_group`
+# Trim the spaces.
+ha_ch=`echo $ha_ch | sed 's/ //g'`
+
+ha_ch_list=''
+for i in `ovn-sbctl --bare --columns _uuid list ha_chassis | sort`
+do
+ ha_ch_list="$ha_ch_list $i"
+done
+
+# Trim the spaces.
+ha_ch_list=`echo $ha_ch_list | sed 's/ //g'`
+
+AT_CHECK([test "$ha_ch_list" = "$ha_ch"])
+
# delete the 2nd Gateway_Chassis on NBDB for alice port
ovn-nbctl --wait=sb set Logical_Router_Port alice gateway_chassis=${nb_gwc1_uuid}
@@ -45,6 +72,10 @@ AT_CHECK([ovn-sbctl --bare --columns gateway_chassis find port_binding logical_p
AT_CHECK([ovn-sbctl find Gateway_Chassis name=alice_gw2], [0], [])
+# There should be only 1 row in ha_chassis SB DB table.
+AT_CHECK([ovn-sbctl --bare --columns _uuid list ha_chassis | wc -l], [0], [1
+])
+
# delete all the gateway_chassis on NBDB for alice port
ovn-nbctl --wait=sb clear Logical_Router_Port alice gateway_chassis
@@ -54,6 +85,12 @@ ovn-nbctl --wait=sb clear Logical_Router_Port alice gateway_chassis
AT_CHECK([ovn-sbctl find Gateway_Chassis name=alice_gw1], [0], [])
AT_CHECK([ovn-sbctl find Gateway_Chassis name=alice_gw2], [0], [])
+# expect that the ha_chassis doesn't exist anymore
+AT_CHECK([ovn-sbctl list ha_chassis | wc -l], [0], [0
+])
+AT_CHECK([ovn-sbctl list ha_chassis_group | wc -l], [0], [0
+])
+
AT_CLEANUP
AT_SETUP([ovn -- check Gateway_Chassis propagation from NBDB to SBDB backwards compatibility])
@@ -301,3 +338,228 @@ as northd
OVS_APP_EXIT_AND_WAIT([ovn-northd])
AT_CLEANUP
+
+AT_SETUP([ovn -- check HA_Chassis_Group propagation from NBDB to SBDB])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+ovn_start
+
+ovn-nbctl --wait=sb ha-chassis-group-add hagrp1
+
+# ovn-northd should not create HA chassis group and HA chassis rows
+# unless the HA chassis group in OVN NB DB is associated to
+# a logical router port. ovn-northd still doesn't support
+# associating a HA chassis group to a logical router port.
+AT_CHECK([ovn-sbctl --bare --columns name find ha_chassis_group name="hagrp1" \
+| wc -l], [0], [0
+])
+
+ovn-nbctl --wait=sb ha-chassis-group-add-chassis hagrp1 ch1 30
+ovn-nbctl --wait=sb ha-chassis-group-add-chassis hagrp1 ch2 20
+ovn-nbctl --wait=sb ha-chassis-group-add-chassis hagrp1 ch3 10
+
+# There should be no HA_Chassis rows in SB DB.
+AT_CHECK([ovn-sbctl list ha_chassis | grep chassis | awk '{print $3}' \
+| grep -v '-' | wc -l ], [0], [0
+])
+
+# Add chassis ch1.
+ovn-sbctl chassis-add ch1 geneve 127.0.0.2
+
+OVS_WAIT_UNTIL([test 1 = `ovn-sbctl list chassis | grep ch1 | wc -l`])
+
+# There should be no HA_Chassis rows
+AT_CHECK([ovn-sbctl list ha_chassis | grep chassis | awk '{print $3}' \
+| grep -v '-' | wc -l ], [0], [0
+])
+
+ovn-nbctl ha-chassis-group-del hagrp1
+OVS_WAIT_UNTIL([test 0 = `ovn-sbctl list ha_chassis_group | wc -l`])
+OVS_WAIT_UNTIL([test 0 = `ovn-sbctl list ha_chassis | wc -l`])
+
+# Create a logical router port and attach Gateway chassis.
+# ovn-northd should create HA chassis group rows in SB DB.
+ovn-nbctl lr-add lr0
+
+ovn-nbctl lrp-add lr0 lr0-public 00:00:20:20:12:13 172.168.0.100/24
+ovn-nbctl lrp-set-gateway-chassis lr0-public ch1 20
+
+OVS_WAIT_UNTIL([test 1 = `ovn-sbctl --bare --columns name find ha_chassis_group \
+name="lr0-public" | wc -l`])
+
+OVS_WAIT_UNTIL([test 1 = `ovn-sbctl --bare --columns _uuid \
+find ha_chassis | wc -l`])
+
+ovn-nbctl lrp-set-gateway-chassis lr0-public ch2 10
+
+ovn-sbctl --bare --columns _uuid find ha_chassis
+OVS_WAIT_UNTIL([test 2 = `ovn-sbctl list ha_chassis | grep chassis | wc -l`])
+
+# Test if 'ref_chassis' column is properly set or not in
+# SB DB ha_chassis_group.
+ovn-nbctl ls-add sw0
+ovn-nbctl lsp-add sw0 sw0-p1
+
+ovn-sbctl chassis-add ch2 geneve 127.0.0.3
+ovn-sbctl chassis-add ch3 geneve 127.0.0.4
+ovn-sbctl chassis-add comp1 geneve 127.0.0.5
+ovn-sbctl chassis-add comp2 geneve 127.0.0.6
+
+ovn-nbctl lrp-add lr0 lr0-sw0 00:00:20:20:12:14 10.0.0.1/24
+ovn-nbctl lsp-add sw0 sw0-lr0
+ovn-nbctl lsp-set-type sw0-lr0 router
+ovn-nbctl lsp-set-addresses sw0-lr0 router
+ovn-nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0
+
+ovn-sbctl lsp-bind sw0-p1 comp1
+OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up sw0-p1` = xup])
+
+comp1_ch_uuid=`ovn-sbctl --bare --columns _uuid find chassis name="comp1"`
+comp2_ch_uuid=`ovn-sbctl --bare --columns _uuid find chassis name="comp2"`
+ch2_ch_uuid=`ovn-sbctl --bare --columns _uuid find chassis name="comp1"`
+
+echo "comp1_ch_uuid = $comp1_ch_uuid"
+OVS_WAIT_UNTIL(
+ [ref_ch_list=`ovn-sbctl --bare --columns ref_chassis find ha_chassis_group | sort`
+ # Trim the spaces.
+ ref_ch_list=`echo $ref_ch_list | sed 's/ //g'`
+ test "$comp1_ch_uuid" = "$ref_ch_list"])
+
+# unbind sw0-p1
+ovn-sbctl lsp-unbind sw0-p1
+OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up sw0-p1` = xdown])
+OVS_WAIT_UNTIL(
+ [ref_ch_list=`ovn-sbctl --bare --columns ref_chassis find ha_chassis_group | sort`
+ # Trim the spaces.
+ ref_ch_list=`echo $ref_ch_list | sed 's/ //g'`
+ test "" = "$ref_ch_list"])
+
+# Bind sw0-p1 in comp2
+ovn-sbctl lsp-bind sw0-p1 comp2
+OVS_WAIT_UNTIL(
+ [ref_ch_list=`ovn-sbctl --bare --columns ref_chassis find ha_chassis_group | sort`
+ # Trim the spaces.
+ ref_ch_list=`echo $ref_ch_list | sed 's/ //g'`
+ test "$comp2_ch_uuid" = "$ref_ch_list"])
+
+ovn-nbctl ls-add sw1
+ovn-nbctl lsp-add sw1 sw1-p1
+ovn-nbctl lr-add lr1
+ovn-nbctl lrp-add lr1 lr1-sw1 00:00:20:20:12:15 20.0.0.1/24
+ovn-nbctl lsp-add sw1 sw1-lr1
+ovn-nbctl lsp-set-type sw1-lr1 router
+ovn-nbctl lsp-set-addresses sw1-lr1 router
+ovn-nbctl lsp-set-options sw1-lr1 router-port=lr1-sw1
+
+# Bind sw1-p1 in comp1.
+ovn-sbctl lsp-bind sw1-p1 comp1
+# Wait until sw1-p1 is up
+OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up sw1-p1` = xup])
+
+# sw1-p1 is not connected to lr0. So comp1 should not be in 'ref_chassis'
+OVS_WAIT_UNTIL(
+ [ref_ch_list=`ovn-sbctl --bare --columns ref_chassis find ha_chassis_group | sort`
+ # Trim the spaces.
+ ref_ch_list=`echo $ref_ch_list | sed 's/ //g'`
+ test "$comp2_ch_uuid" = "$ref_ch_list"])
+
+# Now attach sw0 to lr1
+ovn-nbctl lrp-add lr1 lr1-sw0 00:00:20:20:12:16 10.0.0.10/24
+ovn-nbctl lsp-add sw0 sw0-lr1
+ovn-nbctl lsp-set-type sw0-lr1 router
+ovn-nbctl lsp-set-addresses sw0-lr1 router
+ovn-nbctl lsp-set-options sw0-lr1 router-port=lr1-sw0
+
+# Both comp1 and comp2 should be in 'ref_chassis' as sw1 is indirectly
+# connected to lr0
+exp_ref_ch_list=''
+for i in `ovn-sbctl --bare --columns _uuid list chassis | sort`
+do
+ if test $i = $comp1_ch_uuid; then
+ exp_ref_ch_list="${exp_ref_ch_list}$i"
+ elif test $i = $comp2_ch_uuid; then
+ exp_ref_ch_list="${exp_ref_ch_list}$i"
+ fi
+done
+
+OVS_WAIT_UNTIL(
+ [ref_ch_list=`ovn-sbctl --bare --columns ref_chassis find ha_chassis_group | sort`
+ # Trim the spaces.
+ ref_ch_list=`echo $ref_ch_list | sed 's/ //g'`
+ test "$exp_ref_ch_list" = "$ref_ch_list"])
+
+# Unind sw1-p1. comp2 should not be in the ref_chassis.
+ovn-sbctl lsp-unbind sw1-p1
+OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up sw1-p1` = xdown])
+OVS_WAIT_UNTIL(
+ [ref_ch_list=`ovn-sbctl --bare --columns ref_chassis find ha_chassis_group | sort`
+ # Trim the spaces.
+ ref_ch_list=`echo $ref_ch_list | sed 's/ //g'`
+ test "$comp2_ch_uuid" = "$ref_ch_list"])
+
+# Create sw2 and attach it to lr2
+ovn-nbctl ls-add sw2
+ovn-nbctl lsp-add sw2 sw2-p1
+ovn-nbctl lr-add lr2
+ovn-nbctl lrp-add lr2 lr2-sw2 00:00:20:20:12:17 30.0.0.1/24
+ovn-nbctl lsp-add sw2 sw2-lr2
+ovn-nbctl lsp-set-type sw2-lr2 router
+ovn-nbctl lsp-set-addresses sw2-lr2 router
+ovn-nbctl lsp-set-options sw2-lr2 router-port=lr2-sw2
+
+# Bind sw2-p1 to comp1
+ovn-sbctl lsp-bind sw2-p1 comp1
+# Wait until sw2-p1 is up
+OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up sw2-p1` = xup])
+
+# sw2-p1 is not connected to lr0. So comp1 should not be in 'ref_chassis'
+OVS_WAIT_UNTIL(
+ [ref_ch_list=`ovn-sbctl --bare --columns ref_chassis find ha_chassis_group | sort`
+ # Trim the spaces.
+ ref_ch_list=`echo $ref_ch_list | sed 's/ //g'`
+ test "$comp2_ch_uuid" = "$ref_ch_list"])
+
+# Now attach sw1 to lr2. With this sw2-p1 is indirectly connected to lr0.
+ovn-nbctl lrp-add lr2 lr2-sw1 00:00:20:20:12:18 20.0.0.10/24
+ovn-nbctl lsp-add sw1 sw1-lr2
+ovn-nbctl lsp-set-type sw1-lr2 router
+ovn-nbctl lsp-set-addresses sw1-lr2 router
+ovn-nbctl lsp-set-options sw1-lr2 router-port=lr2-sw1
+
+# sw2-p1 is indirectly connected to lr0. So comp1 (and comp2) should be in
+# 'ref_chassis'
+OVS_WAIT_UNTIL(
+ [ref_ch_list=`ovn-sbctl --bare --columns ref_chassis find ha_chassis_group | sort`
+ # Trim the spaces.
+ ref_ch_list=`echo $ref_ch_list | sed 's/ //g'`
+ test "$exp_ref_ch_list" = "$ref_ch_list"])
+
+# Create sw0-p2 and bind it to comp1
+ovn-nbctl lsp-add sw0 sw0-p2
+ovn-sbctl lsp-bind sw0-p2 comp1
+OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up sw0-p2` = xup])
+OVS_WAIT_UNTIL(
+ [ref_ch_list=`ovn-sbctl --bare --columns ref_chassis find ha_chassis_group | sort`
+ # Trim the spaces.
+ ref_ch_list=`echo $ref_ch_list | sed 's/ //g'`
+ test "$exp_ref_ch_list" = "$ref_ch_list"])
+
+# unbind sw0-p2
+ovn-sbctl lsp-unbind sw0-p2
+OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up sw0-p2` = xdown])
+OVS_WAIT_UNTIL(
+ [ref_ch_list=`ovn-sbctl --bare --columns ref_chassis find ha_chassis_group | sort`
+ # Trim the spaces.
+ ref_ch_list=`echo $ref_ch_list | sed 's/ //g'`
+ test "$exp_ref_ch_list" = "$ref_ch_list"])
+
+# Delete lr1-sw0. comp1 should be deleted from ref_chassis as there is no link
+# from sw1 and sw2 to lr0.
+ovn-nbctl lrp-del lr1-sw0
+
+OVS_WAIT_UNTIL(
+ [ref_ch_list=`ovn-sbctl --bare --columns ref_chassis find ha_chassis_group | sort`
+ # Trim the spaces.
+ ref_ch_list=`echo $ref_ch_list | sed 's/ //g'`
+ test "$comp2_ch_uuid" = "$ref_ch_list"])
+
+AT_CLEANUP
diff --git a/tests/ovn.at b/tests/ovn.at
index ec79651bd..dedbadd1b 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -8386,6 +8386,16 @@ as ext1 ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
AT_CHECK([ovn-nbctl --timeout=3 --wait=sb sync], [0], [ignore])
+# hv1 should be in 'ref_chassis' of the ha_chasssi_group as logical
+# switch 'foo' can reach the router 'R1' (which has gw router port)
+# via foo1 -> foo -> R0 -> join -> R1
+hv1_ch_uuid=`ovn-sbctl --bare --columns _uuid find chassis name="hv1"`
+OVS_WAIT_UNTIL(
+ [ref_ch_list=`ovn-sbctl --bare --columns ref_chassis find ha_chassis_group | sort`
+ # Trim the spaces.
+ ref_ch_list=`echo $ref_ch_list | sed 's/ //g'`
+ test "$hv1_ch_uuid" = "$ref_ch_list"])
+
# Allow some time for ovn-northd and ovn-controller to catch up.
# XXX This should be more systematic.
sleep 2
@@ -9754,6 +9764,32 @@ echo "------ Port_Binding chassisredirect -------"
ovn-sbctl find Port_Binding type=chassisredirect
echo "-------------------------------------------"
+# There should be one ha_chassis_group with the name "outside"
+ha_chassi_grp_name=`ovn-sbctl --bare --columns name find \
+ha_chassis_group name="outside"`
+
+AT_CHECK([test $ha_chassi_grp_name = outside])
+
+# There should be 2 ha_chassis rows in SB DB.
+AT_CHECK([ovn-sbctl list ha_chassis | grep chassis | awk '{print $3}' \
+| grep '-' | wc -l ], [0], [2
+])
+
+ha_ch=`ovn-sbctl --bare --columns ha_chassis find ha_chassis_group`
+# Trim the spaces.
+ha_ch=`echo $ha_ch | sed 's/ //g'`
+
+ha_ch_list=''
+for i in `ovn-sbctl --bare --columns _uuid list ha_chassis | sort`
+do
+ ha_ch_list="$ha_ch_list $i"
+done
+
+# Trim the spaces.
+ha_ch_list=`echo $ha_ch_list | sed 's/ //g'`
+
+AT_CHECK([test "$ha_ch_list" = "$ha_ch"])
+
for chassis in gw1 gw2 hv1 hv2; do
as $chassis
echo "------ $chassis dump ----------"
@@ -9798,33 +9834,56 @@ as hv2 ovs-ofctl dump-flows br-int table=32
gw1_chassis=$(ovn-sbctl --bare --columns=_uuid find Chassis name=gw1)
gw2_chassis=$(ovn-sbctl --bare --columns=_uuid find Chassis name=gw2)
-AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=32 | grep active_backup | grep slaves:$hv1_gw1_ofport,$hv1_gw2_ofport | wc -l], [0], [1
+OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int table=32 | \
+grep active_backup | grep slaves:$hv1_gw1_ofport,$hv1_gw2_ofport \
+| wc -l], [0], [1
])
-AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=32 | grep active_backup | grep slaves:$hv2_gw1_ofport,$hv2_gw2_ofport | wc -l], [0], [1
+OVS_WAIT_UNTIL([as hv2 ovs-ofctl dump-flows br-int table=32 | \
+grep active_backup | grep slaves:$hv2_gw1_ofport,$hv2_gw2_ofport \
+| wc -l], [0], [1
])
-sleep 3 # let BFD sessions settle so we get the right flows on the right chassis
-
# make sure that flows for handling the outside router port reside on gw1
-AT_CHECK([as gw1 ovs-ofctl dump-flows br-int table=24 | grep 00:00:02:01:02:04 | wc -l], [0], [[1
+OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=24 | \
+grep 00:00:02:01:02:04 | wc -l], [0], [[1
]])
-AT_CHECK([as gw2 ovs-ofctl dump-flows br-int table=24 | grep 00:00:02:01:02:04 | wc -l], [0], [[0
+
+OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=24 | \
+grep 00:00:02:01:02:04 | wc -l], [0], [[0
]])
# make sure ARP responder flows for outside router port reside on gw1 too
-AT_CHECK([as gw1 ovs-ofctl dump-flows br-int table=9 | grep arp_tpa=192.168.0.101 | wc -l], [0], [[1
+OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=9 | \
+grep arp_tpa=192.168.0.101 | wc -l], [0], [[1
]])
-AT_CHECK([as gw2 ovs-ofctl dump-flows br-int table=9 | grep arp_tpa=192.168.0.101 | wc -l], [0], [[0
+OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=9 | grep arp_tpa=192.168.0.101 | wc -l], [0], [[0
]])
-
-
# check that the chassis redirect port has been claimed by the gw1 chassis
-AT_CHECK([ovn-sbctl --columns chassis --bare find Port_Binding logical_port=cr-outside | grep $gw1_chassis | wc -l],
- [0],[[1
+OVS_WAIT_UNTIL([ovn-sbctl --columns chassis --bare find Port_Binding \
+logical_port=cr-outside | grep $gw1_chassis | wc -l], [0],[[1
]])
+hv1_ch_uuid=`ovn-sbctl --bare --columns _uuid find chassis name="hv1"`
+hv2_ch_uuid=`ovn-sbctl --bare --columns _uuid find chassis name="hv2"`
+
+exp_ref_ch_list=''
+for i in `ovn-sbctl --bare --columns _uuid list chassis | sort`
+do
+ if test $i = $hv1_ch_uuid; then
+ exp_ref_ch_list="${exp_ref_ch_list}$i"
+ elif test $i = $hv2_ch_uuid; then
+ exp_ref_ch_list="${exp_ref_ch_list}$i"
+ fi
+done
+
+OVS_WAIT_UNTIL(
+ [ref_ch_list=`ovn-sbctl --bare --columns ref_chassis find ha_chassis_group | sort`
+ # Trim the spaces.
+ ref_ch_list=`echo $ref_ch_list | sed 's/ //g'`
+ test "$exp_ref_ch_list" = "$ref_ch_list"])
+
# at this point, we invert the priority of the gw chassis between gw1 and gw2
@@ -9839,15 +9898,19 @@ ovn-nbctl --id=@gc0 create Gateway_Chassis \
ovn-nbctl --wait=hv --timeout=3 sync
# we make sure that the hypervisors noticed, and inverted the slave ports
-AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=32 | grep active_backup | grep slaves:$hv1_gw2_ofport,$hv1_gw1_ofport | wc -l], [0], [1
+OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int table=32 | \
+grep active_backup | grep slaves:$hv1_gw2_ofport,$hv1_gw1_ofport \
+| wc -l], [0], [1
])
-AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=32 | grep active_backup | grep slaves:$hv2_gw2_ofport,$hv2_gw1_ofport | wc -l], [0], [1
+OVS_WAIT_UNTIL([as hv2 ovs-ofctl dump-flows br-int table=32 | \
+grep active_backup | grep slaves:$hv2_gw2_ofport,$hv2_gw1_ofport \
+| wc -l], [0], [1
])
# check that the chassis redirect port has been reclaimed by the gw2 chassis
-AT_CHECK([ovn-sbctl --columns chassis --bare find Port_Binding logical_port=cr-outside | grep $gw2_chassis | wc -l],
- [0],[[1
+OVS_WAIT_UNTIL([ovn-sbctl --columns chassis --bare find Port_Binding \
+logical_port=cr-outside | grep $gw2_chassis | wc -l], [0],[[1
]])
# check BFD enablement on tunnel ports from gw1 #########
@@ -9896,31 +9959,32 @@ AT_CHECK([ovs-vsctl --bare --columns bfd find Interface name=ovn-hv1-0],[0],
[[
]])
-sleep 3 # let BFD sessions settle so we get the right flows on the right chassis
-
# make sure that flows for handling the outside router port reside on gw2 now
-AT_CHECK([as gw2 ovs-ofctl dump-flows br-int table=24 | grep 00:00:02:01:02:04 | wc -l], [0], [[1
+OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=24 | \
+grep 00:00:02:01:02:04 | wc -l], [0], [[1
]])
-AT_CHECK([as gw1 ovs-ofctl dump-flows br-int table=24 | grep 00:00:02:01:02:04 | wc -l], [0], [[0
+OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=24 | \
+grep 00:00:02:01:02:04 | wc -l], [0], [[0
]])
# disconnect GW2 from the network, GW1 should take over
as gw2
port=${sandbox}_br-phys
as main ovs-vsctl del-port n1 $port
-sleep 4
bfd_dump
# make sure that flows for handling the outside router port reside on gw2 now
-AT_CHECK([as gw1 ovs-ofctl dump-flows br-int table=24 | grep 00:00:02:01:02:04 | wc -l], [0], [[1
+OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=24 | \
+grep 00:00:02:01:02:04 | wc -l], [0], [[1
]])
-AT_CHECK([as gw2 ovs-ofctl dump-flows br-int table=24 | grep 00:00:02:01:02:04 | wc -l], [0], [[0
+OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=24 | \
+grep 00:00:02:01:02:04 | wc -l], [0], [[0
]])
# check that the chassis redirect port has been reclaimed by the gw1 chassis
-AT_CHECK([ovn-sbctl --columns chassis --bare find Port_Binding logical_port=cr-outside | grep $gw1_chassis | wc -l],
- [0],[[1
+OVS_WAIT_UNTIL([ovn-sbctl --columns chassis --bare find Port_Binding \
+logical_port=cr-outside | grep $gw1_chassis | wc -l], [0],[[1
]])
ovn-nbctl --wait=hv set NB_Global . options:"bfd-min-rx"=2000
@@ -9950,6 +10014,37 @@ for chassis in gw1 hv1 hv2; do
])
done
+# Delete the inside1 vif. The ref_chassis in ha_chassis_group shouldn't have
+# reference to hv1.
+as hv1 ovs-vsctl del-port hv1-vif1
+
+OVS_WAIT_UNTIL(
+ [ref_ch_list=`ovn-sbctl --bare --columns ref_chassis find ha_chassis_group | sort`
+ # Trim the spaces.
+ ref_ch_list=`echo $ref_ch_list | sed 's/ //g'`
+ test "$hv2_ch_uuid" = "$ref_ch_list"])
+
+# Delete the inside2 vif.
+ovn-sbctl show
+
+echo "Deleting hv2-vif1"
+as hv2 ovs-vsctl del-port hv2-vif1
+
+# ref_chassis of ha_chassis_group should be empty
+OVS_WAIT_UNTIL(
+ [ref_ch_list=`ovn-sbctl --bare --columns ref_chassis find ha_chassis_group | sort`
+ # Trim the spaces.
+ ref_ch_list=`echo $ref_ch_list | sed 's/ //g'`
+ exp_ref_ch_list=""
+ test "$exp_ref_ch_list" = "$ref_ch_list"])
+
+# Delete the Gateway_Chassis for lrp - outside
+ovn-nbctl clear Logical_Router_Port outside gateway_chassis
+
+# There shoud be no ha_chassis_group rows in SB DB.
+OVS_WAIT_UNTIL([test 0 = `ovn-sbctl list ha_chassis_group | wc -l`])
+OVS_WAIT_UNTIL([test 0 = `ovn-sbctl list ha_chassis | wc -l`])
+
OVN_CLEANUP([gw1],[gw2],[hv1],[hv2])
AT_CLEANUP
@@ -10186,10 +10281,7 @@ ovn-nbctl --wait=hv --timeout=3 sync
gw2_chassis=$(ovn-sbctl --bare --columns=_uuid find Chassis name=gw2)
ovn-sbctl destroy Chassis $gw2_chassis
-# Ensure ovn-controller has processed latest sbdb update
-# ovn-nbctl --wait=hv sync
-
-AT_CHECK([grep "Releasing lport" gw1/ovn-controller.log], [1], [])
+OVS_WAIT_UNTIL([test 0 = `grep -c "Releasing lport" gw1/ovn-controller.log`])
OVN_CLEANUP([gw1],[gw2],[hv1])