@@ -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 (encap_rec && pb->encap != encap_rec) {
- if (sb_readonly) {
- return false;
- }
- sbrec_port_binding_set_encap(pb, encap_rec);
+ if (pb->chassis == chassis_rec) {
+ return update_port_encap_if_needed(
+ pb, chassis_rec, iface_rec, sb_readonly,
+ &sbrec_port_binding_set_encap);
+ } else if (pb->additional_chassis == chassis_rec) {
+ return update_port_encap_if_needed(
+ pb, chassis_rec, iface_rec, sb_readonly,
+ &sbrec_port_binding_set_additional_encap);
}
return true;
@@ -972,7 +1023,8 @@ claim_lport(const struct sbrec_port_binding *pb,
* Caller should make sure that this is the case.
*/
static bool
-release_lport_(const struct sbrec_port_binding *pb, bool sb_readonly)
+release_lport_main_chassis(const struct sbrec_port_binding *pb,
+ bool sb_readonly)
{
if (pb->encap) {
if (sb_readonly) {
@@ -1000,11 +1052,41 @@ release_lport_(const struct sbrec_port_binding *pb, bool sb_readonly)
}
static bool
-release_lport(const struct sbrec_port_binding *pb, bool sb_readonly,
+release_lport_additional_chassis(const struct sbrec_port_binding *pb,
+ bool sb_readonly)
+{
+ if (pb->additional_encap) {
+ if (sb_readonly) {
+ return false;
+ }
+ sbrec_port_binding_set_additional_encap(pb, NULL);
+ }
+
+ if (pb->additional_chassis) {
+ if (sb_readonly) {
+ return false;
+ }
+ sbrec_port_binding_set_additional_chassis(pb, NULL);
+ }
+
+ VLOG_INFO("Releasing lport %s from this additional chassis.",
+ pb->logical_port);
+ return true;
+}
+
+static bool
+release_lport(const struct sbrec_port_binding *pb,
+ const struct sbrec_chassis *chassis_rec, bool sb_readonly,
struct hmap *tracked_datapaths, struct if_status_mgr *if_mgr)
{
- if (!release_lport_(pb, sb_readonly)) {
- return false;
+ if (pb->chassis == chassis_rec) {
+ if (!release_lport_main_chassis(pb, sb_readonly)) {
+ return false;
+ }
+ } else if (pb->additional_chassis == chassis_rec) {
+ if (!release_lport_additional_chassis(pb, sb_readonly)) {
+ return false;
+ }
}
update_lport_tracking(pb, tracked_datapaths, false);
@@ -1023,7 +1105,8 @@ is_binding_lport_this_chassis(struct binding_lport *b_lport,
const struct sbrec_chassis *chassis)
{
return (b_lport && b_lport->pb && chassis &&
- b_lport->pb->chassis == chassis);
+ (b_lport->pb->chassis == chassis
+ || b_lport->pb->additional_chassis == chassis));
}
/* Returns 'true' if the 'lbinding' has binding lports of type LP_CONTAINER,
@@ -1048,7 +1131,7 @@ release_binding_lport(const struct sbrec_chassis *chassis_rec,
{
if (is_binding_lport_this_chassis(b_lport, chassis_rec)) {
remove_related_lport(b_lport->pb, b_ctx_out);
- if (!release_lport(b_lport->pb, sb_readonly,
+ if (!release_lport(b_lport->pb, chassis_rec, sb_readonly,
b_ctx_out->tracked_dp_bindings,
b_ctx_out->if_mgr)) {
return false;
@@ -1097,22 +1180,31 @@ consider_vif_lport_(const struct sbrec_port_binding *pb,
} else {
/* We could, but can't claim the lport. */
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
+ if (!pb->chassis || pb->chassis == b_ctx_in->chassis_rec) {
+ VLOG_INFO_RL(&rl,
+ "Not claiming lport %s, chassis %s requested-chassis %s",
+ pb->logical_port, b_ctx_in->chassis_rec->name,
+ pb->requested_chassis ?
+ pb->requested_chassis->name :
+ "(option points at non-existent chassis)");
+ } else {
VLOG_INFO_RL(&rl,
- "Not claiming lport %s, chassis %s "
- "requested-chassis %s",
- pb->logical_port,
- b_ctx_in->chassis_rec->name,
- pb->requested_chassis ?
- pb->requested_chassis->name : "(option points at "
- "non-existent "
- "chassis)");
+ "Not claiming lport %s, chassis %s "
+ "requested-additional-chassis %s",
+ pb->logical_port, b_ctx_in->chassis_rec->name,
+ pb->requested_additional_chassis ?
+ pb->requested_additional_chassis->name :
+ "(option points at non-existent chassis)");
+ }
}
}
- if (pb->chassis == b_ctx_in->chassis_rec) {
+ if (pb->chassis == b_ctx_in->chassis_rec
+ || pb->additional_chassis == b_ctx_in->chassis_rec) {
/* Release the lport if there is no lbinding. */
if (!lbinding_set || !can_bind) {
- return release_lport(pb, !b_ctx_in->ovnsb_idl_txn,
+ return release_lport(pb, b_ctx_in->chassis_rec,
+ !b_ctx_in->ovnsb_idl_txn,
b_ctx_out->tracked_dp_bindings,
b_ctx_out->if_mgr);
}
@@ -1234,7 +1326,8 @@ consider_container_lport(const struct sbrec_port_binding *pb,
* if it was bound earlier. */
if (is_binding_lport_this_chassis(container_b_lport,
b_ctx_in->chassis_rec)) {
- return release_lport(pb, !b_ctx_in->ovnsb_idl_txn,
+ return release_lport(pb, b_ctx_in->chassis_rec,
+ !b_ctx_in->ovnsb_idl_txn,
b_ctx_out->tracked_dp_bindings,
b_ctx_out->if_mgr);
}
@@ -1328,7 +1421,7 @@ consider_localport(const struct sbrec_port_binding *pb,
/* If the port binding is claimed, then release it as localport is claimed
* by any ovn-controller. */
if (pb->chassis == b_ctx_in->chassis_rec) {
- if (!release_lport_(pb, !b_ctx_in->ovnsb_idl_txn)) {
+ if (!release_lport_main_chassis(pb, !b_ctx_in->ovnsb_idl_txn)) {
return false;
}
@@ -1363,7 +1456,8 @@ consider_nonvif_lport_(const struct sbrec_port_binding *pb,
b_ctx_out->tracked_dp_bindings,
b_ctx_out->if_mgr);
} else if (pb->chassis == b_ctx_in->chassis_rec) {
- return release_lport(pb, !b_ctx_in->ovnsb_idl_txn,
+ return release_lport(pb, b_ctx_in->chassis_rec,
+ !b_ctx_in->ovnsb_idl_txn,
b_ctx_out->tracked_dp_bindings,
b_ctx_out->if_mgr);
}
@@ -129,8 +129,23 @@ lport_can_bind_on_this_chassis(const struct sbrec_chassis *chassis_rec,
return !strcmp(requested_chassis_option, chassis_rec->name)
|| !strcmp(requested_chassis_option, chassis_rec->hostname);
}
- return !requested_chassis_option || !requested_chassis_option[0]
- || chassis_rec == pb->requested_chassis;
+ if (!requested_chassis_option || !requested_chassis_option[0]
+ || chassis_rec == pb->requested_chassis) {
+ return true;
+ }
+
+ const char *rac_option = smap_get(&pb->options,
+ "requested-additional-chassis");
+ if (rac_option && rac_option[0]) {
+ if (pb->requested_additional_chassis) {
+ return (pb->requested_chassis &&
+ chassis_rec == pb->requested_additional_chassis);
+ } else {
+ return !strcmp(rac_option, chassis_rec->name)
+ || !strcmp(rac_option, chassis_rec->hostname);
+ }
+ }
+ return false;
}
const struct sbrec_datapath_binding *
@@ -3139,17 +3139,17 @@ ovn_port_update_sbrec_chassis(
const struct ovn_port *op)
{
const char *requested_chassis; /* May be NULL. */
- bool reset_requested_chassis = false;
+ const char *requested_additional_chassis; /* May be NULL. */
+ const struct sbrec_chassis *requested_chassis_sb = NULL;
+ const struct sbrec_chassis *requested_additional_chassis_sb = NULL;
+
requested_chassis = smap_get(&op->nbsp->options,
"requested-chassis");
if (requested_chassis) {
- const struct sbrec_chassis *chassis = chassis_lookup(
+ requested_chassis_sb = chassis_lookup(
sbrec_chassis_by_name, sbrec_chassis_by_hostname,
requested_chassis);
- if (chassis) {
- sbrec_port_binding_set_requested_chassis(op->sb, chassis);
- } else {
- reset_requested_chassis = true;
+ if (!requested_chassis_sb) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(
1, 1);
VLOG_WARN_RL(
@@ -3158,12 +3158,58 @@ ovn_port_update_sbrec_chassis(
"options:requested-chassis on LSP '%s'.",
requested_chassis, op->nbsp->name);
}
- } else if (op->sb->requested_chassis) {
- reset_requested_chassis = true;
}
- if (reset_requested_chassis) {
+
+ requested_additional_chassis = smap_get(
+ &op->nbsp->options, "requested-additional-chassis");
+ if (requested_additional_chassis) {
+ requested_additional_chassis_sb = chassis_lookup(
+ sbrec_chassis_by_name, sbrec_chassis_by_hostname,
+ requested_additional_chassis);
+ if (!requested_additional_chassis_sb) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(
+ 1, 1);
+ VLOG_WARN_RL(
+ &rl,
+ "Unknown chassis '%s' set as "
+ "options:requested-additional-chassis on LSP '%s'.",
+ requested_additional_chassis, op->nbsp->name);
+ } else if (requested_chassis_sb == requested_additional_chassis_sb) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(
+ 1, 1);
+ VLOG_WARN_RL(
+ &rl,
+ "options:requested-chassis (%s) and "
+ "options:requested-additional-chassis (%s) point to the same "
+ "chassis on LSP '%s'. Ignoring additional chassis.",
+ requested_chassis, requested_additional_chassis,
+ op->nbsp->name);
+ requested_additional_chassis_sb = NULL;
+ } else if (!requested_chassis_sb) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(
+ 1, 1);
+ VLOG_WARN_RL(
+ &rl,
+ "Chassis '%s' set as "
+ "options:requested-additional-chassis on LSP '%s', but "
+ "options:requested-chassis is unset. "
+ "Ignoring additional chassis.",
+ requested_additional_chassis, op->nbsp->name);
+ requested_additional_chassis_sb = NULL;
+ }
+ }
+
+ if (requested_chassis_sb) {
+ sbrec_port_binding_set_requested_chassis(op->sb, requested_chassis_sb);
+ } else if (op->sb->requested_chassis) {
sbrec_port_binding_set_requested_chassis(op->sb, NULL);
}
+ if (requested_additional_chassis_sb) {
+ sbrec_port_binding_set_requested_additional_chassis(
+ op->sb, requested_additional_chassis_sb);
+ } else if (op->sb->requested_additional_chassis) {
+ sbrec_port_binding_set_requested_additional_chassis(op->sb, NULL);
+ }
}
static void
@@ -100,7 +100,9 @@ static const char *rbac_fdb_update[] =
static const char *rbac_port_binding_auth[] =
{""};
static const char *rbac_port_binding_update[] =
- {"chassis", "encap", "up", "virtual_parent"};
+ {"chassis", "additional_chassis",
+ "encap", "additional_encap",
+ "up", "virtual_parent"};
static const char *rbac_mac_binding_auth[] =
{""};
@@ -1005,6 +1005,14 @@
one chassis.
</column>
+ <column name="options" key="requested-additional-chassis">
+ If set and used with <ref column="requested-chassis"/>, identifies an
+ additional chassis (by name or hostname) that is allowed to bind this
+ port. Using this option allows to configure a new location for a port
+ binding before the old location is ripped off. This option may be
+ useful in live migration scenarios, for port mirroring, etc.
+ </column>
+
<column name="options" key="iface-id-ver">
If set, this port will be bound by <code>ovn-controller</code>
only if this same key and value is configured in the
@@ -1,7 +1,7 @@
{
"name": "OVN_Southbound",
"version": "20.21.0",
- "cksum": "2362446865 26963",
+ "cksum": "1635579573 27862",
"tables": {
"SB_Global": {
"columns": {
@@ -218,10 +218,18 @@
"refTable": "Chassis",
"refType": "weak"},
"min": 0, "max": 1}},
+ "additional_chassis": {"type": {"key": {"type": "uuid",
+ "refTable": "Chassis",
+ "refType": "weak"},
+ "min": 0, "max": 1}},
"encap": {"type": {"key": {"type": "uuid",
"refTable": "Encap",
"refType": "weak"},
"min": 0, "max": 1}},
+ "additional_encap": {"type": {"key": {"type": "uuid",
+ "refTable": "Encap",
+ "refType": "weak"},
+ "min": 0, "max": 1}},
"mac": {"type": {"key": "string",
"min": 0,
"max": "unlimited"}},
@@ -236,6 +244,11 @@
"requested_chassis": {"type": {"key": {"type": "uuid",
"refTable": "Chassis",
"refType": "weak"},
+ "min": 0, "max": 1}},
+ "requested_additional_chassis": {
+ "type": {"key": {"type": "uuid",
+ "refTable": "Chassis",
+ "refType": "weak"},
"min": 0, "max": 1}}},
"indexes": [["datapath", "tunnel_key"], ["logical_port"]],
"isRoot": true},
@@ -2835,9 +2835,17 @@ tcp.flags = RST;
</column>
<column name="encap">
- Points to supported encapsulation configurations to transmit
- logical dataplane packets to this chassis. Each entry is a <ref
- table="Encap"/> record that describes the configuration.
+ Points to preferred encapsulation configuration to transmit
+ logical dataplane packets to this chassis. The entry is reference to
+ a <ref table="Encap"/> record.
+ </column>
+
+ <column name="additional_encap">
+ Points to preferred encapsulation configuration to transmit
+ logical dataplane packets to this additional chassis. The entry is
+ reference to a <ref table="Encap"/> record.
+
+ See also <ref column="additional_chassis"/>.
</column>
<column name="chassis">
@@ -2889,6 +2897,13 @@ tcp.flags = RST;
</column>
+ <column name="additional_chassis">
+ The meaning of this column is the same as for the
+ <ref column="chassis"/>. The column is used to track an additional
+ physical location of the logical port. Used with regular (empty
+ <ref column="type"/>) port bindings.
+ </column>
+
<column name="gateway_chassis">
<p>
A list of <ref table="Gateway_Chassis"/>.
@@ -3047,6 +3062,33 @@ tcp.flags = RST;
db="OVN_Northbound"/>
is defined and contains a string matching the name or hostname of an
existing chassis.
+
+ See also
+ <ref table="Port_Binding" column="requested_additional_chassis"/>.
+ </column>
+ <column name="requested_additional_chassis">
+ This column exists so that the ovn-controller can effectively monitor
+ all <ref table="Port_Binding"/> records destined for it, and is a
+ supplement to the <ref
+ table="Port_Binding"
+ column="options"
+ key="requested-additional-chassis"/> option. The option is still
+ required so that the ovn-controller can check the CMS intent when the
+ chassis pointed to does not currently exist, which for example occurs
+ when the ovn-controller is stopped without passing the --restart
+ argument.
+
+ This column must be a
+ <ref table="Chassis"/> record. This is populated by
+ <code>ovn-northd</code> when the <ref
+ table="Logical_Switch_Port"
+ column="options"
+ key="requested-additional-chassis"
+ db="OVN_Northbound"/>
+ is defined and contains a string matching the name or hostname of an
+ existing chassis.
+
+ See also <ref table="Port_Binding" column="requested_chassis"/>.
</column>
</group>
@@ -3212,6 +3254,16 @@ tcp.flags = RST;
a live migration. It can also prevent similar thrashing due to a
mis-configuration, if a port is accidentally created on more than
one chassis.
+
+ See also <ref column="options" key="additional-chassis"/>.
+ </column>
+
+ <column name="options" key="requested-additional-chassis">
+ If set and used with <ref column="requested-chassis"/>, identifies an
+ additional chassis (by name or hostname) that is allowed to bind this
+ port. Using this option allows to configure a new location for a port
+ binding before the old location is ripped off. This option may be
+ useful in live migration scenarios, for port mirroring, etc.
</column>
<column name="options" key="iface-id-ver">
@@ -13597,6 +13597,97 @@ OVN_CLEANUP([hv1])
AT_CLEANUP
])
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([options:requested-additional-chassis for logical port])
+ovn_start
+
+net_add n1
+
+sim_add hv1
+as hv1
+check ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.11
+
+sim_add hv2
+as hv2
+check ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.12
+
+check ovn-nbctl ls-add ls0
+check ovn-nbctl lsp-add ls0 lsp0
+
+# Allow only chassis hv1 to bind logical port lsp0.
+check ovn-nbctl lsp-set-options lsp0 requested-chassis=hv1
+
+as hv1 check ovs-vsctl -- add-port br-int lsp0 -- \
+ set Interface lsp0 external-ids:iface-id=lsp0
+as hv2 check ovs-vsctl -- add-port br-int lsp0 -- \
+ set Interface lsp0 external-ids:iface-id=lsp0
+
+wait_row_count Chassis 1 name=hv1
+wait_row_count Chassis 1 name=hv2
+hv1_uuid=$(fetch_column Chassis _uuid name=hv1)
+hv2_uuid=$(fetch_column Chassis _uuid name=hv2)
+
+wait_column "$hv1_uuid" Port_Binding chassis logical_port=lsp0
+wait_column "$hv1_uuid" Port_Binding requested_chassis logical_port=lsp0
+wait_column "" Port_Binding additional_chassis logical_port=lsp0
+wait_column "" Port_Binding requested_additional_chassis logical_port=lsp0
+
+# Request port binding at an additional chassis
+check ovn-nbctl lsp-set-options lsp0 \
+ requested-chassis=hv1 \
+ requested-additional-chassis=hv2
+
+wait_column "$hv1_uuid" Port_Binding chassis logical_port=lsp0
+wait_column "$hv1_uuid" Port_Binding requested_chassis logical_port=lsp0
+wait_column "$hv2_uuid" Port_Binding additional_chassis logical_port=lsp0
+wait_column "$hv2_uuid" Port_Binding requested_additional_chassis logical_port=lsp0
+
+# Check that setting iface:encap-ip populates Port_Binding:additional_encap
+wait_row_count Encap 2 chassis_name=hv1
+wait_row_count Encap 2 chassis_name=hv2
+encap_hv1_uuid=$(fetch_column Encap _uuid chassis_name=hv1 type=geneve)
+encap_hv2_uuid=$(fetch_column Encap _uuid chassis_name=hv2 type=geneve)
+
+wait_column "" Port_Binding encap logical_port=lsp0
+wait_column "" Port_Binding additional_encap logical_port=lsp0
+
+as hv1 check ovs-vsctl -- \
+ set Interface lsp0 external-ids:encap-ip=192.168.0.11
+as hv2 check ovs-vsctl -- \
+ set Interface lsp0 external-ids:encap-ip=192.168.0.12
+
+wait_column "$encap_hv1_uuid" Port_Binding encap logical_port=lsp0
+wait_column "$encap_hv2_uuid" Port_Binding additional_encap logical_port=lsp0
+
+# Complete moving the binding to the new location
+check ovn-nbctl lsp-set-options lsp0 requested-chassis=hv2
+
+wait_column "$hv2_uuid" Port_Binding chassis logical_port=lsp0
+wait_column "$hv2_uuid" Port_Binding requested_chassis logical_port=lsp0
+wait_column "" Port_Binding additional_chassis logical_port=lsp0
+wait_column "" Port_Binding requested_additional_chassis logical_port=lsp0
+
+# Check that additional_encap is cleared
+wait_column "" Port_Binding additional_encap logical_port=lsp0
+
+# Check that abrupted port migration clears additional_encap
+check ovn-nbctl lsp-set-options lsp0 \
+ requested-chassis=hv2 \
+ requested-additional-chassis=hv1
+wait_column "$hv2_uuid" Port_Binding chassis logical_port=lsp0
+wait_column "$hv2_uuid" Port_Binding requested_chassis logical_port=lsp0
+wait_column "$hv1_uuid" Port_Binding additional_chassis logical_port=lsp0
+wait_column "$hv1_uuid" Port_Binding requested_additional_chassis logical_port=lsp0
+check ovn-nbctl lsp-set-options lsp0 requested-chassis=hv2
+wait_column "" Port_Binding additional_encap logical_port=lsp0
+
+OVN_CLEANUP([hv1],[hv2])
+
+AT_CLEANUP
+])
+
OVN_FOR_EACH_NORTHD([
AT_SETUP([options:requested-chassis for logical port])
ovn_start
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 <ihrachys@redhat.com> --- 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(-)