ovn supports creating remote logical ports. An user
can set requested-chassis option for a logical switch port
to the remote chassis and ovn-northd can bind it to that chassis.
This is required for OVN IC in ovn-k8s. Right now ovn-k8s
ovnkube-controller after creating a remote logical port, sets the
chassis column of the corresponding port binding in SB DB to the
remote chassis. This process can be implemented in ovn-northd.
Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2217930
Signed-off-by: Lorenzo Bianconi <[email protected]>
---
Changes since v2:
- address missing logica cases
- add more unit tests
Changes since v1:
- add NEWS entry
- do not remove ovn-ic code to bind sb to gw chassis
- simplify codebase
---
NEWS | 2 ++
ic/ovn-ic.c | 5 ++++
northd/northd.c | 28 +++++++++++++++++++
tests/ovn-ic.at | 2 ++
tests/ovn-northd.at | 67 +++++++++++++++++++++++++++++++++++++++++++++
tests/ovn.at | 27 ++++++++++++++++++
6 files changed, 131 insertions(+)
diff --git a/NEWS b/NEWS
index 93d4bedcd..d7580d9bd 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,8 @@ Post v23.06.0
Existing sessions might get re-hashed to a different ECMP path when
OVN detects the algorithm support in the datapath during an upgrade
or restart of ovn-controller.
+ - Introduce support for binding remote ports in ovn-northd if the
CMS sets
+ requested-chassis option for a remote logical switch port.
OVN v23.06.0 - 01 Jun 2023
--------------------------
diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
index db7e86bc1..2a8383523 100644
--- a/ic/ovn-ic.c
+++ b/ic/ovn-ic.c
@@ -651,6 +651,11 @@ sync_remote_port(struct ic_context *ctx,
/* Sync tunnel key from ISB to NB */
sync_lsp_tnl_key(lsp, isb_pb->tunnel_key);
+ /* Skip port binding if it is already requested by the CMS. */
+ if (smap_get(&lsp->options, "requested-chassis")) {
+ return;
+ }
+
/* Sync gateway from ISB to SB */
if (isb_pb->gateway[0]) {
if (!sb_pb->chassis || strcmp(sb_pb->chassis->name,
isb_pb->gateway)) {
diff --git a/northd/northd.c b/northd/northd.c
index a01f59efb..e6b37e66a 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -3579,6 +3579,28 @@ ovn_port_update_sbrec(struct ovsdb_idl_txn
*ovnsb_txn,
}
}
+ if (lsp_is_remote(op->nbsp)) {
+ /* ovn-northd is supposed to set port_binding for
remote ports
+ * if requested chassis is marked as remote. */
+ if (op->sb->requested_chassis &&
+
smap_get_bool(&op->sb->requested_chassis->other_config,
+ "is-remote", false)) {
+ sbrec_port_binding_set_chassis(op->sb,
+
op->sb->requested_chassis);
+ smap_add(&options, "is-remote-nb-binded", "true");
+ } else if (smap_get_bool(&op->sb->options,
+ "is-remote-nb-binded",
false)) {
+ sbrec_port_binding_set_chassis(op->sb, NULL);
+ smap_add(&options, "is-remote-nb-binded", "false");
+ }
+ } else if (op->sb->chassis &&
+ smap_get_bool(&op->sb->chassis->other_config,
+ "is-remote", false)) {
+ /* Its not a remote port but if the chassis is set
and if its a
+ * remote chassis then clear it. */
+ sbrec_port_binding_set_chassis(op->sb, NULL);
+ }
+
sbrec_port_binding_set_options(op->sb, &options);
smap_destroy(&options);
if (ovn_is_known_nb_lsp_type(op->nbsp->type)) {
@@ -3616,6 +3638,12 @@ ovn_port_update_sbrec(struct ovsdb_idl_txn
*ovnsb_txn,
sbrec_port_binding_set_ha_chassis_group(op->sb, NULL);
}
} else {
+ if (op->sb->chassis &&
+ smap_get_bool(&op->sb->chassis->other_config,
+ "is-remote", false)) {
+ sbrec_port_binding_set_chassis(op->sb, NULL);
+ }
+
const char *chassis = NULL;
if (op->peer && op->peer->od && op->peer->od->nbr) {
chassis = smap_get(&op->peer->od->nbr->options,
"chassis");
diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at
index 09eac860c..66368e7c9 100644
--- a/tests/ovn-ic.at
+++ b/tests/ovn-ic.at
@@ -336,6 +336,7 @@ ovn-nbctl lsp-set-addresses lsp-ts1-lr1 router
ovn-nbctl lsp-set-type lsp-ts1-lr1 router
ovn-nbctl --wait=hv lsp-set-options lsp-ts1-lr1 router-port=lrp-lr1-ts1
+ovn_as az2 ovn-nbctl lsp-set-options lsp-ts1-lr1 requested-chassis=gw1
AT_CHECK([ovn_as az2 ovn-nbctl show | uuidfilt], [0], [dnl
switch <0> (ts1)
port lsp-ts1-lr1
@@ -350,6 +351,7 @@ lsp-ts1-lr1,remote
ovn-nbctl lrp-set-gateway-chassis lrp-lr1-ts1 gw1
OVS_WAIT_UNTIL([ovn_as az2 ovn-sbctl show | grep lsp-ts1-lr1])
+ovn_as az2 ovn-nbctl lsp-set-options lsp-ts1-lr1 requested-chassis=""
ovn-nbctl lrp-del-gateway-chassis lrp-lr1-ts1 gw1
OVS_WAIT_WHILE([ovn_as az2 ovn-sbctl show | grep lsp-ts1-lr1])
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index acb1a4334..7f50e4c7f 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -9728,3 +9728,70 @@ AT_CHECK([grep "lr_in_gw_redirect" R1flows |sed
s'/table=../table=??/' |sort], [
AT_CLEANUP
])
+
+OVN_FOR_EACH_NORTHD_NO_HV([
+AT_SETUP([Remote port binding])
+AT_KEYWORDS([remote-port-binding])
+ovn_start
+
+check ovn-sbctl chassis-add remote-ch0 geneve 127.0.0.1
+check ovn-sbctl set chassis remote-ch0 other_config:is-remote=true
+
+check ovn-sbctl chassis-add local-ch0 geneve 127.0.0.2
+wait_row_count Chassis 2
+
+remote_chassis_uuid=$(fetch_column Chassis _uuid name=remote-ch0)
+as northd ovn-appctl -t NORTHD_TYPE vlog/set dbg
+
+check ovn-nbctl ls-add sw0
+check ovn-nbctl lsp-add sw0 sw0-r1 -- lsp-set-type sw0-r1 remote
+check ovn-nbctl lsp-set-options sw0-r1 requested-chassis=remote-ch0
+wait_for_ports_up sw0-r1
+
+# Make sure it is bound by remote-ch0
+check_column $remote_chassis_uuid Port_Binding chassis
logical_port=sw0-r1
+
+check ovn-nbctl remove logical_switch_port sw0-r1 options
requested-chassis
+wait_row_count nb:Logical_Switch_Port 1 up=false name=sw0-r1
+
+check_column '' Port_Binding chassis logical_port=sw0-r1
+
+# Set the requested-chassis to local-ch0. ovn-northd should not
+# bind it. But before that bind again to remote-ch0. This becomes
+# easier to test for the local-ch0 scenario.
+check ovn-nbctl lsp-set-options sw0-r1 requested-chassis=remote-ch0
+wait_for_ports_up sw0-r1
+check_column $remote_chassis_uuid Port_Binding chassis
logical_port=sw0-r1
+check ovn-nbctl lsp-set-options sw0-r1 requested-chassis=local-ch0
+wait_row_count nb:Logical_Switch_Port 1 up=false name=sw0-r1
+check_column '' Port_Binding chassis logical_port=sw0-r1
+
+# Set the requested-chassis to unknown chassis. ovn-northd should not
+# bind it. But before that bind again to remote-ch0. This becomes
+# easier to test for the local-ch0 scenario.
+check ovn-nbctl lsp-set-options sw0-r1 requested-chassis=remote-ch0
+wait_for_ports_up sw0-r1
+check_column $remote_chassis_uuid Port_Binding chassis
logical_port=sw0-r1
+check ovn-nbctl lsp-set-options sw0-r1 requested-chassis=foo
+wait_row_count nb:Logical_Switch_Port 1 up=false name=sw0-r1
+check_column '' Port_Binding chassis logical_port=sw0-r1
+
+# Change the port type to normal and ovn-northd should not bind it.
+check ovn-nbctl lsp-set-options sw0-r1 requested-chassis=remote-ch0
+wait_for_ports_up sw0-r1
+check_column $remote_chassis_uuid Port_Binding chassis
logical_port=sw0-r1
+check ovn-nbctl lsp-set-type sw0-r1 ''
+wait_row_count nb:Logical_Switch_Port 1 up=false name=sw0-r1
+check_column '' Port_Binding chassis logical_port=sw0-r1
+
+# Change back to type to remote and ovn-northd should bind it.
+check ovn-nbctl lsp-set-type sw0-r1 remote
+wait_for_ports_up sw0-r1
+check_column $remote_chassis_uuid Port_Binding chassis
logical_port=sw0-r1
+
+# Set the type to router and ovn-northd should not claim it.
+check ovn-nbctl lsp-set-type sw0-r1 router
+check_column '' Port_Binding chassis logical_port=sw0-r1
+
+AT_CLEANUP
+])
diff --git a/tests/ovn.at b/tests/ovn.at
index 2e9ae31c0..8f367b499 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -26133,6 +26133,19 @@ done
# XXX This should be more systematic.
sleep 2
+# Populate requested-chassis options for remote lsps
+for az in $(seq 1 $n_az); do
+ ovn_as az${az}
+ for ts in $(seq 1 $n_ts); do
+ for i in $(seq 1 $n_ts); do
+ if [[ $i -eq ${az} ]]; then
+ continue
+ fi
+ check ovn-nbctl lsp-set-options lsp-ts${ts}-lr${i}-${ts}
requested-chassis=gw$i
+ done
+ done
+done
+
ovn-ic-nbctl show > ic-nbctl.dump
AT_CAPTURE_FILE([ic-nbctl.dump])
@@ -26356,6 +26369,13 @@ check ovn-nbctl lsp-add ts ts-lr3 \
wait_for_ports_up
+ovn_as az1
+check ovn-nbctl lsp-set-options ts-lr2 requested-chassis=hv2
+check ovn-nbctl lsp-set-options ts-lr3 requested-chassis=hv2
+
+ovn_as az2
+check ovn-nbctl lsp-set-options ts-lr1 requested-chassis=hv1
+
dnl Enable unregistered IP multicast flooding and IP multicast relay.
ovn_as az1
check ovn-nbctl set logical_switch ls1
other_config:mcast_snoop="true" \
@@ -26561,6 +26581,13 @@ check ovn-nbctl lsp-add ts ts-lr3 \
wait_for_ports_up
+ovn_as az1
+check ovn-nbctl lsp-set-options ts-lr2 requested-chassis=hv2
+check ovn-nbctl lsp-set-options ts-lr3 requested-chassis=hv2
+
+ovn_as az2
+check ovn-nbctl lsp-set-options ts-lr1 requested-chassis=hv1
+
dnl Enable IP multicast snooping and IP multicast relay. Reports are
dnl forwarded statically.
ovn_as az1