[ovs-dev] [PATCH v4 ovn 5/5] ovn-northd: Minimize number of ARP/NS responder flows for DNAT.

Numan Siddique numans at ovn.org
Mon Jul 6 10:57:19 UTC 2020


On Sat, Jul 4, 2020 at 12:05 AM Dumitru Ceara <dceara at redhat.com> wrote:

> Most ARP/NS responder flows can be configured per datapath instead of per
> router port.
>
> The only exception is with distributed gateway router ports which need
> special treatment. This patch changes the ARP/NS responder behavior and
> adds:
> - Priority 92 flows to reply to ARP requests on distributed gateway router
>   ports, on the chassis where the DNAT entry is bound.
> - Priority 91 flows to drop ARP requests on distributed gateway router
> ports,
>   on chassis where the DNAT entry is not bound.
> - Priority 90 flows to reply to ARP requests on all other router ports.
> This
>   last type of flows is programmed exactly once per logical router limiting
>   the total number of required logical flows.
>
> Suggested-by: Han Zhou <hzhou at ovn.org>
> Reported-by: Girish Moodalbail <gmoodalbail at gmail.com>
> Reported-at:
> https://mail.openvswitch.org/pipermail/ovs-discuss/2020-June/050186.html
> Signed-off-by: Dumitru Ceara <dceara at redhat.com>
>

Acked-by: Numan Siddique <numans at ovn.org>

Thanks
Numan


> ---
>  northd/ovn-northd.8.xml |   16 ++
>  northd/ovn-northd.c     |  342
> +++++++++++++++++++++++++++++------------------
>  tests/ovn-northd.at     |   65 +++++----
>  tests/ovn.at            |    8 +
>  4 files changed, 260 insertions(+), 171 deletions(-)
>
> diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
> index 84224ff..11607c0 100644
> --- a/northd/ovn-northd.8.xml
> +++ b/northd/ovn-northd.8.xml
> @@ -1857,9 +1857,8 @@ nd_na_router {
>            IPv4: For a configured DNAT IP address or a load balancer
>            IPv4 VIP <var>A</var>, for each router port <var>P</var> with
>            Ethernet address <var>E</var>, a priority-90 flow matches
> -          <code>inport == <var>P</var> && arp.op == 1 &&
> -          arp.tpa == <var>A</var></code> (ARP request)
> -          with the following actions:
> +          <code>arp.op == 1 && arp.tpa == <var>A</var></code>
> +          (ARP request) with the following actions:
>          </p>
>
>          <pre>
> @@ -1876,6 +1875,11 @@ output;
>          </pre>
>
>          <p>
> +          IPv4: For a configured load balancer IPv4 VIP, a similar flow is
> +          added with the additional match <code>inport ==
> <var>P</var></code>.
> +        </p>
> +
> +        <p>
>            If the router port <var>P</var> is a distributed gateway router
>            port, then the <code>is_chassis_resident(<var>P</var>)</code> is
>            also added in the match condition for the load balancer IPv4
> @@ -1922,9 +1926,11 @@ nd_na {
>          <ul>
>            <li>
>              If the corresponding NAT rule cannot be handled in a
> -            distributed manner, then this flow is only programmed on
> +            distributed manner, then a priority-92 flow is programmed on
>              the gateway port instance on the
> -            <code>redirect-chassis</code>.  This behavior avoids
> +            <code>redirect-chassis</code>.  A priority-91 drop flow is
> +            programmed on the other chassis when ARP requests/NS packets
> +            are received on the gateway port. This behavior avoids
>              generation of multiple ARP responses from different chassis,
>              and allows upstream MAC learning to point to the
>              <code>redirect-chassis</code>.
> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> index 2dc4e20..5643317 100644
> --- a/northd/ovn-northd.c
> +++ b/northd/ovn-northd.c
> @@ -8054,7 +8054,7 @@ lrouter_nat_is_stateless(const struct nbrec_nat *nat)
>  static void
>  build_lrouter_arp_flow(struct ovn_datapath *od, struct ovn_port *op,
>                         const char *ip_address, const char *eth_addr,
> -                       struct ds *extra_match, uint16_t priority,
> +                       struct ds *extra_match, bool drop, uint16_t
> priority,
>                         struct hmap *lflows, const struct ovsdb_idl_row
> *hint)
>  {
>      struct ds match = DS_EMPTY_INITIALIZER;
> @@ -8069,20 +8069,24 @@ build_lrouter_arp_flow(struct ovn_datapath *od,
> struct ovn_port *op,
>      if (extra_match && ds_last(extra_match) != EOF) {
>          ds_put_format(&match, " && %s", ds_cstr(extra_match));
>      }
> -    ds_put_format(&actions,
> -                  "eth.dst = eth.src; "
> -                  "eth.src = %s; "
> -                  "arp.op = 2; /* ARP reply */ "
> -                  "arp.tha = arp.sha; "
> -                  "arp.sha = %s; "
> -                  "arp.tpa = arp.spa; "
> -                  "arp.spa = %s; "
> -                  "outport = inport; "
> -                  "flags.loopback = 1; "
> -                  "output;",
> -                  eth_addr,
> -                  eth_addr,
> -                  ip_address);
> +    if (drop) {
> +        ds_put_format(&actions, "drop;");
> +    } else {
> +        ds_put_format(&actions,
> +                      "eth.dst = eth.src; "
> +                      "eth.src = %s; "
> +                      "arp.op = 2; /* ARP reply */ "
> +                      "arp.tha = arp.sha; "
> +                      "arp.sha = %s; "
> +                      "arp.tpa = arp.spa; "
> +                      "arp.spa = %s; "
> +                      "outport = inport; "
> +                      "flags.loopback = 1; "
> +                      "output;",
> +                      eth_addr,
> +                      eth_addr,
> +                      ip_address);
> +    }
>
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT, priority,
>                              ds_cstr(&match), ds_cstr(&actions), hint);
> @@ -8101,7 +8105,7 @@ static void
>  build_lrouter_nd_flow(struct ovn_datapath *od, struct ovn_port *op,
>                        const char *action, const char *ip_address,
>                        const char *sn_ip_address, const char *eth_addr,
> -                      struct ds *extra_match, uint16_t priority,
> +                      struct ds *extra_match, bool drop, uint16_t
> priority,
>                        struct hmap *lflows,
>                        const struct ovsdb_idl_row *hint)
>  {
> @@ -8123,21 +8127,25 @@ build_lrouter_nd_flow(struct ovn_datapath *od,
> struct ovn_port *op,
>          ds_put_format(&match, " && %s", ds_cstr(extra_match));
>      }
>
> -    ds_put_format(&actions,
> -                  "%s { "
> -                    "eth.src = %s; "
> -                    "ip6.src = %s; "
> -                    "nd.target = %s; "
> -                    "nd.tll = %s; "
> -                    "outport = inport; "
> -                    "flags.loopback = 1; "
> -                    "output; "
> -                  "};",
> -                  action,
> -                  eth_addr,
> -                  ip_address,
> -                  ip_address,
> -                  eth_addr);
> +    if (drop) {
> +        ds_put_format(&actions, "drop;");
> +    } else {
> +        ds_put_format(&actions,
> +                      "%s { "
> +                        "eth.src = %s; "
> +                        "ip6.src = %s; "
> +                        "nd.target = %s; "
> +                        "nd.tll = %s; "
> +                        "outport = inport; "
> +                        "flags.loopback = 1; "
> +                        "output; "
> +                      "};",
> +                      action,
> +                      eth_addr,
> +                      ip_address,
> +                      ip_address,
> +                      eth_addr);
> +    }
>
>      ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT, priority,
>                              ds_cstr(&match), ds_cstr(&actions), hint);
> @@ -8327,7 +8335,41 @@ build_lrouter_flows(struct hmap *datapaths, struct
> hmap *ports,
>                        "ip4.dst == 0.0.0.0/8",
>                        "drop;");
>
> -        /* Priority-90 flows reply to ARP requests and ND packets. */
> +        /* Priority-90-92 flows handle ARP requests and ND packets. Most
> are
> +         * per logical port but DNAT addresses can be handled per datapath
> +         * for non gateway router ports.
> +         */
> +        for (int i = 0; i < od->nbr->n_nat; i++) {
> +            struct ovn_nat *nat_entry = &od->nat_entries[i];
> +            const struct nbrec_nat *nat = nat_entry->nb;
> +
> +            /* Skip entries we failed to parse. */
> +            if (!nat_entry_is_valid(nat_entry)) {
> +                continue;
> +            }
> +
> +            if (!strcmp(nat->type, "snat")) {
> +                continue;
> +            }
> +
> +            /* Priority 91 and 92 flows are added for each gateway router
> +             * port to handle the special cases. In case we get the packet
> +             * on a regular port, just reply with the port's ETH address.
> +             */
> +            struct lport_addresses *ext_addrs = &nat_entry->ext_addrs;
> +            if (nat_entry_is_v6(nat_entry)) {
> +                build_lrouter_nd_flow(od, NULL, "nd_na",
> +                                      ext_addrs->ipv6_addrs[0].addr_s,
> +                                      ext_addrs->ipv6_addrs[0].sn_addr_s,
> +                                      REG_INPORT_ETH_ADDR, NULL, false,
> 90,
> +                                      lflows, &nat->header_);
> +            } else {
> +                build_lrouter_arp_flow(od, NULL,
> +                                       ext_addrs->ipv4_addrs[0].addr_s,
> +                                       REG_INPORT_ETH_ADDR, NULL, false,
> 90,
> +                                       lflows, &nat->header_);
> +            }
> +        }
>
>          /* Drop ARP packets (priority 85). ARP request packets for
> router's own
>           * IPs are handled with priority-90 flows.
> @@ -8477,8 +8519,8 @@ build_lrouter_flows(struct hmap *datapaths, struct
> hmap *ports,
>
>              build_lrouter_arp_flow(op->od, op,
>                                     op->lrp_networks.ipv4_addrs[i].addr_s,
> -                                   REG_INPORT_ETH_ADDR, &match, 90,
> lflows,
> -                                   &op->nbrp->header_);
> +                                   REG_INPORT_ETH_ADDR, &match, false, 90,
> +                                   lflows, &op->nbrp->header_);
>          }
>
>          /* A set to hold all load-balancer vips that need ARP responses.
> */
> @@ -8496,7 +8538,7 @@ build_lrouter_flows(struct hmap *datapaths, struct
> hmap *ports,
>
>              build_lrouter_arp_flow(op->od, op,
>                                     ip_address, REG_INPORT_ETH_ADDR,
> -                                   &match, 90, lflows, NULL);
> +                                   &match, false, 90, lflows, NULL);
>          }
>
>          SSET_FOR_EACH (ip_address, &all_ips_v6) {
> @@ -8508,108 +8550,12 @@ build_lrouter_flows(struct hmap *datapaths,
> struct hmap *ports,
>
>              build_lrouter_nd_flow(op->od, op, "nd_na",
>                                    ip_address, NULL, REG_INPORT_ETH_ADDR,
> -                                  &match, 90, lflows, NULL);
> +                                  &match, false, 90, lflows, NULL);
>          }
>
>          sset_destroy(&all_ips_v4);
>          sset_destroy(&all_ips_v6);
>
> -        /* A gateway router can have 2 SNAT IP addresses to force DNATed
> and
> -         * LBed traffic respectively to be SNATed.  In addition, there
> can be
> -         * a number of SNAT rules in the NAT table. */
> -        struct v46_ip *snat_ips = xmalloc(sizeof *snat_ips
> -                                          * (op->od->nbr->n_nat + 2));
> -        size_t n_snat_ips = 0;
> -
> -        struct v46_ip snat_ip;
> -        const char *dnat_force_snat_ip = get_force_snat_ip(op->od, "dnat",
> -                                                           &snat_ip);
> -        if (dnat_force_snat_ip) {
> -            snat_ips[n_snat_ips++] = snat_ip;
> -        }
> -
> -        const char *lb_force_snat_ip = get_force_snat_ip(op->od, "lb",
> -                                                         &snat_ip);
> -        if (lb_force_snat_ip) {
> -            snat_ips[n_snat_ips++] = snat_ip;
> -        }
> -
> -        for (size_t i = 0; i < op->od->nbr->n_nat; i++) {
> -            struct ovn_nat *nat_entry = &op->od->nat_entries[i];
> -            const struct nbrec_nat *nat = nat_entry->nb;
> -
> -            /* Skip entries we failed to parse. */
> -            if (!nat_entry_is_valid(nat_entry)) {
> -                continue;
> -            }
> -
> -            if (!strcmp(nat->type, "snat")) {
> -                if (nat_entry_is_v6(nat_entry)) {
> -                    struct in6_addr *ipv6 =
> -                        &nat_entry->ext_addrs.ipv6_addrs[0].addr;
> -
> -                    snat_ips[n_snat_ips].family = AF_INET6;
> -                    snat_ips[n_snat_ips++].ipv6 = *ipv6;
> -                } else {
> -                    ovs_be32 ip = nat_entry->ext_addrs.ipv4_addrs[0].addr;
> -                    snat_ips[n_snat_ips].family = AF_INET;
> -                    snat_ips[n_snat_ips++].ipv4 = ip;
> -                }
> -                continue;
> -            }
> -
> -            /* Mac address to use when replying to ARP/NS. */
> -            const char *mac_s = REG_INPORT_ETH_ADDR;
> -
> -            /* ARP / ND handling for external IP addresses.
> -             *
> -             * DNAT IP addresses are external IP addresses that need ARP
> -             * handling. */
> -            ds_clear(&match);
> -
> -            if (op->od->l3dgw_port && op == op->od->l3dgw_port) {
> -                struct eth_addr mac;
> -                if (nat->external_mac &&
> -                    eth_addr_from_string(nat->external_mac, &mac)
> -                    && nat->logical_port) {
> -                    /* distributed NAT case, use nat->external_mac */
> -                    mac_s = nat->external_mac;
> -                    /* Traffic with eth.src = nat->external_mac should
> only be
> -                     * sent from the chassis where nat->logical_port is
> -                     * resident, so that upstream MAC learning points to
> the
> -                     * correct chassis.  Also need to avoid generation of
> -                     * multiple ARP responses from different chassis. */
> -                    ds_put_format(&match, "is_chassis_resident(\"%s\")",
> -                                  nat->logical_port);
> -                } else {
> -                    mac_s = REG_INPORT_ETH_ADDR;
> -                    /* Traffic with eth.src =
> l3dgw_port->lrp_networks.ea_s
> -                     * should only be sent from the "redirect-chassis",
> so that
> -                     * upstream MAC learning points to the
> "redirect-chassis".
> -                     * Also need to avoid generation of multiple ARP
> responses
> -                     * from different chassis. */
> -                    if (op->od->l3redirect_port) {
> -                        ds_put_format(&match, "is_chassis_resident(%s)",
> -                                      op->od->l3redirect_port->json_key);
> -                    }
> -                }
> -            }
> -
> -            struct lport_addresses *ext_addrs = &nat_entry->ext_addrs;
> -            if (nat_entry_is_v6(nat_entry)) {
> -                build_lrouter_nd_flow(op->od, op, "nd_na",
> -                                      ext_addrs->ipv6_addrs[0].addr_s,
> -                                      ext_addrs->ipv6_addrs[0].sn_addr_s,
> -                                      mac_s, &match, 90,
> -                                      lflows, &nat->header_);
> -            } else {
> -                build_lrouter_arp_flow(op->od, op,
> -                                       ext_addrs->ipv4_addrs[0].addr_s,
> -                                       mac_s, &match, 90,
> -                                       lflows, &nat->header_);
> -            }
> -        }
> -
>          if (!smap_get(&op->od->nbr->options, "chassis")
>              && !op->od->l3dgw_port) {
>              /* UDP/TCP port unreachable. */
> @@ -8658,6 +8604,50 @@ build_lrouter_flows(struct hmap *datapaths, struct
> hmap *ports,
>              }
>          }
>
> +        /* A gateway router can have 2 SNAT IP addresses to force DNATed
> and
> +         * LBed traffic respectively to be SNATed.  In addition, there
> can be
> +         * a number of SNAT rules in the NAT table. */
> +        struct v46_ip *snat_ips = xmalloc(sizeof *snat_ips
> +                                          * (op->od->nbr->n_nat + 2));
> +        size_t n_snat_ips = 0;
> +
> +        struct v46_ip snat_ip;
> +        const char *dnat_force_snat_ip = get_force_snat_ip(op->od, "dnat",
> +                                                           &snat_ip);
> +        if (dnat_force_snat_ip) {
> +            snat_ips[n_snat_ips++] = snat_ip;
> +        }
> +
> +        const char *lb_force_snat_ip = get_force_snat_ip(op->od, "lb",
> +                                                         &snat_ip);
> +        if (lb_force_snat_ip) {
> +            snat_ips[n_snat_ips++] = snat_ip;
> +        }
> +
> +        for (size_t i = 0; i < op->od->nbr->n_nat; i++) {
> +            struct ovn_nat *nat_entry = &op->od->nat_entries[i];
> +            const struct nbrec_nat *nat = nat_entry->nb;
> +
> +            /* Skip entries we failed to parse. */
> +            if (!nat_entry_is_valid(nat_entry)) {
> +                continue;
> +            }
> +
> +            if (!strcmp(nat->type, "snat")) {
> +                if (nat_entry_is_v6(nat_entry)) {
> +                    struct in6_addr *ipv6 =
> +                        &nat_entry->ext_addrs.ipv6_addrs[0].addr;
> +
> +                    snat_ips[n_snat_ips].family = AF_INET6;
> +                    snat_ips[n_snat_ips++].ipv6 = *ipv6;
> +                } else {
> +                    ovs_be32 ip = nat_entry->ext_addrs.ipv4_addrs[0].addr;
> +                    snat_ips[n_snat_ips].family = AF_INET;
> +                    snat_ips[n_snat_ips++].ipv4 = ip;
> +                }
> +            }
> +        }
> +
>          ds_clear(&match);
>          ds_put_cstr(&match, "ip4.dst == {");
>          bool has_drop_ips = false;
> @@ -8719,6 +8709,90 @@ build_lrouter_flows(struct hmap *datapaths, struct
> hmap *ports,
>          }
>
>          free(snat_ips);
> +
> +        /* ARP/NS packets are taken care of per router. The only exception
> +         * is on the l3dgw_port where we might need to use a different
> +         * ETH address.
> +         */
> +        if (op != op->od->l3dgw_port) {
> +            continue;
> +        }
> +
> +        for (size_t i = 0; i < op->od->nbr->n_nat; i++) {
> +            struct ovn_nat *nat_entry = &op->od->nat_entries[i];
> +            const struct nbrec_nat *nat = nat_entry->nb;
> +
> +            /* Skip entries we failed to parse. */
> +            if (!nat_entry_is_valid(nat_entry)) {
> +                continue;
> +            }
> +
> +            if (!strcmp(nat->type, "snat")) {
> +                continue;
> +            }
> +
> +            /* Mac address to use when replying to ARP/NS. */
> +            const char *mac_s = REG_INPORT_ETH_ADDR;
> +
> +            /* ARP / ND handling for external IP addresses.
> +             *
> +             * DNAT IP addresses are external IP addresses that need ARP
> +             * handling. */
> +
> +            struct eth_addr mac;
> +
> +            ds_clear(&match);
> +            if (nat->external_mac &&
> +                eth_addr_from_string(nat->external_mac, &mac)
> +                && nat->logical_port) {
> +                /* distributed NAT case, use nat->external_mac */
> +                mac_s = nat->external_mac;
> +                /* Traffic with eth.src = nat->external_mac should only be
> +                 * sent from the chassis where nat->logical_port is
> +                 * resident, so that upstream MAC learning points to the
> +                 * correct chassis.  Also need to avoid generation of
> +                 * multiple ARP responses from different chassis. */
> +                ds_put_format(&match, "is_chassis_resident(\"%s\")",
> +                              nat->logical_port);
> +            } else {
> +                mac_s = REG_INPORT_ETH_ADDR;
> +                /* Traffic with eth.src = l3dgw_port->lrp_networks.ea_s
> +                 * should only be sent from the "redirect-chassis", so
> that
> +                 * upstream MAC learning points to the "redirect-chassis".
> +                 * Also need to avoid generation of multiple ARP responses
> +                 * from different chassis. */
> +                if (op->od->l3redirect_port) {
> +                    ds_put_format(&match, "is_chassis_resident(\"%s\")",
> +                                  op->od->l3redirect_port->json_key);
> +                }
> +            }
> +
> +            /* Respond to ARP/NS requests on the chassis that binds the gw
> +             * port. Drop the ARP/NS requests on other chassis.
> +             */
> +            struct lport_addresses *ext_addrs = &nat_entry->ext_addrs;
> +            if (nat_entry_is_v6(nat_entry)) {
> +                build_lrouter_nd_flow(op->od, op, "nd_na",
> +                                      ext_addrs->ipv6_addrs[0].addr_s,
> +                                      ext_addrs->ipv6_addrs[0].sn_addr_s,
> +                                      mac_s, &match, false, 92,
> +                                      lflows, &nat->header_);
> +                build_lrouter_nd_flow(op->od, op, "nd_na",
> +                                      ext_addrs->ipv6_addrs[0].addr_s,
> +                                      ext_addrs->ipv6_addrs[0].sn_addr_s,
> +                                      mac_s, NULL, true, 91,
> +                                      lflows, &nat->header_);
> +            } else {
> +                build_lrouter_arp_flow(op->od, op,
> +                                       ext_addrs->ipv4_addrs[0].addr_s,
> +                                       mac_s, &match, false, 92,
> +                                       lflows, &nat->header_);
> +                build_lrouter_arp_flow(op->od, op,
> +                                       ext_addrs->ipv4_addrs[0].addr_s,
> +                                       mac_s, NULL, true, 91,
> +                                       lflows, &nat->header_);
> +            }
> +        }
>      }
>
>      /* DHCPv6 reply handling */
> @@ -8793,8 +8867,8 @@ build_lrouter_flows(struct hmap *datapaths, struct
> hmap *ports,
>              build_lrouter_nd_flow(op->od, op, "nd_na_router",
>                                    op->lrp_networks.ipv6_addrs[i].addr_s,
>
>  op->lrp_networks.ipv6_addrs[i].sn_addr_s,
> -                                  REG_INPORT_ETH_ADDR, &match, 90, lflows,
> -                                  &op->nbrp->header_);
> +                                  REG_INPORT_ETH_ADDR, &match, false, 90,
> +                                  lflows, &op->nbrp->header_);
>          }
>
>          /* UDP/TCP port unreachable */
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index a3fb7ef..5693f84 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -1594,33 +1594,24 @@ action=(xreg0[[0..47]] = 00:00:00:00:01:00; next;)
>  # Ingress router port ETH address is used for ARP reply/NA in
> lr_in_ip_input.
>  AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_ip_input.*priority=90" |
> grep "arp\|nd" | sort], [0], [dnl
>    table=3 (lr_in_ip_input     ), priority=90   , dnl
> -match=(inport == "lrp" && arp.op == 1 && arp.tpa == 42.42.42.1 && arp.spa
> == 42.42.42.0/24), dnl
> -action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP
> reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa;
> arp.spa = 42.42.42.1; outport = inport; flags.loopback = 1; output;)
> -  table=3 (lr_in_ip_input     ), priority=90   , dnl
> -match=(inport == "lrp" && arp.op == 1 && arp.tpa == 43.43.43.2), dnl
> +match=(arp.op == 1 && arp.tpa == 43.43.43.2), dnl
>  action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP
> reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa;
> arp.spa = 43.43.43.2; outport = inport; flags.loopback = 1; output;)
>    table=3 (lr_in_ip_input     ), priority=90   , dnl
> -match=(inport == "lrp" && arp.op == 1 && arp.tpa == 43.43.43.3), dnl
> +match=(arp.op == 1 && arp.tpa == 43.43.43.3), dnl
>  action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP
> reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa;
> arp.spa = 43.43.43.3; outport = inport; flags.loopback = 1; output;)
>    table=3 (lr_in_ip_input     ), priority=90   , dnl
> -match=(inport == "lrp" && arp.op == 1 && arp.tpa == 43.43.43.4), dnl
> +match=(arp.op == 1 && arp.tpa == 43.43.43.4), dnl
>  action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP
> reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa;
> arp.spa = 43.43.43.4; outport = inport; flags.loopback = 1; output;)
>    table=3 (lr_in_ip_input     ), priority=90   , dnl
> +match=(inport == "lrp" && arp.op == 1 && arp.tpa == 42.42.42.1 && arp.spa
> == 42.42.42.0/24), dnl
> +action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP
> reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa;
> arp.spa = 42.42.42.1; outport = inport; flags.loopback = 1; output;)
> +  table=3 (lr_in_ip_input     ), priority=90   , dnl
>  match=(inport == "lrp" && ip6.dst == {fe80::200:ff:fe00:1,
> ff02::1:ff00:1} && nd_ns && nd.target == fe80::200:ff:fe00:1), dnl
>  action=(nd_na_router { eth.src = xreg0[[0..47]]; ip6.src =
> fe80::200:ff:fe00:1; nd.target = fe80::200:ff:fe00:1; nd.tll =
> xreg0[[0..47]]; outport = inport; flags.loopback = 1; output; };)
>    table=3 (lr_in_ip_input     ), priority=90   , dnl
>  match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.1 &&
> arp.spa == 43.43.43.0/24), dnl
>  action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP
> reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa;
> arp.spa = 43.43.43.1; outport = inport; flags.loopback = 1; output;)
>    table=3 (lr_in_ip_input     ), priority=90   , dnl
> -match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.2),
> dnl
> -action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP
> reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa;
> arp.spa = 43.43.43.2; outport = inport; flags.loopback = 1; output;)
> -  table=3 (lr_in_ip_input     ), priority=90   , dnl
> -match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.3),
> dnl
> -action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP
> reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa;
> arp.spa = 43.43.43.3; outport = inport; flags.loopback = 1; output;)
> -  table=3 (lr_in_ip_input     ), priority=90   , dnl
> -match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.4),
> dnl
> -action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP
> reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa;
> arp.spa = 43.43.43.4; outport = inport; flags.loopback = 1; output;)
> -  table=3 (lr_in_ip_input     ), priority=90   , dnl
>  match=(inport == "lrp-public" && ip6.dst == {fe80::200:ff:fe00:100,
> ff02::1:ff00:100} && nd_ns && nd.target == fe80::200:ff:fe00:100), dnl
>  action=(nd_na_router { eth.src = xreg0[[0..47]]; ip6.src =
> fe80::200:ff:fe00:100; nd.target = fe80::200:ff:fe00:100; nd.tll =
> xreg0[[0..47]]; outport = inport; flags.loopback = 1; output; };)
>  ])
> @@ -1654,37 +1645,55 @@ action=(xreg0[[0..47]] = 00:00:00:00:01:00; next;)
>
>  # Ingress router port is used for ARP reply/NA in lr_in_ip_input.
>  # xxreg0[0..47] is used unless external_mac is set.
> +# Priority 90 flows (per router).
>  AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_ip_input.*priority=90" |
> grep "arp\|nd" | sort], [0], [dnl
>    table=3 (lr_in_ip_input     ), priority=90   , dnl
> -match=(inport == "lrp" && arp.op == 1 && arp.tpa == 42.42.42.1 && arp.spa
> == 42.42.42.0/24), dnl
> -action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP
> reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa;
> arp.spa = 42.42.42.1; outport = inport; flags.loopback = 1; output;)
> -  table=3 (lr_in_ip_input     ), priority=90   , dnl
> -match=(inport == "lrp" && arp.op == 1 && arp.tpa == 43.43.43.2), dnl
> +match=(arp.op == 1 && arp.tpa == 43.43.43.2), dnl
>  action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP
> reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa;
> arp.spa = 43.43.43.2; outport = inport; flags.loopback = 1; output;)
>    table=3 (lr_in_ip_input     ), priority=90   , dnl
> -match=(inport == "lrp" && arp.op == 1 && arp.tpa == 43.43.43.3), dnl
> +match=(arp.op == 1 && arp.tpa == 43.43.43.3), dnl
>  action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP
> reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa;
> arp.spa = 43.43.43.3; outport = inport; flags.loopback = 1; output;)
>    table=3 (lr_in_ip_input     ), priority=90   , dnl
> -match=(inport == "lrp" && arp.op == 1 && arp.tpa == 43.43.43.4), dnl
> +match=(arp.op == 1 && arp.tpa == 43.43.43.4), dnl
>  action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP
> reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa;
> arp.spa = 43.43.43.4; outport = inport; flags.loopback = 1; output;)
>    table=3 (lr_in_ip_input     ), priority=90   , dnl
> +match=(inport == "lrp" && arp.op == 1 && arp.tpa == 42.42.42.1 && arp.spa
> == 42.42.42.0/24), dnl
> +action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP
> reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa;
> arp.spa = 42.42.42.1; outport = inport; flags.loopback = 1; output;)
> +  table=3 (lr_in_ip_input     ), priority=90   , dnl
>  match=(inport == "lrp" && ip6.dst == {fe80::200:ff:fe00:1,
> ff02::1:ff00:1} && nd_ns && nd.target == fe80::200:ff:fe00:1), dnl
>  action=(nd_na_router { eth.src = xreg0[[0..47]]; ip6.src =
> fe80::200:ff:fe00:1; nd.target = fe80::200:ff:fe00:1; nd.tll =
> xreg0[[0..47]]; outport = inport; flags.loopback = 1; output; };)
>    table=3 (lr_in_ip_input     ), priority=90   , dnl
>  match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.1 &&
> arp.spa == 43.43.43.0/24), dnl
>  action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP
> reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa;
> arp.spa = 43.43.43.1; outport = inport; flags.loopback = 1; output;)
>    table=3 (lr_in_ip_input     ), priority=90   , dnl
> -match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.2 &&
> is_chassis_resident("cr-lrp-public")), dnl
> +match=(inport == "lrp-public" && ip6.dst == {fe80::200:ff:fe00:100,
> ff02::1:ff00:100} && nd_ns && nd.target == fe80::200:ff:fe00:100 &&
> is_chassis_resident("cr-lrp-public")), dnl
> +action=(nd_na_router { eth.src = xreg0[[0..47]]; ip6.src =
> fe80::200:ff:fe00:100; nd.target = fe80::200:ff:fe00:100; nd.tll =
> xreg0[[0..47]]; outport = inport; flags.loopback = 1; output; };)
> +])
> +
> +# Priority 91 drop flows (per distributed gw port), if port is not
> resident.
> +AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_ip_input.*priority=91" |
> grep "arp\|nd" | sort], [0], [dnl
> +  table=3 (lr_in_ip_input     ), priority=91   , dnl
> +match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.2),
> dnl
> +action=(drop;)
> +  table=3 (lr_in_ip_input     ), priority=91   , dnl
> +match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.3),
> dnl
> +action=(drop;)
> +  table=3 (lr_in_ip_input     ), priority=91   , dnl
> +match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.4),
> dnl
> +action=(drop;)
> +])
> +
> +# Priority 92 ARP/NS responders (per distributed gw port), if port is
> resident.
> +AT_CHECK([ovn-sbctl lflow-list | grep -E "lr_in_ip_input.*priority=92" |
> grep "arp\|nd" | sort], [0], [dnl
> +  table=3 (lr_in_ip_input     ), priority=92   , dnl
> +match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.2 &&
> is_chassis_resident(""cr-lrp-public"")), dnl
>  action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP
> reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa;
> arp.spa = 43.43.43.2; outport = inport; flags.loopback = 1; output;)
> -  table=3 (lr_in_ip_input     ), priority=90   , dnl
> -match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.3 &&
> is_chassis_resident("cr-lrp-public")), dnl
> +  table=3 (lr_in_ip_input     ), priority=92   , dnl
> +match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.3 &&
> is_chassis_resident(""cr-lrp-public"")), dnl
>  action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP
> reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa = arp.spa;
> arp.spa = 43.43.43.3; outport = inport; flags.loopback = 1; output;)
> -  table=3 (lr_in_ip_input     ), priority=90   , dnl
> +  table=3 (lr_in_ip_input     ), priority=92   , dnl
>  match=(inport == "lrp-public" && arp.op == 1 && arp.tpa == 43.43.43.4 &&
> is_chassis_resident("ls-vm")), dnl
>  action=(eth.dst = eth.src; eth.src = 00:00:00:00:00:02; arp.op = 2; /*
> ARP reply */ arp.tha = arp.sha; arp.sha = 00:00:00:00:00:02; arp.tpa =
> arp.spa; arp.spa = 43.43.43.4; outport = inport; flags.loopback = 1;
> output;)
> -  table=3 (lr_in_ip_input     ), priority=90   , dnl
> -match=(inport == "lrp-public" && ip6.dst == {fe80::200:ff:fe00:100,
> ff02::1:ff00:100} && nd_ns && nd.target == fe80::200:ff:fe00:100 &&
> is_chassis_resident("cr-lrp-public")), dnl
> -action=(nd_na_router { eth.src = xreg0[[0..47]]; ip6.src =
> fe80::200:ff:fe00:100; nd.target = fe80::200:ff:fe00:100; nd.tll =
> xreg0[[0..47]]; outport = inport; flags.loopback = 1; output; };)
>  ])
>
>  # xreg0[0..47] isn't used anywhere else.
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 1a1cfbf..9522b55 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -19336,7 +19336,7 @@ OVS_WAIT_UNTIL([
>  send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0
> 0 121)
>
>  # Verify that the ARP request is replied to from hv1 and not hv2.
>
> -match_arp_req="priority=90.*${match_r1_metadata}.*arp_tpa=10.0.0.121,arp_op=1"
>
> +match_arp_req="priority=92.*${match_r1_metadata}.*arp_tpa=10.0.0.121,arp_op=1"
>
>  as hv1
>  OVS_WAIT_UNTIL([
> @@ -19356,7 +19356,7 @@ OVS_WAIT_UNTIL([
>  send_arp_request 1 0 ${src_mac} $(ip_to_hex 10 0 0 254) $(ip_to_hex 10 0
> 0 122)
>
>  # Verify that the ARP request is replied to from hv2 and not hv1.
>
> -match_arp_req="priority=90.*${match_r1_metadata}.*arp_tpa=10.0.0.122,arp_op=1"
>
> +match_arp_req="priority=92.*${match_r1_metadata}.*arp_tpa=10.0.0.122,arp_op=1"
>
>  as hv2
>  OVS_WAIT_UNTIL([
> @@ -19400,7 +19400,7 @@ dst_ipv6=00100000000000000000000000000121
>  send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 72dd
>
>  # Verify that the ND_NS is replied to from hv1 and not hv2.
>
> -match_nd_ns="priority=90.*${match_r1_metadata}.*icmp_type=135.*nd_target=10::121"
>
> +match_nd_ns="priority=92.*${match_r1_metadata}.*icmp_type=135.*nd_target=10::121"
>
>  as hv1
>  OVS_WAIT_UNTIL([
> @@ -19422,7 +19422,7 @@ dst_ipv6=00100000000000000000000000000122
>  send_nd_ns 1 0 ${src_mac} ${src_ipv6} ${dst_ipv6} 72db
>
>  # Verify that the ND_NS is replied to from hv2 and not hv1.
>
> -match_nd_ns="priority=90.*${match_r1_metadata}.*icmp_type=135.*nd_target=10::122"
>
> +match_nd_ns="priority=92.*${match_r1_metadata}.*icmp_type=135.*nd_target=10::122"
>
>  as hv2
>  OVS_WAIT_UNTIL([
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
>


More information about the dev mailing list