[ovs-dev] [PATCH ovn v9 2/4] northd: Add IP routing and ARP resolution flows for NAT/LB addresses.
Numan Siddique
numans at ovn.org
Wed Jul 7 17:28:55 UTC 2021
On Wed, Jun 30, 2021 at 7:57 PM Mark Michelson <mmichels at redhat.com> wrote:
>
> Dealing with NAT and load balancer IPs has been a bit of a pain point.
> It requires creating static routes if east-west traffic to those
> addresses is desired. Further, it requires ARPs to be sent between the
> logical routers in order to create MAC Bindings.
>
> This commit seeks to make things easier. NAT and load balancer addresess
> automatically have IP routing logical flows and ARP resolution logical
> flows created for reachable routers. This eliminates the need to create
> static routes, and it also eliminates the need for ARPs to be sent
> between logical routers.
>
> In this commit, the behavior is not optional. The next commit will
> introduce configuration to make the behavior optional.
>
> Signed-off-by: Mark Michelson <mmichels at redhat.com>
Hi Mark,
There is one small problem. Please see below. With that addressed:
Acked-by: Numan Siddique <numans at ovn.org>
Numan
> ---
> northd/ovn-northd.c | 129 +++++++++++++++++++++++++-
> northd/ovn_northd.dl | 57 ++++++++++++
> tests/ovn-northd.at | 214 +++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 395 insertions(+), 5 deletions(-)
>
> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> index 694c3b2c4..58132bc5c 100644
> --- a/northd/ovn-northd.c
> +++ b/northd/ovn-northd.c
> @@ -1378,6 +1378,21 @@ build_datapaths(struct northd_context *ctx, struct hmap *datapaths,
> }
> }
>
> +/* Structure representing logical router port
> + * routable addresses. This includes DNAT and Load Balancer
> + * addresses. This structure will only be filled in if the
> + * router port is a gateway router port. Otherwise, all pointers
> + * will be NULL and n_addrs will be 0.
> + */
> +struct ovn_port_routable_addresses {
> + /* Array of address strings suitable for writing to a database table */
> + char **addresses;
> + /* The addresses field parsed into component parts */
> + struct lport_addresses *laddrs;
> + /* Number of items in each of the above arrays */
> + size_t n_addrs;
> +};
> +
> /* A logical switch port or logical router port.
> *
> * In steady state, an ovn_port points to a northbound Logical_Switch_Port
> @@ -1421,6 +1436,8 @@ struct ovn_port {
>
> struct lport_addresses lrp_networks;
>
> + struct ovn_port_routable_addresses routables;
> +
> /* Logical port multicast data. */
> struct mcast_port_info mcast_info;
>
> @@ -1447,6 +1464,44 @@ struct ovn_port {
> struct ovs_list list; /* In list of similar records. */
> };
>
> +static void
> +destroy_routable_addresses(struct ovn_port_routable_addresses *ra)
> +{
> + for (size_t i = 0; i < ra->n_addrs; i++) {
> + free(ra->addresses[i]);
> + destroy_lport_addresses(&ra->laddrs[i]);
> + }
> + free(ra->addresses);
> + free(ra->laddrs);
> +}
> +
> +static char **get_nat_addresses(const struct ovn_port *op, size_t *n);
> +
> +static void
> +assign_routable_addresses(struct ovn_port *op)
> +{
> + size_t n;
> + char **nats = get_nat_addresses(op, &n);
> +
> + if (!nats) {
> + return;
> + }
> +
> + struct lport_addresses *laddrs = xcalloc(n, sizeof(*laddrs));
> + for (size_t i = 0; i < n; i++) {
> + int ofs;
> + if (!extract_addresses(nats[i], &laddrs[i], &ofs)){
> + continue;
> + }
> + }
> +
> + /* Everything seems to have worked out */
> + op->routables.addresses = nats;
> + op->routables.laddrs = laddrs;
> + op->routables.n_addrs = n;
The n_addrs would have the wrong value if 'extract_addresses()' fails.
You probably want to maintain another variable for n_addrs.
Thanks
Numan
> +}
> +
> +
> static void
> ovn_port_set_nb(struct ovn_port *op,
> const struct nbrec_logical_switch_port *nbsp,
> @@ -1496,6 +1551,8 @@ ovn_port_destroy(struct hmap *ports, struct ovn_port *port)
> }
> free(port->ps_addrs);
>
> + destroy_routable_addresses(&port->routables);
> +
> destroy_lport_addresses(&port->lrp_networks);
> free(port->json_key);
> free(port->key);
> @@ -2403,6 +2460,8 @@ join_logical_ports(struct northd_context *ctx,
> * use during flow creation. */
> od->l3dgw_port = op;
> od->l3redirect_port = crp;
> +
> + assign_routable_addresses(op);
> }
> }
> }
> @@ -2486,7 +2545,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;
> @@ -3067,7 +3126,6 @@ ovn_port_update_sbrec(struct northd_context *ctx,
> } else {
> sbrec_port_binding_set_options(op->sb, NULL);
> }
> -
> const char *nat_addresses = smap_get(&op->nbsp->options,
> "nat-addresses");
> size_t n_nats = 0;
> @@ -3123,6 +3181,7 @@ ovn_port_update_sbrec(struct northd_context *ctx,
> if (add_router_port_garp) {
> struct ds garp_info = DS_EMPTY_INITIALIZER;
> ds_put_format(&garp_info, "%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",
> @@ -3139,7 +3198,6 @@ ovn_port_update_sbrec(struct northd_context *ctx,
> nats[n_nats - 1] = ds_steal_cstr(&garp_info);
> ds_destroy(&garp_info);
> }
> -
> sbrec_port_binding_set_nat_addresses(op->sb,
> (const char **) nats, n_nats);
> for (size_t i = 0; i < n_nats; i++) {
> @@ -9910,7 +9968,7 @@ build_ND_RA_flows_for_lrouter(struct ovn_datapath *od, struct hmap *lflows)
> */
> static void
> build_ip_routing_flows_for_lrouter_port(
> - struct ovn_port *op, struct hmap *lflows)
> + struct ovn_port *op, struct hmap *ports,struct hmap *lflows)
> {
> if (op->nbrp) {
>
> @@ -9927,6 +9985,31 @@ build_ip_routing_flows_for_lrouter_port(
> op->lrp_networks.ipv6_addrs[i].plen, NULL, false,
> &op->nbrp->header_, false);
> }
> + } else if (lsp_is_router(op->nbsp)) {
> + struct ovn_port *peer = ovn_port_get_peer(ports, op);
> + if (!peer || !peer->nbrp || !peer->lrp_networks.n_ipv4_addrs) {
> + return;
> + }
> +
> + for (int i = 0; i < op->od->n_router_ports; i++) {
> + struct ovn_port *router_port = ovn_port_get_peer(
> + ports, op->od->router_ports[i]);
> + if (!router_port || !router_port->nbrp || router_port == peer) {
> + continue;
> + }
> +
> + struct ovn_port_routable_addresses *ra = &router_port->routables;
> + for (size_t j = 0; j < ra->n_addrs; j++) {
> + struct lport_addresses *laddrs = &ra->laddrs[j];
> + for (size_t k = 0; k < laddrs->n_ipv4_addrs; k++) {
> + add_route(lflows, peer->od, peer,
> + peer->lrp_networks.ipv4_addrs[0].addr_s,
> + laddrs->ipv4_addrs[k].network_s,
> + laddrs->ipv4_addrs[k].plen, NULL, false,
> + &peer->nbrp->header_, false);
> + }
> + }
> + }
> }
> }
>
> @@ -10105,6 +10188,36 @@ build_arp_resolve_flows_for_lrouter(
> }
> }
>
> +static void
> +routable_addresses_to_lflows(struct hmap *lflows, struct ovn_port *router_port,
> + struct ovn_port *peer, struct ds *match,
> + struct ds *actions)
> +{
> + struct ovn_port_routable_addresses *ra = &router_port->routables;
> + if (!ra->n_addrs) {
> + return;
> + }
> +
> + for (size_t i = 0; i < ra->n_addrs; i++) {
> + ds_clear(match);
> + ds_put_format(match, "outport == %s && "REG_NEXT_HOP_IPV4" == {", peer->json_key);
> + bool first = true;
> + for (size_t j = 0; j < ra->laddrs[i].n_ipv4_addrs; j++) {
> + if (!first) {
> + ds_put_cstr(match, ", ");
> + }
> + ds_put_cstr(match, ra->laddrs[i].ipv4_addrs[j].addr_s);
> + first = false;
> + }
> + ds_put_cstr(match, "}");
> +
> + ds_clear(actions);
> + ds_put_format(actions, "eth.dst = %s; next;", ra->laddrs[i].ea_s);
> + ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP_RESOLVE, 100,
> + ds_cstr(match), ds_cstr(actions));
> + }
> +}
> +
> /* Local router ingress table ARP_RESOLVE: ARP Resolution.
> *
> * Any unicast packet that reaches this table is an IP packet whose
> @@ -10427,6 +10540,12 @@ build_arp_resolve_flows_for_lrouter_port(
> ds_cstr(match), ds_cstr(actions),
> &op->nbsp->header_);
> }
> +
> + if (smap_get(&peer->od->nbr->options, "chassis") ||
> + (peer->od->l3dgw_port && peer == peer->od->l3dgw_port)) {
> + routable_addresses_to_lflows(lflows, router_port, peer,
> + match, actions);
> + }
> }
> }
>
> @@ -11972,7 +12091,7 @@ build_lswitch_and_lrouter_iterate_by_op(struct ovn_port *op,
> &lsi->actions);
> build_neigh_learning_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
> &lsi->actions);
> - build_ip_routing_flows_for_lrouter_port(op, lsi->lflows);
> + build_ip_routing_flows_for_lrouter_port(op, lsi->ports, lsi->lflows);
> build_ND_RA_flows_for_lrouter_port(op, lsi->lflows, &lsi->match,
> &lsi->actions);
> build_arp_resolve_flows_for_lrouter_port(op, lsi->lflows, lsi->ports,
> diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl
> index ce6680e97..35d40ff5a 100644
> --- a/northd/ovn_northd.dl
> +++ b/northd/ovn_northd.dl
> @@ -23,6 +23,7 @@ import multicast
> import helpers
> import ipam
> import vec
> +import set
>
> index Logical_Flow_Index() on sb::Out_Logical_Flow()
>
> @@ -6467,6 +6468,45 @@ Route(key, dst.port, dst.src_ip, Some{dst.nexthop}) :-
> dsts.size() == 1,
> Some{var dst} = dsts.nth(0).
>
> +/* Create routes from peer to port's routable addresses */
> +Route(key, peer, src_ip, None) :-
> + RouterPortRoutableAddresses(port, addresses),
> + FirstHopRouterPortRoutableAddresses(port, peer_uuid),
> + peer_lrp in &nb::Logical_Router_Port(._uuid = peer_uuid),
> + peer in &RouterPort(.lrp = peer_lrp, .networks = networks),
> + Some{var src} = networks.ipv4_addrs.first(),
> + var src_ip = IPv4{src.addr},
> + var addr = FlatMap(addresses),
> + var ip4_addr = FlatMap(addr.ipv4_addrs),
> + var key = RouteKey{DstIp, IPv4{ip4_addr.addr}, ip4_addr.plen}.
> +
> +/* This relation indicates that logical router port "port" has routable
> + * addresses (i.e. DNAT and Load Balancer VIPs) and that logical router
> + * port "peer" is reachable via a hop across a single logical switch.
> + */
> +relation FirstHopRouterPortRoutableAddresses(
> + port: uuid,
> + peer: uuid)
> +FirstHopRouterPortRoutableAddresses(port_uuid, peer_uuid) :-
> + FirstHopLogicalRouter(r1, ls),
> + FirstHopLogicalRouter(r2, ls),
> + r1 != r2,
> + LogicalRouterPort(port_uuid, r1),
> + LogicalRouterPort(peer_uuid, r2),
> + RouterPortRoutableAddresses(.rport = port_uuid),
> + lrp in &nb::Logical_Router_Port(._uuid = port_uuid),
> + peer_lrp in &nb::Logical_Router_Port(._uuid = peer_uuid),
> + LogicalSwitchRouterPort(_, lrp.name, ls),
> + LogicalSwitchRouterPort(_, peer_lrp.name, ls).
> +
> +relation RouterPortRoutableAddresses(
> + rport: uuid,
> + addresses: Set<lport_addresses>)
> +RouterPortRoutableAddresses(port.lrp._uuid, addresses) :-
> + port in &RouterPort(.is_redirect = true),
> + var addresses = get_nat_addresses(port).filter_map(extract_addresses),
> + addresses != set_empty().
> +
> /* Return a vector of pairs (1, set[0]), ... (n, set[n - 1]). */
> function numbered_vec(set: Set<'A>) : Vec<(bit<16>, 'A)> = {
> var vec = vec_with_capacity(set.size());
> @@ -6954,6 +6994,23 @@ Flow(.logical_datapath = lr_uuid,
> snat_ips.contains_key(IPv6{addr.addr}),
> var match_ips = "${addr.addr}".group_by((lr_uuid, lrp_uuid)).to_vec().
>
> +/* Create ARP resolution flows for NAT and LB addresses for first hop
> + * logical routers
> + */
> +Flow(.logical_datapath = peer.router._uuid,
> + .stage = s_ROUTER_IN_ARP_RESOLVE(),
> + .priority = 100,
> + .__match = "outport == ${peer.json_name} && " ++ rEG_NEXT_HOP() ++ " == {${ips}}",
> + .actions = "eth.dst = ${addr.ea}; next;",
> + .external_ids = stage_hint(lrp._uuid)) :-
> + RouterPortRoutableAddresses(port, addresses),
> + FirstHopRouterPortRoutableAddresses(port, peer_uuid),
> + peer in &RouterPort(.lrp = lrp),
> + lrp._uuid == peer_uuid,
> + not peer.router.options.get_bool_def("dynamic_neigh_routers", false),
> + var addr = FlatMap(addresses),
> + var ips = addr.ipv4_addrs.map(|a| a.addr.to_string()).join(", ").
> +
> /* This is a logical switch port that backs a VM or a container.
> * Extract its addresses. For each of the address, go through all
> * the router ports attached to the switch (to which this port
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index 2c811f094..feb38ea5e 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -3787,3 +3787,217 @@ AT_CHECK([grep -w "ls_in_dhcp_options" sw0flows | sort], [0], [dnl
>
> 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 -- NAT and Load Balancer flows])
> +
> +# Determine if expected flows are present. The only parameter to this
> +# function is the number of expected flows per NAT destination address.
> +# This should always be either 0 or 1. 0 means that we do not expect
> +# lflows to be present. 1 means we expect an lflow to be present
> +check_lflows() {
> + expected=$1
> + ro1_flows=$(ovn-sbctl lflow-list ro1)
> +
> + ro1_ip_routing=$(grep lr_in_ip_routing <<< "$ro1_flows")
> + match=$(grep -c "match=(ip4.dst == 20.0.0.100/32)" <<< "$ro1_ip_routing")
> + AT_CHECK([test "$expected" = "$match"])
> +
> + ro1_arp_resolve=$(grep lr_in_arp_resolve <<< "$ro1_flows")
> + match=$(grep -c 'match=(outport == "ro1-sw" && reg0 == {20.0.0.100})' <<< "$ro1_arp_resolve")
> + AT_CHECK([test "$expected" = "$match"])
> +
> + ro2_flows=$(ovn-sbctl lflow-list ro2)
> +
> + ro2_ip_routing=$(grep lr_in_ip_routing <<< "$ro2_flows")
> + match=$(grep -c "match=(ip4.dst == 10.0.0.100/32)" <<< "$ro2_ip_routing")
> + AT_CHECK([test "$expected" = "$match"])
> +
> + ro2_arp_resolve=$(grep lr_in_arp_resolve <<< "$ro2_flows")
> + match=$(grep -c 'match=(outport == "ro2-sw" && reg0 == {10.0.0.100})' <<< "$ro2_arp_resolve")
> + AT_CHECK([test "$expected" = "$match"])
> +}
> +
> +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 generate no lflows])
> +
> +check_lflows 0
> +
> +AS_BOX([Checking that connected logical switch ports have no lflows 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_lflows 0
> +
> +AS_BOX([Checking that NAT flows are not installed 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 ro2 dnat 20.0.0.100 192.168.2.100
> +
> +check_lflows 0
> +
> +AS_BOX([Checking that NAT flows are installed 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_lflows 1
> +
> +AS_BOX([Checking that NAT flows are not installed 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_lflows 0
> +
> +AS_BOX([Checking that NAT flows are installed 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_lflows 1
> +
> +AS_BOX([Checking that NAT flows are not installed 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_lflows 0
> +
> +AS_BOX([Checking that Floating IP NAT flows are not installed 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_lflows 0
> +
> +AS_BOX([Checking that Floating IP NAT flows are installed 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_lflows 1
> +
> +AS_BOX([Checking that Floating IP NAT flows are not installed 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_lflows 0
> +
> +AS_BOX([Checking that Floating IP NAT flows are installed 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_lflows 1
> +
> +AS_BOX([Checking that Floating IP NAT flows are not installed 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_lflows 0
> +
> +AS_BOX([Checking that Load Balancer VIP flows are not installed 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_lflows 0
> +
> +AS_BOX([Checking that Load Balancer VIP flows are installed 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_lflows 1
> +
> +AS_BOX([Checking that Load Balancer VIP flows are not installed 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_lflows 0
> +
> +AS_BOX([Checking that Load Balancer VIP flows are installed 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_lflows 1
> +
> +AS_BOX([Checking that Load Balancer VIP flows are not iinstalled 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_lflows 0
> +
> +AT_CLEANUP
> --
> 2.31.1
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
More information about the dev
mailing list