@@ -2486,7 +2486,7 @@ get_nat_addresses(const struct ovn_port *op, size_t *n)
{
size_t n_nats = 0;
struct eth_addr mac;
- if (!op->nbrp || !op->od || !op->od->nbr
+ if (!op || !op->nbrp || !op->od || !op->od->nbr
|| (!op->od->nbr->n_nat && !op->od->nbr->n_load_balancer)
|| !eth_addr_from_string(op->nbrp->mac, &mac)) {
*n = n_nats;
@@ -2878,6 +2878,123 @@ ovn_update_ipv6_prefix(struct hmap *ports)
}
}
+static void
+ovn_port_set_garp_addresses(const struct ovn_port *op, const char **nats,
+ size_t n_nats, const char *router_networks,
+ bool peer_is_gateway, bool peer_has_dist_gw_port)
+{
+ const char *nat_addresses = smap_get(&op->nbsp->options,
+ "nat-addresses");
+ size_t n_sources = 0;
+ const char **source = NULL;
+ if (nat_addresses && (peer_is_gateway || peer_has_dist_gw_port)) {
+ if (!strcmp(nat_addresses, "router")) {
+ /* We size this to n_nats + 1 since it can at most include
+ * all NAT addresses plus the router's networks.
+ */
+ source = nats;
+ n_sources = n_nats;
+ /* Only accept manual specification of ethernet address
+ * followed by IPv4 addresses on type "l3gateway" ports. */
+ } else if (peer_is_gateway) {
+ struct lport_addresses laddrs;
+ if (!extract_lsp_addresses(nat_addresses, &laddrs)) {
+ static struct vlog_rate_limit rl =
+ VLOG_RATE_LIMIT_INIT(1, 1);
+ VLOG_WARN_RL(&rl, "Error extracting nat-addresses.");
+ } else {
+ destroy_lport_addresses(&laddrs);
+ /* Allocate enough space for the nat_addresses plus
+ * the router networks
+ */
+ source = &nat_addresses;
+ n_sources = 1;
+ }
+ }
+ }
+
+ size_t n_garps = 0;
+ /* The "garps" array contains the addresses for which
+ * ovn-controller should send GARPs. This is controlled
+ * by the "nat-addresses" option on the logical switch.
+ *
+ * Size the garps array to one more than the number of NAT
+ * sources so that we can fit the NATs and the router
+ * networks.
+ */
+ char **garps = xcalloc(n_sources + 1, sizeof *garps);
+ for (n_garps = 0; n_garps < n_sources; n_garps++) {
+ garps[n_garps] = xstrdup(source[n_garps]);
+ }
+
+ /* Add the router mac and IPv4 addresses to
+ * Port_Binding.nat_addresses so that GARP is sent for these
+ * IPs by the ovn-controller on which the distributed gateway
+ * router port resides if:
+ *
+ * - op->peer has 'reside-on-redirect-chassis' set and the
+ * the logical router datapath has distributed router port.
+ *
+ * - op->peer is distributed gateway router port.
+ *
+ * - op->peer's router is a gateway router and op has a localnet
+ * port.
+ *
+ * Note: Port_Binding.nat_addresses column is also used for
+ * sending the GARPs for the router port IPs.
+ * */
+ bool add_router_port_garp = false;
+ if (peer_has_dist_gw_port &&
+ (smap_get_bool(&op->peer->nbrp->options,
+ "reside-on-redirect-chassis", false) ||
+ op->peer == op->peer->od->l3dgw_port)) {
+ add_router_port_garp = true;
+ } else if (peer_is_gateway && op->od->n_localnet_ports) {
+ add_router_port_garp = true;
+ }
+
+ if (add_router_port_garp) {
+ /* "garps" was allocated with enough space to hold
+ * this address without reallocating.
+ */
+ garps[n_garps] = xstrdup(router_networks);
+ n_garps++;
+ }
+
+ sbrec_port_binding_set_nat_addresses(op->sb,
+ (const char **) garps,
+ n_garps);
+ for (size_t i = 0; i < n_garps; i++) {
+ free(garps[i]);
+ }
+ free(garps);
+}
+
+static void
+ovn_port_set_router_addresses(const struct ovn_port *op, const char **nats,
+ size_t n_nats, const char *router_networks)
+{
+ /* The total number of router addresses is the NATs plus the
+ * router networks
+ */
+ size_t n_router_addresses = n_nats + 1;
+ const char **router_addresses = xcalloc(n_router_addresses,
+ sizeof *router_addresses);
+
+ for (size_t i = 0; i < n_nats; i++) {
+ router_addresses[i] = nats[i];
+ }
+ router_addresses[n_nats] = router_networks;
+
+ /* All NAT addresses + the router address need to be added
+ * to the port binding's router_addresses field, even if they
+ * have not been configured on the switch port.
+ */
+ sbrec_port_binding_set_router_addresses(
+ op->sb, (const char **) router_addresses, n_router_addresses);
+ free(router_addresses);
+}
+
static void
ovn_port_update_sbrec(struct northd_context *ctx,
struct ovsdb_idl_index *sbrec_chassis_by_name,
@@ -3050,9 +3167,14 @@ ovn_port_update_sbrec(struct northd_context *ctx,
chassis = smap_get(&op->peer->od->nbr->options, "chassis");
}
+ bool peer_is_gateway = !!chassis;
+ bool peer_has_dist_gw_port = op->peer
+ && op->peer->od
+ && op->peer->od->l3redirect_port;
+
/* A switch port connected to a gateway router is also of
* type "l3gateway". */
- if (chassis) {
+ if (peer_is_gateway) {
sbrec_port_binding_set_type(op->sb, "l3gateway");
} else {
sbrec_port_binding_set_type(op->sb, "patch");
@@ -3060,7 +3182,7 @@ ovn_port_update_sbrec(struct northd_context *ctx,
const char *router_port = smap_get(&op->nbsp->options,
"router-port");
- if (router_port || chassis) {
+ if (router_port || peer_is_gateway) {
struct smap new;
smap_init(&new);
if (router_port) {
@@ -3075,84 +3197,41 @@ ovn_port_update_sbrec(struct northd_context *ctx,
sbrec_port_binding_set_options(op->sb, NULL);
}
- const char *nat_addresses = smap_get(&op->nbsp->options,
- "nat-addresses");
- size_t n_nats = 0;
- char **nats = NULL;
- if (nat_addresses && !strcmp(nat_addresses, "router")) {
- if (op->peer && op->peer->od
- && (chassis || op->peer->od->l3redirect_port)) {
- nats = get_nat_addresses(op->peer, &n_nats);
- }
- /* Only accept manual specification of ethernet address
- * followed by IPv4 addresses on type "l3gateway" ports. */
- } else if (nat_addresses && chassis) {
- struct lport_addresses laddrs;
- if (!extract_lsp_addresses(nat_addresses, &laddrs)) {
- static struct vlog_rate_limit rl =
- VLOG_RATE_LIMIT_INIT(1, 1);
- VLOG_WARN_RL(&rl, "Error extracting nat-addresses.");
- } else {
- destroy_lport_addresses(&laddrs);
- n_nats = 1;
- nats = xcalloc(1, sizeof *nats);
- nats[0] = xstrdup(nat_addresses);
- }
- }
+ size_t n_nats;
+ char **nats;
+ nats = get_nat_addresses(op->peer, &n_nats);
- /* Add the router mac and IPv4 addresses to
- * Port_Binding.nat_addresses so that GARP is sent for these
- * IPs by the ovn-controller on which the distributed gateway
- * router port resides if:
- *
- * - op->peer has 'reside-on-redirect-chassis' set and the
- * the logical router datapath has distributed router port.
- *
- * - op->peer is distributed gateway router port.
- *
- * - op->peer's router is a gateway router and op has a localnet
- * port.
- *
- * Note: Port_Binding.nat_addresses column is also used for
- * sending the GARPs for the router port IPs.
- * */
- bool add_router_port_garp = false;
- if (op->peer && op->peer->nbrp && op->peer->od->l3dgw_port &&
- op->peer->od->l3redirect_port &&
- (smap_get_bool(&op->peer->nbrp->options,
- "reside-on-redirect-chassis", false) ||
- op->peer == op->peer->od->l3dgw_port)) {
- add_router_port_garp = true;
- } else if (chassis && op->od->n_localnet_ports) {
- add_router_port_garp = true;
- }
-
- if (add_router_port_garp) {
- struct ds garp_info = DS_EMPTY_INITIALIZER;
- ds_put_format(&garp_info, "%s", op->peer->lrp_networks.ea_s);
+ struct ds router_networks = DS_EMPTY_INITIALIZER;
+ if (op->peer) {
+ ds_put_format(&router_networks, "%s", op->peer->lrp_networks.ea_s);
for (size_t i = 0; i < op->peer->lrp_networks.n_ipv4_addrs;
i++) {
- ds_put_format(&garp_info, " %s",
+ ds_put_format(&router_networks, " %s",
op->peer->lrp_networks.ipv4_addrs[i].addr_s);
- }
- if (op->peer->od->l3redirect_port) {
- ds_put_format(&garp_info, " is_chassis_resident(%s)",
- op->peer->od->l3redirect_port->json_key);
+ if (peer_has_dist_gw_port) {
+ ds_put_format(&router_networks, " is_chassis_resident(%s)",
+ op->peer->od->l3redirect_port->json_key);
+ }
}
+ }
+ ovn_port_set_garp_addresses(op, (const char **) nats, n_nats,
+ ds_cstr(&router_networks), peer_is_gateway,
+ peer_has_dist_gw_port);
- n_nats++;
- nats = xrealloc(nats, (n_nats * sizeof *nats));
- nats[n_nats - 1] = ds_steal_cstr(&garp_info);
- ds_destroy(&garp_info);
+ if (peer_is_gateway || (peer_has_dist_gw_port
+ && op->peer == op->peer->od->l3dgw_port)) {
+ ovn_port_set_router_addresses(op, (const char **) nats, n_nats,
+ ds_cstr(&router_networks));
+ } else {
+ sbrec_port_binding_set_router_addresses(op->sb, NULL, 0);
}
- sbrec_port_binding_set_nat_addresses(op->sb,
- (const char **) nats, n_nats);
for (size_t i = 0; i < n_nats; i++) {
free(nats[i]);
}
free(nats);
+ ds_destroy(&router_networks);
}
sbrec_port_binding_set_parent_port(op->sb, op->nbsp->parent_name);
@@ -14119,6 +14198,8 @@ main(int argc, char *argv[])
add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_mac);
add_column_noalert(ovnsb_idl_loop.idl,
&sbrec_port_binding_col_nat_addresses);
+ add_column_noalert(ovnsb_idl_loop.idl,
+ &sbrec_port_binding_col_router_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);
@@ -116,6 +116,7 @@ relation OutProxy_Port_Binding (
tag: Option<integer>,
mac: Set<string>,
nat_addresses: Set<string>,
+ router_addresses: Set<string>,
external_ids: Map<string,string>
)
@@ -131,6 +132,7 @@ OutProxy_Port_Binding(._uuid = lsp._uuid,
.tag = tag,
.mac = lsp.addresses,
.nat_addresses = set_empty(),
+ .router_addresses = set_empty(),
.external_ids = eids) :-
sp in &SwitchPort(.lsp = lsp, .sw = &sw),
SwitchPortNewDynamicTag(lsp._uuid, opt_tag),
@@ -169,6 +171,7 @@ OutProxy_Port_Binding(._uuid = lsp._uuid,
.tag = None,
.mac = lsp.addresses,
.nat_addresses = nat_addresses,
+ .router_addresses = router_addresses,
.external_ids = eids) :-
&SwitchPort(.lsp = lsp, .sw = &sw, .peer = peer),
var eids = {
@@ -194,13 +197,17 @@ OutProxy_Port_Binding(._uuid = lsp._uuid,
}
}
},
- var base_nat_addresses = {
+ var all_nat_addresses = match (peer) {
+ None -> { set_empty() },
+ Some{rport} -> get_nat_addresses(deref(rport))
+ },
+ var garp_nat_addresses = {
match (lsp.options.get("nat-addresses")) {
None -> { set_empty() },
Some{"router"} -> match ((l3dgw_port, opt_chassis, peer)) {
(None, None, _) -> set_empty(),
(_, _, None) -> set_empty(),
- (_, _, Some{rport}) -> get_nat_addresses(deref(rport))
+ (_, _, Some{rport}) -> all_nat_addresses
},
Some{nat_addresses} -> {
/* Only accept manual specification of ethernet address
@@ -233,7 +240,11 @@ OutProxy_Port_Binding(._uuid = lsp._uuid,
* Note: Port_Binding.nat_addresses column is also used for
* sending the GARPs for the router port IPs.
* */
- var garp_nat_addresses = match (peer) {
+ var router_interface_addresses = match (peer) {
+ None -> set_empty(),
+ Some{rport} -> set_singleton(get_router_interface_addresses(deref(rport)))
+ },
+ var garp_router_interface_addresses = match (peer) {
Some{rport} -> match (
(rport.lrp.options.get_bool_def("reside-on-redirect-chassis", false)
and l3dgw_port.is_some()) or
@@ -241,11 +252,22 @@ OutProxy_Port_Binding(._uuid = lsp._uuid,
(rport.router.lr.options.contains_key("chassis") and
not sw.localnet_ports.is_empty())) {
false -> set_empty(),
- true -> set_singleton(get_garp_nat_addresses(deref(rport)))
+ true -> router_interface_addresses
},
None -> set_empty()
},
- var nat_addresses = set_union(base_nat_addresses, garp_nat_addresses).
+ var nat_addresses = set_union(garp_nat_addresses, garp_router_interface_addresses),
+ var router_addresses = match ((opt_chassis, l3dgw_port, peer)) {
+ (Some{_} , _, _) -> set_union(all_nat_addresses, router_interface_addresses),
+ (_, Some{gw_port}, Some{rport}) -> {
+ if (gw_port == rport.lrp) {
+ set_union(all_nat_addresses, router_interface_addresses)
+ } else {
+ set_empty()
+ }
+ },
+ (_, _, _) -> set_empty()
+ }.
/* Case 3: Port_Binding per logical router port */
OutProxy_Port_Binding(._uuid = lrp._uuid,
@@ -259,6 +281,7 @@ OutProxy_Port_Binding(._uuid = lrp._uuid,
.tag = None, // always empty for router ports
.mac = set_singleton("${lrp.mac} ${lrp.networks.join(\" \")}"),
.nat_addresses = set_empty(),
+ .router_addresses = set_empty(),
.external_ids = lrp.external_ids) :-
rp in &RouterPort(.lrp = lrp, .router = &router, .peer = peer),
RouterPortRAOptionsComplete(lrp._uuid, options0),
@@ -400,15 +423,15 @@ function get_nat_addresses(rport: RouterPort): Set<string> =
}
}
-function get_garp_nat_addresses(rport: RouterPort): string = {
- var garp_info = ["${rport.networks.ea}"];
+function get_router_interface_addresses(rport: RouterPort): string = {
+ var router_info = ["${rport.networks.ea}"];
for (ipv4_addr in rport.networks.ipv4_addrs) {
- garp_info.push("${ipv4_addr.addr}")
+ router_info.push("${ipv4_addr.addr}")
};
if (rport.router.redirect_port_name != "") {
- garp_info.push("is_chassis_resident(${rport.router.redirect_port_name})")
+ router_info.push("is_chassis_resident(${rport.router.redirect_port_name})")
};
- garp_info.join(" ")
+ router_info.join(" ")
}
/* Extra options computed for router ports by the logical flow generation code */
@@ -441,6 +464,7 @@ OutProxy_Port_Binding(// lrp._uuid is already in use; generate a new UUID by
.tag = None, //always empty for router ports
.mac = set_singleton("${lrp.mac} ${lrp.networks.join(\" \")}"),
.nat_addresses = set_empty(),
+ .router_addresses = set_empty(),
.external_ids = lrp.external_ids) :-
DistributedGatewayPort(lrp, lr_uuid),
LogicalRouterHAChassisGroup(lr_uuid, hacg_uuid),
@@ -478,6 +502,7 @@ sb::Out_Port_Binding(._uuid = pbinding._uuid,
.tag = pbinding.tag,
.mac = pbinding.mac,
.nat_addresses = pbinding.nat_addresses,
+ .router_addresses = pbinding.router_addresses,
.external_ids = pbinding.external_ids,
.up = Some{up}) :-
pbinding in OutProxy_Port_Binding(),
@@ -1,7 +1,7 @@
{
"name": "OVN_Southbound",
"version": "20.17.0",
- "cksum": "669123379 26536",
+ "cksum": "367711378 26723",
"tables": {
"SB_Global": {
"columns": {
@@ -225,6 +225,9 @@
"nat_addresses": {"type": {"key": "string",
"min": 0,
"max": "unlimited"}},
+ "router_addresses": {"type": {"key": "string",
+ "min": 0,
+ "max": "unlimited"}},
"up": {"type": {"key": "boolean", "min": 0, "max": 1}},
"external_ids": {"type": {"key": "string",
"value": "string",
@@ -2994,6 +2994,16 @@ tcp.flags = RST;
158.36.44.24 with a MAC address of 80:fa:5b:06:72:b7 from the chassis
where the logical port "foo1" resides.
</column>
+
+ <column name="router_addresses">
+ This is an exhaustive list of all NAT, load balancer, and interface
+ addresses of the connected router port. The format of the entries is
+ the same as the <ref column="nat_addresses"/> column. Whereas the
+ <ref column="nat_addresses"/> column is used to determine the addresses
+ for which ovn-controller will send gratuitous ARPs, the addresses in
+ this column are used to pre-set <ref table="MAC_Binding"/>s to avoid
+ the need for sending unnecessary ARPs.
+ </column>
</group>
<group title="L3 Gateway Options">
@@ -3024,6 +3034,16 @@ tcp.flags = RST;
158.36.44.22 and 158.36.44.24 with a MAC address of 80:fa:5b:06:72:b7.
This is used in OVS version 2.8 and later versions.
</column>
+
+ <column name="router_addresses">
+ This is an exhaustive list of all NAT, load balancer, and interface
+ addresses of the connected router port. The format of the entries is
+ the same as the <ref column="nat_addresses"/> column. Whereas the
+ <ref column="nat_addresses"/> column is used to determine the addresses
+ for which ovn-controller will send gratuitous ARPs, the addresses in
+ this column are used to pre-set <ref table="MAC_Binding"/>s to avoid
+ the need for sending unnecessary ARPs.
+ </column>
</group>
<group title="Localnet Options">
@@ -2991,3 +2991,256 @@ ovn-sbctl list FDB
AT_CLEANUP
])
+
+# XXX This test currently only runs for ovn-northd.c. The test fails
+# with ovn-northd-ddlog because of the section where 2 HA_Chassis_Groups
+# are used by 2 routers. For some reason, this causes ovn-northd-ddlog
+# to stop processing new changes to the northbound database and to
+# seemingly infinitely loop. This issue has been reported, but there is
+# currently no fix for it. Once this issue is fixed, we can run this
+# test for both C and DDLog versions of northd.
+AT_SETUP([ovn -- Router Address Propagation])
+ovn_start
+
+AS_BOX([Setting up the logical network])
+
+check ovn-nbctl ls-add sw
+
+check ovn-nbctl lr-add ro1
+check ovn-nbctl lrp-add ro1 ro1-sw 00:00:00:00:00:01 10.0.0.1/24
+check ovn-nbctl lsp-add sw sw-ro1
+
+check ovn-nbctl lr-add ro2
+check ovn-nbctl lrp-add ro2 ro2-sw 00:00:00:00:00:02 20.0.0.1/24
+check ovn-nbctl --wait=sb lsp-add sw sw-ro2
+
+check ovn-nbctl ls-add ls1
+check ovn-nbctl lsp-add ls1 vm1
+check ovn-nbctl lsp-set-addresses vm1 "00:00:00:00:01:02 192.168.1.2"
+check ovn-nbctl lrp-add ro1 ro1-ls1 00:00:00:00:01:01 192.168.1.1/24
+check ovn-nbctl lsp-add ls1 ls1-ro1
+check ovn-nbctl lsp-set-type ls1-ro1 router
+check ovn-nbctl lsp-set-addresses ls1-ro1 router
+check ovn-nbctl lsp-set-options ls1-ro1 router-port=ro1-ls1
+
+check ovn-nbctl ls-add ls2
+check ovn-nbctl lsp-add ls2 vm2
+check ovn-nbctl lsp-set-addresses vm2 "00:00:00:00:02:02 192.168.2.2"
+check ovn-nbctl lrp-add ro2 ro2-ls2 00:00:00:00:02:01 192.168.2.1/24
+check ovn-nbctl lsp-add ls2 ls2-ro2
+check ovn-nbctl lsp-set-type ls2-ro2 router
+check ovn-nbctl lsp-set-addresses ls2-ro2 router
+check ovn-nbctl lsp-set-options ls2-ro2 router-port=ro2-ls2
+
+check ovn-nbctl ha-chassis-group-add grp1
+check ovn-nbctl ha-chassis-group-add-chassis grp1 hv1 100
+grp1_uuid=$(ovn-nbctl --columns=_uuid --bare find HA_Chassis_group name=grp1)
+
+check ovn-nbctl ha-chassis-group-add grp2
+check ovn-nbctl ha-chassis-group-add-chassis grp2 hv2 100
+grp2_uuid=$(ovn-nbctl --columns=_uuid --bare find HA_Chassis_group name=grp2)
+
+AS_BOX([Checking that unconnected logical switch ports have no router_addresses])
+
+check_column "" Port_Binding router_addresses logical_port=sw-ro1
+check_column "" Port_Binding router_addresses logical_port=sw-ro2
+
+AS_BOX([Checking that connected logical switch ports have no router_addresses for non-gateway ports])
+
+check ovn-nbctl lsp-set-type sw-ro1 router
+check ovn-nbctl lsp-set-addresses sw-ro1 router
+check ovn-nbctl lsp-set-options sw-ro1 router-port=ro1-sw
+
+check ovn-nbctl lsp-set-type sw-ro2 router
+check ovn-nbctl lsp-set-addresses sw-ro2 router
+check ovn-nbctl --wait=sb lsp-set-options sw-ro2 router-port=ro2-sw
+
+check_column "" Port_Binding router_addresses logical_port=sw-ro1
+check_column "" Port_Binding router_addresses logical_port=sw-ro2
+
+# During every itereation, we will ensure that the switch ports that are not connected
+# to the gateway router port do not have router_addresses on them.
+check_column "" Port_Binding router_addresses logical_port=ls1-ro1
+check_column "" Port_Binding router_addresses logical_port=ls2-ro2
+
+AS_BOX([Checking that NAT addresses are not propagated for non-gateway routers])
+
+check ovn-nbctl lr-nat-add ro1 dnat 10.0.0.100 192.168.1.100
+check ovn-nbctl lr-nat-add ro1 snat 10.0.0.200 192.168.1.200/30
+
+check ovn-nbctl lr-nat-add ro2 dnat 20.0.0.100 192.168.2.100
+check ovn-nbctl --wait=sb lr-nat-add ro2 snat 20.0.0.200 192.168.2.200/30
+
+check_column "" Port_Binding router_addresses logical_port=sw-ro1
+check_column "" Port_Binding router_addresses logical_port=sw-ro2
+
+check_column "" Port_Binding router_addresses logical_port=ls1-ro1
+check_column "" Port_Binding router_addresses logical_port=ls2-ro2
+
+AS_BOX([Checking that NAT addresses are propagated with is_chassis_resident for gateway routers])
+
+check ovn-nbctl lrp-set-gateway-chassis ro1-sw hv1 100
+check ovn-nbctl --wait=sb lrp-set-gateway-chassis ro2-sw hv2 100
+
+check_column "00:00:00:00:00:01 10.0.0.1 is_chassis_resident(\"cr-ro1-sw\") 00:00:00:00:00:01 10.0.0.100 10.0.0.200 is_chassis_resident(\"cr-ro1-sw\")" Port_Binding router_addresses logical_port=sw-ro1
+check_column "00:00:00:00:00:02 20.0.0.1 is_chassis_resident(\"cr-ro2-sw\") 00:00:00:00:00:02 20.0.0.100 20.0.0.200 is_chassis_resident(\"cr-ro2-sw\")" Port_Binding router_addresses logical_port=sw-ro2
+
+check_column "" Port_Binding router_addresses logical_port=ls1-ro1
+check_column "" Port_Binding router_addresses logical_port=ls2-ro2
+
+AS_BOX([Checking that NAT addresses are not propagated for routers with gateway chassis removed])
+
+check ovn-nbctl lrp-del-gateway-chassis ro1-sw hv1
+check ovn-nbctl --wait=sb lrp-del-gateway-chassis ro2-sw hv2
+
+check_column "" Port_Binding router_addresses logical_port=sw-ro1
+check_column "" Port_Binding router_addresses logical_port=sw-ro2
+
+check_column "" Port_Binding router_addresses logical_port=ls1-ro1
+check_column "" Port_Binding router_addresses logical_port=ls2-ro2
+
+AS_BOX([Checking that NAT addresses are propagated with is_chassis_resident for routers with ha_chassis_group])
+
+check ovn-nbctl set logical_router_port ro1-sw ha_chassis_group="$grp1_uuid"
+check ovn-nbctl --wait=sb set logical_router_port ro2-sw ha_chassis_group="$grp2_uuid"
+
+check_column "00:00:00:00:00:01 10.0.0.1 is_chassis_resident(\"cr-ro1-sw\") 00:00:00:00:00:01 10.0.0.100 10.0.0.200 is_chassis_resident(\"cr-ro1-sw\")" Port_Binding router_addresses logical_port=sw-ro1
+check_column "00:00:00:00:00:02 20.0.0.1 is_chassis_resident(\"cr-ro2-sw\") 00:00:00:00:00:02 20.0.0.100 20.0.0.200 is_chassis_resident(\"cr-ro2-sw\")" Port_Binding router_addresses logical_port=sw-ro2
+
+check_column "" Port_Binding router_addresses logical_port=ls1-ro1
+check_column "" Port_Binding router_addresses logical_port=ls2-ro2
+
+AS_BOX([Checking that NAT addresses are not propagated for routers with HA_Chassis_Group removed])
+
+check ovn-nbctl clear logical_router_port ro1-sw ha_chassis_group
+check ovn-nbctl --wait=sb clear logical_router_port ro2-sw ha_chassis_group
+
+check_column "" Port_Binding router_addresses logical_port=sw-ro1
+check_column "" Port_Binding router_addresses logical_port=sw-ro2
+
+check_column "" Port_Binding router_addresses logical_port=ls1-ro1
+check_column "" Port_Binding router_addresses logical_port=ls2-ro2
+
+AS_BOX([Checking that Floating IP NAT addresses are not propagated with no gateway port set])
+
+check ovn-nbctl lr-nat-del ro1
+check ovn-nbctl lr-nat-del ro2
+
+check ovn-nbctl lr-nat-add ro1 dnat_and_snat 10.0.0.100 192.168.1.2 vm1 00:00:00:00:00:01
+check ovn-nbctl lr-nat-add ro2 dnat_and_snat 20.0.0.100 192.168.2.2 vm2 00:00:00:00:00:02
+
+check_column "" Port_Binding router_addresses logical_port=sw-ro1
+check_column "" Port_Binding router_addresses logical_port=sw-ro2
+
+check_column "" Port_Binding router_addresses logical_port=ls1-ro1
+check_column "" Port_Binding router_addresses logical_port=ls2-ro2
+
+AS_BOX([Checking that Floating IP NAT addresses are propagated with is_chassis_resident for gateway routers])
+
+check ovn-nbctl lrp-set-gateway-chassis ro1-sw hv1 100
+check ovn-nbctl --wait=sb lrp-set-gateway-chassis ro2-sw hv2 100
+
+check_column "00:00:00:00:00:01 10.0.0.1 is_chassis_resident(\"cr-ro1-sw\") 00:00:00:00:00:01 10.0.0.100 is_chassis_resident(\"vm1\")" Port_Binding router_addresses logical_port=sw-ro1
+check_column "00:00:00:00:00:02 20.0.0.1 is_chassis_resident(\"cr-ro2-sw\") 00:00:00:00:00:02 20.0.0.100 is_chassis_resident(\"vm2\")" Port_Binding router_addresses logical_port=sw-ro2
+
+check_column "" Port_Binding router_addresses logical_port=ls1-ro1
+check_column "" Port_Binding router_addresses logical_port=ls2-ro2
+
+AS_BOX([Checking that Floating IP NAT addresses are not propagated for routers with gateway chassis removed])
+
+check ovn-nbctl lrp-del-gateway-chassis ro1-sw hv1
+check ovn-nbctl --wait=sb lrp-del-gateway-chassis ro2-sw hv2
+
+check_column "" Port_Binding router_addresses logical_port=sw-ro1
+check_column "" Port_Binding router_addresses logical_port=sw-ro2
+
+check_column "" Port_Binding router_addresses logical_port=ls1-ro1
+check_column "" Port_Binding router_addresses logical_port=ls2-ro2
+
+AS_BOX([Checking that Floating IP NAT addresses are propagated with is_chassis_resident for routers with ha_chassis_group])
+
+grp1_uuid=$(ovn-nbctl --columns=_uuid --bare find HA_Chassis_group name=grp1)
+check ovn-nbctl set logical_router_port ro1-sw ha_chassis_group="$grp1_uuid"
+
+grp2_uuid=$(ovn-nbctl --columns=_uuid --bare find HA_Chassis_group name=grp2)
+check ovn-nbctl --wait=sb set logical_router_port ro2-sw ha_chassis_group="$grp2_uuid"
+
+check_column "00:00:00:00:00:01 10.0.0.1 is_chassis_resident(\"cr-ro1-sw\") 00:00:00:00:00:01 10.0.0.100 is_chassis_resident(\"vm1\")" Port_Binding router_addresses logical_port=sw-ro1
+check_column "00:00:00:00:00:02 20.0.0.1 is_chassis_resident(\"cr-ro2-sw\") 00:00:00:00:00:02 20.0.0.100 is_chassis_resident(\"vm2\")" Port_Binding router_addresses logical_port=sw-ro2
+
+check_column "" Port_Binding router_addresses logical_port=ls1-ro1
+check_column "" Port_Binding router_addresses logical_port=ls2-ro2
+
+AS_BOX([Checking that Floating IP NAT addresses are not propagated for routers with HA_Chassis_Group removed])
+
+check ovn-nbctl clear logical_router_port ro1-sw ha_chassis_group
+check ovn-nbctl --wait=sb clear logical_router_port ro2-sw ha_chassis_group
+
+check_column "" Port_Binding router_addresses logical_port=sw-ro1
+check_column "" Port_Binding router_addresses logical_port=sw-ro2
+
+check_column "" Port_Binding router_addresses logical_port=ls1-ro1
+check_column "" Port_Binding router_addresses logical_port=ls2-ro2
+
+AS_BOX([Checking that Load Balancer VIP addresses are not propagated for routers with no gateway port])
+
+check ovn-nbctl lr-nat-del ro1
+check ovn-nbctl lr-nat-del ro2
+
+check ovn-nbctl lb-add lb1 10.0.0.100 192.168.1.2
+check ovn-nbctl lr-lb-add ro1 lb1
+
+check ovn-nbctl lb-add lb2 20.0.0.100 192.168.2.2
+check ovn-nbctl lr-lb-add ro2 lb2
+
+check_column "" Port_Binding router_addresses logical_port=sw-ro1
+check_column "" Port_Binding router_addresses logical_port=sw-ro2
+
+AS_BOX([Checking that Load Balancer VIP addresses are propagated with is_chassis_resident for gateway routers])
+
+check ovn-nbctl lrp-set-gateway-chassis ro1-sw hv1 100
+check ovn-nbctl --wait=sb lrp-set-gateway-chassis ro2-sw hv2 100
+
+check_column "00:00:00:00:00:01 10.0.0.1 is_chassis_resident(\"cr-ro1-sw\") 00:00:00:00:00:01 10.0.0.100 is_chassis_resident(\"cr-ro1-sw\")" Port_Binding router_addresses logical_port=sw-ro1
+check_column "00:00:00:00:00:02 20.0.0.1 is_chassis_resident(\"cr-ro2-sw\") 00:00:00:00:00:02 20.0.0.100 is_chassis_resident(\"cr-ro2-sw\")" Port_Binding router_addresses logical_port=sw-ro2
+
+check_column "" Port_Binding router_addresses logical_port=ls1-ro1
+check_column "" Port_Binding router_addresses logical_port=ls2-ro2
+
+AS_BOX([Checking that Load Balancer VIP addresses are not propagated for routers with gateway chassis removed])
+
+check ovn-nbctl lrp-del-gateway-chassis ro1-sw hv1
+check ovn-nbctl --wait=sb lrp-del-gateway-chassis ro2-sw hv2
+
+check_column "" Port_Binding router_addresses logical_port=sw-ro1
+check_column "" Port_Binding router_addresses logical_port=sw-ro2
+
+check_column "" Port_Binding router_addresses logical_port=ls1-ro1
+check_column "" Port_Binding router_addresses logical_port=ls2-ro2
+
+AS_BOX([Checking that Load Balancer VIP addresses are propagated with is_chassis_resident for routers with ha_chassis_group])
+
+grp1_uuid=$(ovn-nbctl --columns=_uuid --bare find HA_Chassis_group name=grp1)
+check ovn-nbctl set logical_router_port ro1-sw ha_chassis_group="$grp1_uuid"
+
+grp2_uuid=$(ovn-nbctl --columns=_uuid --bare find HA_Chassis_group name=grp2)
+check ovn-nbctl --wait=sb set logical_router_port ro2-sw ha_chassis_group="$grp2_uuid"
+
+check_column "00:00:00:00:00:01 10.0.0.1 is_chassis_resident(\"cr-ro1-sw\") 00:00:00:00:00:01 10.0.0.100 is_chassis_resident(\"cr-ro1-sw\")" Port_Binding router_addresses logical_port=sw-ro1
+check_column "00:00:00:00:00:02 20.0.0.1 is_chassis_resident(\"cr-ro2-sw\") 00:00:00:00:00:02 20.0.0.100 is_chassis_resident(\"cr-ro2-sw\")" Port_Binding router_addresses logical_port=sw-ro2
+
+check_column "" Port_Binding router_addresses logical_port=ls1-ro1
+check_column "" Port_Binding router_addresses logical_port=ls2-ro2
+
+AS_BOX([Checking that Load Balancer VIP addresses are not propagated for routers with HA_Chassis_Group removed])
+
+check ovn-nbctl clear logical_router_port ro1-sw ha_chassis_group
+check ovn-nbctl --wait=sb clear logical_router_port ro2-sw ha_chassis_group
+
+check_column "" Port_Binding router_addresses logical_port=sw-ro1
+check_column "" Port_Binding router_addresses logical_port=sw-ro2
+
+check_column "" Port_Binding router_addresses logical_port=ls1-ro1
+check_column "" Port_Binding router_addresses logical_port=ls2-ro2
+
+AT_CLEANUP
northd currently stores logical switch port's configured "nat-addresses" in the southbound Port_Binding "nat_addresses" column. This allows for explicit configuration of which NAT addresses should be broadcast in gARP messages by OVN. This adds a similar column, "router_addresses" to the Port_Binding. The difference is that this column contains all NAT, load balancer, and router interface addresses, no matter the northbound configuration. This column will be used in an upcoming commit. Signed-off-by: Mark Michelson <mmichels@redhat.com> --- northd/ovn-northd.c | 217 +++++++++++++++++++++++++------------ northd/ovn_northd.dl | 45 ++++++-- ovn-sb.ovsschema | 5 +- ovn-sb.xml | 20 ++++ tests/ovn-northd.at | 253 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 461 insertions(+), 79 deletions(-)