If used in conjunction with requested-chassis, OVN will attempt to
bind the port at another location in addition to the main chassis.
This is useful in live migration scenarios where it's important to
prepare the environment for workloads to move to, avoiding costly flow
configuration at the moment of the final port binding location change.
The patch mimics behavior of requested-chassis. Corresponding database
fields (pb->additional_chassis, pb->requested_additional_chassis,
pb->additional_encap) are introduced as part of the patch.
Signed-off-by: Ihar Hrachyshka
---
controller/binding.c | 178 +--
controller/lport.c | 19 -
northd/northd.c | 64 +---
northd/ovn-northd.c | 4 +-
ovn-nb.xml | 8 ++
ovn-sb.ovsschema | 15 +++-
ovn-sb.xml | 58 +-
tests/ovn.at | 91 ++
8 files changed, 379 insertions(+), 58 deletions(-)
diff --git a/controller/binding.c b/controller/binding.c
index c7a13d5d5..ec8bff3d8 100644
--- a/controller/binding.c
+++ b/controller/binding.c
@@ -912,6 +912,26 @@ claimed_lport_set_up(const struct sbrec_port_binding *pb,
}
}
+typedef void (*set_func)(const struct sbrec_port_binding *pb,
+ const struct sbrec_encap *);
+
+static bool
+update_port_encap_if_needed(const struct sbrec_port_binding *pb,
+const struct sbrec_chassis *chassis_rec,
+const struct ovsrec_interface *iface_rec,
+bool sb_readonly, set_func f)
+{
+const struct sbrec_encap *encap_rec =
+sbrec_get_port_encap(chassis_rec, iface_rec);
+if (encap_rec && pb->encap != encap_rec) {
+if (sb_readonly) {
+return false;
+}
+f(pb, encap_rec);
+}
+return true;
+}
+
/* Returns false if lport is not claimed due to 'sb_readonly'.
* Returns true otherwise.
*/
@@ -928,37 +948,68 @@ claim_lport(const struct sbrec_port_binding *pb,
claimed_lport_set_up(pb, parent_pb, chassis_rec, notify_up, if_mgr);
}
-if (pb->chassis != chassis_rec) {
-if (sb_readonly) {
-return false;
-}
+if (!pb->requested_chassis || pb->requested_chassis == chassis_rec) {
+if (pb->chassis != chassis_rec) {
+if (sb_readonly) {
+return false;
+}
-if (pb->chassis) {
-VLOG_INFO("Changing chassis for lport %s from %s to %s.",
-pb->logical_port, pb->chassis->name,
-chassis_rec->name);
-} else {
-VLOG_INFO("Claiming lport %s for this chassis.", pb->logical_port);
-}
-for (int i = 0; i < pb->n_mac; i++) {
-VLOG_INFO("%s: Claiming %s", pb->logical_port, pb->mac[i]);
+if (pb->chassis) {
+VLOG_INFO("Changing chassis for lport %s from %s to %s.",
+pb->logical_port, pb->chassis->name,
+chassis_rec->name);
+} else {
+VLOG_INFO("Claiming lport %s for this chassis.",
+ pb->logical_port);
+}
+for (int i = 0; i < pb->n_mac; i++) {
+VLOG_INFO("%s: Claiming %s", pb->logical_port, pb->mac[i]);
+}
+
+sbrec_port_binding_set_chassis(pb, chassis_rec);
+if (pb->additional_chassis == chassis_rec) {
+sbrec_port_binding_set_additional_chassis(pb, NULL);
+if (pb->additional_encap) {
+sbrec_port_binding_set_additional_encap(pb, NULL);
+}
+}
}
+} else if (pb->requested_additional_chassis == chassis_rec) {
+if (pb->additional_chassis != chassis_rec) {
+if (sb_readonly) {
+return false;
+}
-sbrec_port_binding_set_chassis(pb, chassis_rec);
+if (pb->additional_chassis) {
+VLOG_INFO(
+"Changing additional chassis for lport %s from %s to %s.",
+pb->logical_port, pb->chassis->name, chassis_rec->name);
+} else {
+VLOG_INFO(
+"Claiming lport %s for this additional chassis.",
+pb->logical_port);
+}
+for (int i = 0; i < pb->n_mac; i++) {
+VLOG_INFO("%s: Claiming %s", pb->logical_port, pb->mac[i]);
+}
-if (tracked_datapaths) {
-update_lport_tracking(pb, tracked_datapaths, true);
+sbrec_port_binding_set_additional_chassis(pb, chassis_rec);
}
}
+if (tracked_datapaths) {
+update_lport_tracking(pb, tracked_datapaths, true);
+}
+
/* Check if the port encap binding, if any, has changed */
-struct sbrec_encap *encap_rec =
-sbrec_get_port_encap(chassis_rec, iface_rec);
-if