On Fri, Jun 7, 2019 at 5:15 AM Ankur Sharma <ankur.sha...@nutanix.com>
wrote:

> Hi Numan,
>
> Thanks for trying out the patch and providing feedback.
> I am planning to change this series to reflect only the E-W and would send
> out separate patches for N-S improvements.
>
> Following is the reasoning:
>
> ======================
> a. I agree that the network_type construct is adding to the confusion and
> may be we should rely on optional/external-id based key-value config.
> b. N-S patch has 3- changes (on a high level) which are distinct from each
> other, having them in a single patch is causing the confusion and is
> holding rest of the reviewed changes.
> c. Last but not the least, there were some gaps in the patch as well.
>
> Here is what I am planning to do:
>
> ==========================
> a. Keep this series for E-W only and remove all the network_type related
> changes from here (including showing type as bridged/vlan).
>


Hi Ankur.

I agree with the approach you are planning to take.



>
> b. For N-S Changes, this series has following changes. I will send them
> out in separate patches, especially the ones which are more of a bug fix.
>     i. Do not allow ARP resolution from physical network unless gateway
> chassis is configured è More of a bug fix, will be sent as a separate
> standalone patch.
>
>    ii. GARP advertisement during failover  in the absence of NAT
> configuration è More of a bug fix, will be sent as a separate standalone
> patch.
>
>   iii. Periodic GARP advertisement with/without NAT configuration è New
> feature, will be added along with SNAT changes.
>

This periodic GARP adv will be required irrespective of network_type of the
logical switches connected to a router. So I would request you to handle
this as well
when you submit the patch.


>   iv. Avoid redirection è New feature, will come as a separate patchset,
> we will make it as optional feature, i.e by default even non NATed traffic
> will go via gateway chassis, but config knob can override it.
>

Agree. This makes sense and easier.


>    v. No chassis mac replace on gateway chassis è More of a addendum to
> E-W, I am thinking about clubbing it some of N-S changes as this is where
> it will be relevant.
>
>
>
> c. Will send out separate patch for showing network type as overlay or
> bridged (based on localnet port’s presence), I believe it is good to have
> 😊.
>     i.e we will not have any new column in logical switch table, but the
> output of relevant ovn-nbctl show command will show type as “overlay” or
> “bridged”.
>
>
> Above will allow us to make progress on the changes we are in agreement
> on, while having thorough discussion on the remaining.
>
> Let me know, if you are fine with the plan, I should be able to send E-W
> only changes in a couple of days and should be able to individual bug fixes
> soon after as well.
>
>
> For rest of the comments, please find my replies inline.
>
> Appreciate your feedback.
>
> Regards,
> Ankur
>
>
>
>
> *From:* Numan Siddique <nusid...@redhat.com>
> *Sent:* Monday, June 3, 2019 3:06 AM
> *To:* Ankur Sharma <ankur.sha...@nutanix.com>
> *Cc:* ovs-dev@openvswitch.org
> *Subject:* Re: [ovs-dev] [PATCH v9 2/2] OVN: Enable N-S Traffic, Vlan
> backed DVR
>
>
>
>
>
> Hi Ankur,
>
>
>
> Please see some comments inline. Please note that I haven't got the chance
> to look into the code
>
> in detail. I am first trying to test out the patches. (I am in PTO. Expect
> some delay in my replies).
>
>
>
>
>
>
>
> On Thu, May 30, 2019 at 5:58 AM Ankur Sharma <ankur.sha...@nutanix.com>
> wrote:
>
> Background:
> [1] https://mail.openvswitch.org/pipermail/ovs-dev/2018-October/353066.html
> [mail.openvswitch.org]
> <https://urldefense.proofpoint.com/v2/url?u=https-3A__mail.openvswitch.org_pipermail_ovs-2Ddev_2018-2DOctober_353066.html&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=PIGJNMisAQ9iokicyVS4lKZ7fLKTOjQYSIV6R83EdO8&s=xQRPm8R90ygR4nx7uyRGOYHzW5NFiroiyZqi9JSYb-A&e=>
> [2] 
> https://docs.google.com/document/d/1uoQH478wM1OZ16HrxzbOUvk5LvFnfNEWbkPT6Zmm9OU/edit?usp=sharing
> [docs.google.com]
> <https://urldefense.proofpoint.com/v2/url?u=https-3A__docs.google.com_document_d_1uoQH478wM1OZ16HrxzbOUvk5LvFnfNEWbkPT6Zmm9OU_edit-3Fusp-3Dsharing&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=PIGJNMisAQ9iokicyVS4lKZ7fLKTOjQYSIV6R83EdO8&s=myrKaOI2LsuZQQOZhhhNw1zwDgat77e5CmPmpTFpllw&e=>
>
> This Series:
> Layer 2, Layer 3 E-W and Layer 3 N-S (NO NAT) changes for vlan
> backed distributed logical router.
>
> This patch:
> For North-South traffic, we need a chassis which will respond to
> ARP requests for router port coming from outside. For this purpose,
> we will reply upon gateway-chassis construct in OVN, on a logical
> router port, we will associate one or more chassis as gateway chassis.
>
> One of these chassis would be active at a point and will become
> entry point to traffic, bound for end points behind logical router
> coming from outside network (North to South).
>
> This patch make some enhancements to gateway chassis implementation
> to manage above used case.
>
> A.
> Do not replace router port mac with chassis mac on gateway
> chassis.
> This is done, because:
>     i. Chassisredirect port is NOT a distributed port, hence
>        we need not replace its mac address
>       (which same as router port mac).
>
>    ii. ARP cache will be consistent everywhere, i.e just like
>        endpoints on OVN chassis will see configured router port
>        mac as resolved mac for router port ip, outside endpoints
>        will see that as well.
>
>   iii. For implementing Network Address Translation. Although
>        not a part of this series. But, follow up series would
>        be having this feature and approach would rely upon
>        sending packets to redirect chassis using chassis redirect
>        router port mac as dest mac.
>
> B.
> Advertise router port GARP on gateway chassis.
> This is needed, especially if a failover happens and
> chassisredirect port moves to a new gateway chassis.
> Otherwise, there would be packet drops till outside
> router ARPs for router port ip again.
>
> Intention of this GARP is to update top of the rack (TOR)
> to direct router port mac to new hypervisor.
>
> Hence, we could have done the same using RARP as well, but
> because ovn-controller has implementation for GARP already,
> hence it did not look like worthy to add a RARP implementation
> just for this.
>
> C.
> For South to North traffic, we need not pass through gateway
> chassis, if there is no address transalation needed.
>
> For overlay networks, NATing is a must to talk to outside networks.
> However, for vlan backed networks, NATing is not a must, and hence
> in the absence of NATing configuration we need redirect the packet
> to gateway chassis.
>
> Signed-off-by: Ankur Sharma <ankur.sha...@nutanix.com>
> ---
>  ovn/controller/physical.c  |  24 +-
>  ovn/controller/pinctrl.c   | 205 +++++++++++--
>  ovn/controller/pinctrl.h   |   6 +
>  ovn/lib/ovn-util.c         |  31 ++
>  ovn/lib/ovn-util.h         |   6 +
>  ovn/northd/ovn-northd.c    |  43 ++-
>  ovn/ovn-architecture.7.xml |  87 +++++-
>  tests/ovn.at [ovn.at]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__ovn.at&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=PIGJNMisAQ9iokicyVS4lKZ7fLKTOjQYSIV6R83EdO8&s=pIYtQRJ9jgQGUXeKv6WUk41aKfohgLbkkL-XzaS6SsQ&e=>
>              | 732 ++++++++++++++++++++++++++++++++++++++++++++-
>  8 files changed, 1090 insertions(+), 44 deletions(-)
>
> diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c
> index af587a5..1ab5968 100644
> --- a/ovn/controller/physical.c
> +++ b/ovn/controller/physical.c
> @@ -21,6 +21,7 @@
>  #include "lflow.h"
>  #include "lport.h"
>  #include "chassis.h"
> +#include "pinctrl.h"
>  #include "lib/bundle.h"
>  #include "openvswitch/poll-loop.h"
>  #include "lib/uuid.h"
> @@ -238,9 +239,12 @@ get_zone_ids(const struct sbrec_port_binding *binding,
>  }
>
>  static void
> -put_replace_router_port_mac_flows(const struct
> +put_replace_router_port_mac_flows(struct ovsdb_idl_index
> +                                  *sbrec_port_binding_by_name,
> +                                  const struct
>                                    sbrec_port_binding *localnet_port,
>                                    const struct sbrec_chassis *chassis,
> +                                  const struct sset *active_tunnels,
>                                    const struct hmap *local_datapaths,
>                                    struct ofpbuf *ofpacts_p,
>                                    ofp_port_t ofport,
> @@ -281,8 +285,21 @@ put_replace_router_port_mac_flows(const struct
>          char *err_str = NULL;
>          struct match match;
>          struct ofpact_mac *replace_mac;
> +        char *cr_peer_name = xasprintf("cr-%s",
> rport_binding->logical_port);
>
> -        /* Table 65, priority 150.
> +
> +        if (pinctrl_is_chassis_resident(sbrec_port_binding_by_name,
> +                                        chassis, active_tunnels,
> +                                        cr_peer_name)) {
> +            /* If a router port's chassisredirect port is
> +             * resident on this chassis, then we need not do mac replace.
> */
> +            free(cr_peer_name);
> +            continue;
> +        }
> +
> +        free(cr_peer_name);
> +
> +       /* Table 65, priority 150.
>           * =======================
>           *
>           * Implements output to localnet port.
> @@ -797,7 +814,8 @@ consider_port_binding(struct ovsdb_idl_index
> *sbrec_port_binding_by_name,
>                          &match, ofpacts_p, &binding->header_.uuid);
>
>          if (!strcmp(binding->type, "localnet")) {
> -            put_replace_router_port_mac_flows(binding, chassis,
> +            put_replace_router_port_mac_flows(sbrec_port_binding_by_name,
> +                                              binding, chassis,
> active_tunnels,
>                                                local_datapaths, ofpacts_p,
>                                                ofport, flow_table);
>          }
> diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c
> index b7bb4c9..a145867 100644
> --- a/ovn/controller/pinctrl.c
> +++ b/ovn/controller/pinctrl.c
> @@ -226,6 +226,8 @@ static bool may_inject_pkts(void);
>  COVERAGE_DEFINE(pinctrl_drop_put_mac_binding);
>  COVERAGE_DEFINE(pinctrl_drop_buffered_packets_map);
>
> +#define GARP_DEF_REPEAT_INTERVAL_MS   (3 * 60 * 1000) /* 3 minutes */
> +
>  void
>  pinctrl_init(void)
>  {
> @@ -242,6 +244,25 @@ pinctrl_init(void)
>                                                  &pinctrl);
>  }
>
> +bool
> +pinctrl_is_chassis_resident(struct ovsdb_idl_index
> *sbrec_port_binding_by_name,
> +                            const struct sbrec_chassis *chassis,
> +                            const struct sset *active_tunnels,
> +                            const char *port_name)
> +{
> +    const struct sbrec_port_binding *pb
> +        = lport_lookup_by_name(sbrec_port_binding_by_name, port_name);
> +    if (!pb || !pb->chassis) {
> +        return false;
> +    }
> +    if (strcmp(pb->type, "chassisredirect")) {
> +        return pb->chassis == chassis;
> +    } else {
> +        return ha_chassis_group_is_active(pb->ha_chassis_group,
> +                                          active_tunnels, chassis);
> +    }
> +}
> +
>  static ovs_be32
>  queue_msg(struct rconn *swconn, struct ofpbuf *msg)
>  {
> @@ -2548,6 +2569,8 @@ struct garp_data {
>      int backoff;                 /* Backoff for the next announcement. */
>      uint32_t dp_key;             /* Datapath used to output this GARP. */
>      uint32_t port_key;           /* Port to inject the GARP into. */
> +    bool is_repeat;              /* Send GARPs continously */
> +    long long int repeat_interval; /* Interval between GARP bursts in ms
> */
>  };
>
>  /* Contains GARPs to be sent. Protected by pinctrl_mutex*/
> @@ -2568,7 +2591,8 @@ destroy_send_garps(void)
>  /* Runs with in the main ovn-controller thread context. */
>  static void
>  add_garp(const char *name, const struct eth_addr ea, ovs_be32 ip,
> -         uint32_t dp_key, uint32_t port_key)
> +         uint32_t dp_key, uint32_t port_key, bool is_repeat,
> +         long long int repeat_interval)
>  {
>      struct garp_data *garp = xmalloc(sizeof *garp);
>      garp->ea = ea;
> @@ -2577,6 +2601,8 @@ add_garp(const char *name, const struct eth_addr ea,
> ovs_be32 ip,
>      garp->backoff = 1;
>      garp->dp_key = dp_key;
>      garp->port_key = port_key;
> +    garp->is_repeat = is_repeat;
> +    garp->repeat_interval = repeat_interval;
>      shash_add(&send_garp_data, name, garp);
>
>      /* Notify pinctrl_handler so that it can wakeup and process
> @@ -2586,7 +2612,8 @@ add_garp(const char *name, const struct eth_addr ea,
> ovs_be32 ip,
>
>  /* Add or update a vif for which GARPs need to be announced. */
>  static void
> -send_garp_update(const struct sbrec_port_binding *binding_rec,
> +send_garp_update(struct ovsdb_idl_index *sbrec_port_binding_by_name,
> +                 const struct sbrec_port_binding *binding_rec,
>                   struct shash *nat_addresses)
>  {
>      volatile struct garp_data *garp = NULL;
> @@ -2611,7 +2638,7 @@ send_garp_update(const struct sbrec_port_binding
> *binding_rec,
>                      add_garp(name, laddrs->ea,
>                               laddrs->ipv4_addrs[i].addr,
>                               binding_rec->datapath->tunnel_key,
> -                             binding_rec->tunnel_key);
> +                             binding_rec->tunnel_key, false, 0);
>                  }
>                  free(name);
>              }
> @@ -2621,6 +2648,64 @@ send_garp_update(const struct sbrec_port_binding
> *binding_rec,
>          return;
>      }
>
> +    /* Update GARPs for local chassisredirect port, if the peer
> +     * layer 2 switch is of type vlan.
> +     */
> +    if (!strcmp(binding_rec->type, "chassisredirect")) {
> +        struct eth_addr mac;
> +        ovs_be32 ip, mask;
> +        uint32_t dp_key = 0;
> +        uint32_t port_key = 0;
> +        const struct sbrec_port_binding *peer_port = NULL;
> +        const struct sbrec_port_binding *distributed_port = NULL;
> +
> +        if (!ovn_sbrec_get_port_binding_ip_mac(binding_rec, &mac,
> +                                               &ip, &mask)) {
> +            /* Router Port binding without ip and mac configured. */
> +            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> +            VLOG_WARN_RL(&rl, "cannot send garp, router port binding: %s,
> "
> +                         "does not have proper ip,mac values: %s",
> +                         binding_rec->logical_port, *binding_rec->mac);
> +            return;
> +        }
> +
> +        const char *lrp_name = smap_get(&binding_rec->options,
> +                                        "distributed-port");
> +        ovs_assert(lrp_name);
> +
> +        distributed_port =
> lport_lookup_by_name(sbrec_port_binding_by_name,
> +                                                lrp_name);
> +        ovs_assert(distributed_port);
> +
> +        const char *peer_name = smap_get(&distributed_port->options,
> "peer");
> +        ovs_assert(peer_name);
> +
> +        peer_port = lport_lookup_by_name(sbrec_port_binding_by_name,
> +                                         peer_name);
> +        ovs_assert(peer_port);
> +
> +        const char *network_type =
> smap_get(&peer_port->datapath->external_ids,
> +                                            "network-type");
> +
> +        /* Advertise GARP only of logical switch is of type bridged. */
> +        if (!network_type || strcmp(network_type, "bridged")) {
> +            return;
> +        }
> +
> +        dp_key = peer_port->datapath->tunnel_key;
> +        port_key = peer_port->tunnel_key;
> +
> +        garp = shash_find_data(&send_garp_data,
> binding_rec->logical_port);
> +        if (garp) {
> +            garp->dp_key = dp_key;
> +            garp->port_key = port_key;
> +        } else {
> +            add_garp(binding_rec->logical_port, mac, ip,
> +                     dp_key, port_key, true, GARP_DEF_REPEAT_INTERVAL_MS);
> +        }
> +        return;
> +    }
> +
>      /* Update GARP for vif if it exists. */
>      garp = shash_find_data(&send_garp_data, binding_rec->logical_port);
>      if (garp) {
> @@ -2640,7 +2725,8 @@ send_garp_update(const struct sbrec_port_binding
> *binding_rec,
>
>          add_garp(binding_rec->logical_port,
>                   laddrs.ea, laddrs.ipv4_addrs[0].addr,
> -                 binding_rec->datapath->tunnel_key,
> binding_rec->tunnel_key);
> +                 binding_rec->datapath->tunnel_key,
> binding_rec->tunnel_key,
> +                 false, 0);
>
>          destroy_lport_addresses(&laddrs);
>          break;
> @@ -2702,7 +2788,12 @@ send_garp(struct rconn *swconn, struct garp_data
> *garp,
>          garp->backoff *= 2;
>          garp->announce_time = current_time + garp->backoff * 1000;
>      } else {
> -        garp->announce_time = LLONG_MAX;
> +        if (garp->is_repeat) {
> +            garp->backoff = 1;
> +            garp->announce_time = current_time + garp->repeat_interval;
> +        } else {
> +            garp->announce_time = LLONG_MAX;
> +        }
>      }
>      return garp->announce_time;
>  }
> @@ -2786,25 +2877,6 @@ get_localnet_vifs_l3gwports(
>      sbrec_port_binding_index_destroy_row(target);
>  }
>
> -static bool
> -pinctrl_is_chassis_resident(struct ovsdb_idl_index
> *sbrec_port_binding_by_name,
> -                            const struct sbrec_chassis *chassis,
> -                            const struct sset *active_tunnels,
> -                            const char *port_name)
> -{
> -    const struct sbrec_port_binding *pb
> -        = lport_lookup_by_name(sbrec_port_binding_by_name, port_name);
> -    if (!pb || !pb->chassis) {
> -        return false;
> -    }
> -    if (strcmp(pb->type, "chassisredirect")) {
> -        return pb->chassis == chassis;
> -    } else {
> -        return ha_chassis_group_is_active(pb->ha_chassis_group,
> -                                          active_tunnels, chassis);
> -    }
> -}
> -
>  /* Extracts the mac, IPv4 and IPv6 addresses, and logical port from
>   * 'addresses' which should be of the format 'MAC [IP1 IP2 ..]
>   * [is_chassis_resident("LPORT_NAME")]', where IPn should be a valid IPv4
> @@ -2946,6 +3018,67 @@ get_nat_addresses_and_keys(struct ovsdb_idl_index
> *sbrec_port_binding_by_name,
>  }
>
>  static void
> +get_local_cr_ports(struct ovsdb_idl_index *sbrec_port_binding_by_name,
> +                   struct sset *local_cr_ports,
> +                   struct sset *local_l3gw_ports,
> +                   const struct sbrec_chassis *chassis,
> +                   const struct sset *active_tunnels)
> +{
> +    const char *gw_port;
> +    SSET_FOR_EACH (gw_port, local_l3gw_ports) {
> +        const struct sbrec_port_binding *binding_rec;
> +
> +        binding_rec = lport_lookup_by_name(sbrec_port_binding_by_name,
> +                                           gw_port);
> +        if (!binding_rec) {
> +            continue;
> +        }
> +
> +        /* For the patch port we will add send garp for peer's ip and
> mac. */
> +        if (!strcmp(binding_rec->type, "patch")) {
> +            const struct sbrec_port_binding *cr_port = NULL;
> +
> +            bool is_cr_resident;
> +            struct eth_addr mac;
> +            ovs_be32 ip, mask;
> +
> +            const char *peer_name = smap_get(&binding_rec->options,
> "peer");
> +            ovs_assert(peer_name);
> +
> +            char *cr_peer_name = xasprintf("cr-%s", peer_name);
> +            cr_port = lport_lookup_by_name(sbrec_port_binding_by_name,
> +                                           cr_peer_name);
> +            free(cr_peer_name);
> +
> +            if (!cr_port) {
> +                continue;
> +            }
> +
> +            is_cr_resident = pinctrl_is_chassis_resident
> +                                (sbrec_port_binding_by_name,
> +                                 chassis,
> +                                 active_tunnels,
> +                                 cr_port->logical_port);
> +            if (!is_cr_resident) {
> +                continue;
> +            }
> +
> +            if (!ovn_sbrec_get_port_binding_ip_mac(cr_port, &mac, &ip,
> +                                                   &mask)) {
> +                /* Router Port binding without ip and mac configured. */
> +                static struct vlog_rate_limit rl =
> VLOG_RATE_LIMIT_INIT(1, 1);
> +                VLOG_WARN_RL(&rl, "cannot send garp, router port binding:
> %s, "
> +                             "does not have proper ip,mac values: %s",
> +                              cr_port->logical_port, *cr_port->mac);
> +                return;
> +            }
> +
> +            sset_add(local_cr_ports, cr_port->logical_port);
> +        }
> +    }
> +}
> +
> +static void
>  send_garp_wait(long long int send_garp_time)
>  {
>      /* Set the poll timer for next garp only if there is garp data to
> @@ -2990,6 +3123,8 @@ send_garp_prepare(struct ovsdb_idl_index
> *sbrec_port_binding_by_datapath,
>  {
>      struct sset localnet_vifs = SSET_INITIALIZER(&localnet_vifs);
>      struct sset local_l3gw_ports = SSET_INITIALIZER(&local_l3gw_ports);
> +    struct sset local_cr_ports = SSET_INITIALIZER(&local_cr_ports);
> +
>      struct sset nat_ip_keys = SSET_INITIALIZER(&nat_ip_keys);
>      struct shash nat_addresses;
>
> @@ -3004,11 +3139,17 @@ send_garp_prepare(struct ovsdb_idl_index
> *sbrec_port_binding_by_datapath,
>                                 &nat_ip_keys, &local_l3gw_ports,
>                                 chassis, active_tunnels,
>                                 &nat_addresses);
> +
> +    get_local_cr_ports(sbrec_port_binding_by_name,
> +                       &local_cr_ports, &local_l3gw_ports,
> +                       chassis, active_tunnels);
> +
>      /* For deleted ports and deleted nat ips, remove from send_garp_data.
> */
>      struct shash_node *iter, *next;
>      SHASH_FOR_EACH_SAFE (iter, next, &send_garp_data) {
>          if (!sset_contains(&localnet_vifs, iter->name) &&
> -            !sset_contains(&nat_ip_keys, iter->name)) {
> +            !sset_contains(&nat_ip_keys, iter->name) &&
> +            !sset_contains(&local_cr_ports, iter->name)) {
>              send_garp_delete(iter->name);
>          }
>      }
> @@ -3019,7 +3160,7 @@ send_garp_prepare(struct ovsdb_idl_index
> *sbrec_port_binding_by_datapath,
>          const struct sbrec_port_binding *pb = lport_lookup_by_name(
>              sbrec_port_binding_by_name, iface_id);
>          if (pb) {
> -            send_garp_update(pb, &nat_addresses);
> +            send_garp_update(sbrec_port_binding_by_name, pb,
> &nat_addresses);
>          }
>      }
>
> @@ -3029,7 +3170,17 @@ send_garp_prepare(struct ovsdb_idl_index
> *sbrec_port_binding_by_datapath,
>          const struct sbrec_port_binding *pb
>              = lport_lookup_by_name(sbrec_port_binding_by_name, gw_port);
>          if (pb) {
> -            send_garp_update(pb, &nat_addresses);
> +            send_garp_update(sbrec_port_binding_by_name, pb,
> &nat_addresses);
> +        }
> +    }
> +
> +    /* Update send_garp_data for chassisredirect router ports. */
> +    const char *cr_port;
> +    SSET_FOR_EACH (cr_port, &local_cr_ports) {
> +        const struct sbrec_port_binding *pb
> +            = lport_lookup_by_name(sbrec_port_binding_by_name, cr_port);
> +        if (pb) {
> +            send_garp_update(sbrec_port_binding_by_name, pb,
> &nat_addresses);
>          }
>      }
>
> diff --git a/ovn/controller/pinctrl.h b/ovn/controller/pinctrl.h
> index f61d705..92f704e 100644
> --- a/ovn/controller/pinctrl.h
> +++ b/ovn/controller/pinctrl.h
> @@ -44,4 +44,10 @@ void pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
>  void pinctrl_wait(struct ovsdb_idl_txn *ovnsb_idl_txn);
>  void pinctrl_destroy(void);
>
> +bool
> +pinctrl_is_chassis_resident(struct ovsdb_idl_index
> *sbrec_port_binding_by_name,
> +                            const struct sbrec_chassis *chassis,
> +                            const struct sset *active_tunnels,
> +                            const char *port_name);
> +
>  #endif /* ovn/pinctrl.h */
> diff --git a/ovn/lib/ovn-util.c b/ovn/lib/ovn-util.c
> index 0f07d80..3d0ad8e 100644
> --- a/ovn/lib/ovn-util.c
> +++ b/ovn/lib/ovn-util.c
> @@ -16,6 +16,7 @@
>  #include "ovn-util.h"
>  #include "dirs.h"
>  #include "openvswitch/vlog.h"
> +#include "openvswitch/ofp-parse.h"
>  #include "ovn/lib/ovn-nb-idl.h"
>  #include "ovn/lib/ovn-sb-idl.h"
>
> @@ -371,3 +372,33 @@ ovn_logical_flow_hash(const struct uuid
> *logical_datapath,
>      hash = hash_string(match, hash);
>      return hash_string(actions, hash);
>  }
> +
> +/*  Extracts the mac, ip and mask for a sbrec_port_binding.
> + *
> + *  Expects following format:
> + *  "MAC_ADDRESS IP/MASK"
> + *
> + *  Return true if MAC, IP and MASK are found, false otherwise.
> + */
> +bool
> +ovn_sbrec_get_port_binding_ip_mac(const struct sbrec_port_binding
> *binding,
> +                                  struct eth_addr *mac,
> +                                  ovs_be32 *ip, ovs_be32 *mask)
> +{
> +    char *err_str = NULL;
> +
> +    err_str = str_to_mac(binding->mac[0], mac);
> +    if (err_str) {
> +        free(err_str);
> +        return false;
> +    }
> +
> +    err_str = ip_parse_masked(binding->mac[0] + ETH_ADDR_STRLEN + 1,
> +                              ip, mask);
> +    if (err_str) {
> +        free(err_str);
> +        return false;
> +    }
> +
> +    return true;
> +}
> diff --git a/ovn/lib/ovn-util.h b/ovn/lib/ovn-util.h
> index 6d5e1df..c01595a 100644
> --- a/ovn/lib/ovn-util.h
> +++ b/ovn/lib/ovn-util.h
> @@ -19,6 +19,7 @@
>  #include "lib/packets.h"
>
>  struct nbrec_logical_router_port;
> +struct sbrec_port_binding;
>  struct sbrec_logical_flow;
>  struct uuid;
>
> @@ -81,4 +82,9 @@ uint32_t ovn_logical_flow_hash(const struct uuid
> *logical_datapath,
>                                 uint16_t priority,
>                                 const char *match, const char *actions);
>
> +bool
> +ovn_sbrec_get_port_binding_ip_mac(const struct sbrec_port_binding
> *binding,
> +                                  struct eth_addr *mac, ovs_be32 *ip,
> +                                  ovs_be32 *mask);
> +
>  #endif
> diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
> index 74d3692..6835910 100644
> --- a/ovn/northd/ovn-northd.c
> +++ b/ovn/northd/ovn-northd.c
> @@ -5914,6 +5914,20 @@ build_lrouter_flows(struct hmap *datapaths, struct
> hmap *ports,
>                      ds_put_format(&match, " && is_chassis_resident(%s)",
>                                    op->od->l3redirect_port->json_key);
>                  }
> +            } else if (op->peer &&
> +                       op->peer->od->network_type == DP_NETWORK_BRIDGED) {
> +                /* For a router port connected to bridged logical switch,
> +                 * we will always have the is_chassis_resident check.
> +                 * This is because there could be vm/server on vlan
> network,
> +                 * but not on OVN chassis and could end up arping for
> router
> +                 * port ip.
> +                 *
> +                 * This check works on the assumption that for OVN
> chassis,
> +                 * VMs logical switch ARP responder will respond to ARP
> +                 * requests for router port IP.
> +                 */
> +                ds_put_format(&match, " &&
> is_chassis_resident(\"cr-%s\")",
> +                              op->key);
>              }
>
>              ds_clear(&actions);
> @@ -7365,18 +7379,23 @@ build_lrouter_flows(struct hmap *datapaths, struct
> hmap *ports,
>              ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 300,
>                            REGBIT_DISTRIBUTED_NAT" == 1", "next;");
>
> -            /* For traffic with outport == l3dgw_port, if the
> -             * packet did not match any higher priority redirect
> -             * rule, then the traffic is redirected to the central
> -             * instance of the l3dgw_port. */
> -            ds_clear(&match);
> -            ds_put_format(&match, "outport == %s",
> -                          od->l3dgw_port->json_key);
> -            ds_clear(&actions);
> -            ds_put_format(&actions, "outport = %s; next;",
> -                          od->l3redirect_port->json_key);
> -            ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 50,
> -                          ds_cstr(&match), ds_cstr(&actions));
> +            /* For VLAN backed networks, default match will not redirect
> to
> +             * chassis redirect port. */
> +            if (od->l3dgw_port->peer &&
> +                od->l3dgw_port->peer->od->network_type ==
> DP_NETWORK_OVERLAY) {
> +                /* For traffic with outport == l3dgw_port, if the
> +                 * packet did not match any higher priority redirect
> +                 * rule, then the traffic is redirected to the central
> +                 * instance of the l3dgw_port. */
> +                ds_clear(&match);
> +                ds_put_format(&match, "outport == %s",
> +                              od->l3dgw_port->json_key);
> +                ds_clear(&actions);
> +                ds_put_format(&actions, "outport = %s; next;",
> +                              od->l3redirect_port->json_key);
> +                ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 50,
> +                              ds_cstr(&match), ds_cstr(&actions));
> +            }
>
>
>
> Looks like this code is having some side effects.
>
>
>
>
>
> Point 1.
>
> ======
>
> For my public switch if I don't set the network_type as "bridged",
>
> then I see the below logical flows and think this is as expected. And I
> think
>
> that's why in my v7 tests the packets were tunneled to the gw chassis (as
>
> you mentioned in the reply).
>
>
>
> ****
>
> table=12(lr_in_gw_redirect  ), priority=300  , match=(reg9[2] == 1),
> action=(next;)
>   table=12(lr_in_gw_redirect  ), priority=200  , match=(reg9[0] == 1),
> action=(outport = "cr-lr0-public"; next;)
>   table=12(lr_in_gw_redirect  ), priority=150  , match=(outport ==
> "lr0-public" && eth.dst == 00:00:00:00:00:00), action=(outport =
> "cr-lr0-public"; next;)
>   table=12(lr_in_gw_redirect  ), priority=50   , match=(outport ==
> "lr0-public"), action=(outport = "cr-lr0-public"; next;)
>   table=12(lr_in_gw_redirect  ), priority=0    , match=(1), action=(next;)
>
> ****
>
>
>
> If I set the type as "bridged", I see the below flows
>
>
>
> ****
>
>  table=12(lr_in_gw_redirect  ), priority=300  , match=(reg9[2] == 1),
> action=(next;)
>   table=12(lr_in_gw_redirect  ), priority=200  , match=(reg9[0] == 1),
> action=(outport = "cr-lr0-public"; next;)
>   table=12(lr_in_gw_redirect  ), priority=150  , match=(outport ==
> "lr0-sw1" && reg0 == 20.0.0.3 && eth.dst == 00:00:00:00:00:00),
> action=(eth.dst = 40:54:00:00:00:03; next;)
>   table=12(lr_in_gw_redirect  ), priority=0    , match=(1), action=(next;)
>
> ****
>
>
>
> I don't understand the 3rd flow with the match -- "outport == "lr0-sw1"...
>
>
>
> Looks like the "match" and "action" variables have some old data. Please
> look into the code again.
> [ANKUR]:
> Yup, missed out on clearing match and actions, thanks for calling it out.
>
>
>
> After the "if" condition you added in this patch at line 7384, the below
> code is still there and it doesn't make sense
>
>
>
> ******
>
>              /* For VLAN backed networks, default match will not redirect
> to
>              * chassis redirect port. */
>             if (od->l3dgw_port->peer &&
>                 od->l3dgw_port->peer->od->network_type ==
> DP_NETWORK_OVERLAY) {
>                 /* For traffic with outport == l3dgw_port, if the
>                  * packet did not match any higher priority redirect
>                  * rule, then the traffic is redirected to the central
>                  * instance of the l3dgw_port. */
>                 ds_clear(&match);
>                 ds_put_format(&match, "outport == %s",
>                               od->l3dgw_port->json_key);
>                 ds_clear(&actions);
>                 ds_put_format(&actions, "outport = %s; next;",
>                               od->l3redirect_port->json_key);
>                 ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 50,
>                               ds_cstr(&match), ds_cstr(&actions));
>             }
>
>             /* If the Ethernet destination has not been resolved,
>              * redirect to the central instance of the l3dgw_port.
>              * Such traffic will be replaced by an ARP request or ND
>              * Neighbor Solicitation in the ARP request ingress
>              * table, before being redirected to the central instance.
>              */
>             ds_put_format(&match, " && eth.dst == 00:00:00:00:00:00");
>   ====> THIS ONE
>             ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 150,
>  ====> AND THIS ONE
>                           ds_cstr(&match), ds_cstr(&actions));
>         }
>
> [ANKUR]:
> Intention here was to just remove the flow which was sending out anything
> directed to router port to chassis redirect router port.
>
>
>
> ********
>
>
>
> Point 2
>
> =====
>
>
>
> This patch breaks the S/N traffic if we have a logical switch (sw0) of
> type overlay connected
>
> to a router and the router also a gw port connected to a logical switch
> (public) of type bridged (i.e provider network).
>
> This public switch has a localnet port.
>
>
>
> Some thing like this - http://paste.openstack.org/show/752427/
> [paste.openstack.org]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__paste.openstack.org_show_752427_&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=PIGJNMisAQ9iokicyVS4lKZ7fLKTOjQYSIV6R83EdO8&s=6rUfRX1OJVsHGsYSDvkxwm1jNck-tOBUBuVlw4FyvHQ&e=>
>
>
>
> It works fine if I change the type of the logical switch - public to
> overlay. But this doesn't make sense, since
>
> the logical switch - public is a provider (or bridged) network and CMS can
> set the type as bridged.
>
>
>
> I still think it's better not to have "network_type" column in
> logical_switch. We can always consider a logical
>
> switch having a localnet port of type "bridged" and with out a localnet
> port of type "overlay".
>
> [ANKUR]:
> Agreed, nomenclature and usage of type field is confusing. It will be
> difficult to convey / expect that CMS
>
> will NOT end up using even it was not supped to. I mentioned it the email
> reply, that I will be removing it
>
> from current patch series and we will have separate config knobs for the
> use cases this field was added for.
>
>
>
> This patch series sets the network_type=bridged in the external_ids of the
> datapath_binding row in SB DB.
>
>
>
> Please see my comments in v4 of the patch 1 where I suggested something
> like below
>
>
>
> ****
>
> enum ovn_datapath_nw_type {
>
>     DP_NETWORK_OVERLAY,
>
>     DP_NETWORK_PROVIDER
>
> };
>
>
>
> static void
>
> ovn_datapath_update_nw_type(struct ovn_datapath *od)
>
> {
>
>     if (!od->nbs) {
>
>         return;
>
>     }
>
>
>
>     if (!od->localnet_port) {
>
>         od->network_type = DP_NETWORK_OVERLAY;
>
>     } else {
>
>         od->network_type = DP_NETWORK_PROVIDER;
>
>     }
>
> }
>
> ******
>
>
>
> I think you can still set the external_ids of the datapath_binding row
> with "network_type=bridged"
>
> if od->network_type is BRIDGED so that ovn-controller can distinguish if
> its bridged or overlay datapath.
>
>
>
>
>
> I am mainly thinking from upgrades perspective for the existing
> deployments once this patch is series is applied.
>
> Until CMS changes the network_type to "bridged" for all the logical
> switches with localnet ports in the
>
> existing deployments, "ovn-nbctl show" will show these logical switches as
> "overlay" which is weird.
>
> And later we may encounter other issues when enhancing OVN with new
> features.
>
> [ANKUR]:
> Yes, the value is quite easy to get confused with, I will be removing it
> in v10.
>
>
>
> I think instead of adding the code to skip the redirection to the gateway
> chassis in ovn-northd if its a bridged network,
>
> it's better to handle it in table 32 and since the mac replacement is
> handled in table 65 it probably makes more sense this way.
> [ANKUR]:
> IMO, Table 32 should only decide if redirection has to be done on overlay
> or vlan. While, logical flow should decide if redirection
>
> is needed or not.
>
>
>
> Thanks
>
> Numan
>
>
>
>
>
>              /* If the Ethernet destination has not been resolved,
>               * redirect to the central instance of the l3dgw_port.
> diff --git a/ovn/ovn-architecture.7.xml b/ovn/ovn-architecture.7.xml
> index 6275db1..6df711e 100644
> --- a/ovn/ovn-architecture.7.xml
> +++ b/ovn/ovn-architecture.7.xml
> @@ -1441,7 +1441,7 @@
>      </li>
>    </ol>
>
> -  <h3>External traffic</h3>
> +  <h3>External traffic (NAT)</h3>
>
>    <p>
>      The following happens when a VM sends an external traffic (which
> requires
> @@ -1607,6 +1607,91 @@
>      </li>
>    </ol>
>
> +  <h3>External traffic (NO NAT)</h3>
> +  <p>
> +    The following happens when a VM sends an external traffic (i.e to non
> +    logical router connected network), but there is not need for NATing.
> +  </p>
> +
> +  <p>
> +    Since, there is no NATing required, hence we need not redirect the
> packet
> +    to a gateway chassis. As a result, this packet flow is same as
> East-West.
> +    In order to ensure that OVN will not redirect the packet over a tunnel
> +    to gateway-chassis, "network_type" of destination localnet logical
> switch,
> +    should be set as "bridged". A "bridged" logical switch ensures that
> there
> +    is no tunnel encapsulation done while forwarding the packet on it.
> +    Please refer to <code>ovn-nb</code>(5) for more details.
> +  </p>
> +
> +  <ol>
> +    <li>
> +      It first enters the ingress pipeline, and then egress pipeline of
> the
> +      source localnet logical switch datapath. It then enters the ingress
> +      pipeline of the logical router datapath via the logical router port
> in
> +      the source chassis.
> +    </li>
> +
> +    <li>
> +      Routing decision is taken. Since, destination network is NOT
> directly
> +      connected to logial router, hence a static route is expected, which
> will
> +      provide next hop ip.
> +    </li>
> +
> +    <li>
> +      From the router datapath, packet enters the ingress pipeline and
> then
> +      egress pipeline of the destination localnet logical switch datapath
> +      (it is of type "bridged" and this is where the next hop is present)
> +      and goes out of the integration bridge to the provider bridge (
> +      belonging to the destination logical switch) via the localnet port.
> +      Same as East-West, source mac will replaced with chassis mac.
> +    </li>
> +  </ol>
> +
> +  <p>
> +    The following happens for the reverse external traffic.
> +  </p>
> +
> +  <ol>
> +    <li>
> +      The gateway chassis receives the packet from the localnet port of
> +      the logical switch (bridged type) which provides external
> connectivity.
> +      The packet then enters the ingress pipeline and then egress
> pipeline of
> +      the localnet logical switch (which provides external connectivity).
> +      The packet then enters the ingress pipeline of the logical router
> +      datapath.
> +    </li>
> +
> +    <li>
> +      Routing decision is taken and logical switch of destination VM is
> +      identified.
> +    </li>
> +
> +    <li>
> +      The packet then enters the ingress pipeline and then egress
> +      pipeline of VM's localnet logical switch. Since the source VM
> +      doesn't reside in the gateway chassis, the packet is sent out via
> the
> +      localnet port of the VM's logical switch. Source mac of this packet
> +      will be replaced with chassis unique mac.
> +    </li>
> +
> +    <li>
> +      VM's chassis receives the packet via the localnet port and
> +      sends it to the integration bridge. The packet enters the
> +      ingress pipeline and then egress pipeline of the localnet
> +      logical switch and finally gets delivered to the VM port.
> +    </li>
> +  </ol>
> +
> +  <p>
> +    One thing to note here is that, while VM to External traffic did not
> +    require redirection to gateway chassis, the reverse traffic is through
> +    gateway chassis only. This is because, for external router, OVN
> logical
> +    router port IP will be the next hop to reach the endpoints behind it.
> +    As a result, we need a centralized chassis, which will respond to ARP
> +    requests coming from external network. This centralized chassis, is
> the
> +    gateway chassis which is attached to corresponding router port.
> +  </p>
> +
>    <h2>Life Cycle of a VTEP gateway</h2>
>
>    <p>
> diff --git a/tests/ovn.at [ovn.at]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__ovn.at&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=PIGJNMisAQ9iokicyVS4lKZ7fLKTOjQYSIV6R83EdO8&s=pIYtQRJ9jgQGUXeKv6WUk41aKfohgLbkkL-XzaS6SsQ&e=>
> b/tests/ovn.at [ovn.at]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__ovn.at&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=PIGJNMisAQ9iokicyVS4lKZ7fLKTOjQYSIV6R83EdO8&s=pIYtQRJ9jgQGUXeKv6WUk41aKfohgLbkkL-XzaS6SsQ&e=>
> index e5108a7..8a03393 100644
> --- a/tests/ovn.at [ovn.at]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__ovn.at&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=PIGJNMisAQ9iokicyVS4lKZ7fLKTOjQYSIV6R83EdO8&s=pIYtQRJ9jgQGUXeKv6WUk41aKfohgLbkkL-XzaS6SsQ&e=>
> +++ b/tests/ovn.at [ovn.at]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__ovn.at&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=PIGJNMisAQ9iokicyVS4lKZ7fLKTOjQYSIV6R83EdO8&s=pIYtQRJ9jgQGUXeKv6WUk41aKfohgLbkkL-XzaS6SsQ&e=>
> @@ -29,6 +29,12 @@ m4_define([OVN_CHECK_PACKETS],
>    [ovn_check_packets__ "$1" "$2"
>     AT_CHECK([sort $rcv_text], [0], [expout])])
>
> +m4_define([OVN_CHECK_PACKETS_REMOVE_BROADCAST],
> +  [ovn_check_packets__ "$1" "$2"
> +   echo "received_text=$rcv_text"
> +   sed -i '/ffffffffffff/d' $rcv_text
> +   AT_CHECK([sort $rcv_text], [0], [expout])])
> +
>  AT_BANNER([OVN components])
>
>  AT_SETUP([ovn -- lexer])
> @@ -14018,7 +14024,7 @@ ovn-hv4-0
>  OVN_CLEANUP([hv1], [hv2], [hv3])
>  AT_CLEANUP
>
> -AT_SETUP([ovn -- 2 HVs, 2 lports/HV, localnet ports, DVR chassis mac])
> +AT_SETUP([ovn -- 2 HVs, 2 lports/HV, localnet ports, DVR E-W chassis mac])
>  ovn_start
>
>
> @@ -14028,6 +14034,8 @@ ovn_start
>  # of VIF port name indicates the hypervisor it is bound to, e.g.
>  # lp23 means VIF 3 on hv2.
>  #
> +# Both the switches are connected to a logical router "router".
> +#
>  # Each switch's VLAN tag and their logical switch ports are:
>  #   - ls1:
>  #       - tagged with VLAN 101
> @@ -14185,6 +14193,7 @@ test_ip() {
>  echo "------ OVN dump ------"
>  ovn-nbctl show
>  ovn-sbctl show
> +ovn-sbctl list port_binding
>
>  echo "------ hv1 dump ------"
>  as hv1 ovs-vsctl show
> @@ -14211,6 +14220,727 @@ as hv2 ovs-appctl fdb/show br-phys
>
>  OVN_CHECK_PACKETS([hv2/vif22-tx.pcap], [vif22.expected])
>
> +
> +# Associate a chassis as gateway chassis and validate garp.
> +
> +OVN_CLEANUP([hv1],[hv2])
> +
> +AT_CLEANUP
> +
> +
> +AT_SETUP([ovn -- 2 HVs, 2 lports/HV, localnet ports, DVR N-S GARP])
> +ovn_start
> +
> +
> +# In this test cases we create 2 switches, all connected to same
> +# physical network (through br-phys on each HV). Each switch has
> +# 1 VIF. Each HV has 1 VIF port. The first digit
> +# of VIF port name indicates the hypervisor it is bound to, e.g.
> +# lp23 means VIF 3 on hv2.
> +#
> +# Both the switches are connected to a logical router "router".
> +#
> +# Additionally, we create a logical switch (ls-underlay) for N-S traffic.
> +#
> +# Each switch's VLAN tag and their logical switch ports are:
> +#   - ls1:
> +#       - tagged with VLAN 101
> +#       - ports: lp11
> +#   - ls2:
> +#       - tagged with VLAN 201
> +#       - ports: lp22
> +#   - ls-underlay:
> +#       - tagged with VLAN 1000
> +#
> +# Note: a localnet port is created for each switch to connect to
> +# physical network.
> +# lsp_to_ls LSP
> +#
> +# Prints the name of the logical switch that contains LSP.
> +
> +net_add n1
> +for i in 1 2; do
> +    sim_add hv$i
> +    as hv$i
> +    ovs-vsctl add-br br-phys
> +    ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
> +    ovs-vsctl set open .
> external-ids:ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:$i$i"
> +    ovs-vsctl set open . external-ids:system-id="HV$i"
> +    ovn_attach n1 br-phys 192.168.0.$i
> +    ovs-vsctl set-controller br-int ptcp:
> +    AT_CHECK([ovs-vsctl add-port br-phys snoopvif -- set Interface
> snoopvif options:tx_pcap=hv$i/snoopvif-tx.pcap
> options:rxq_pcap=hv$i/snoopvif-rx.pcap])
> +done
> +
> +ovn-nbctl ls-add ls-underlay bridged
> +ovn-nbctl lsp-add ls-underlay ln3 "" 1000
> +ovn-nbctl lsp-set-addresses ln3 unknown
> +ovn-nbctl lsp-set-type ln3 localnet
> +ovn-nbctl lsp-set-options ln3 network_name=phys
> +
> +ovn-nbctl lr-add router
> +ovn-nbctl lrp-add router router-to-underlay 00:00:01:01:02:07 172.31.0.1/24
> [172.31.0.1]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__172.31.0.1_24&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=PIGJNMisAQ9iokicyVS4lKZ7fLKTOjQYSIV6R83EdO8&s=rqMxle8BgWOlhM3GlQ2s4e96C9zXLut8Ap0enbFWkfk&e=>
> +
> +ovn-nbctl lsp-add ls-underlay underlay-to-router -- set
> Logical_Switch_Port \
> +                              underlay-to-router type=router \
> +                              options:router-port=router-to-underlay \
> +                              -- lsp-set-addresses underlay-to-router
> router
> +
> +ovn-nbctl --wait=sb sync
> +
> +# Associate hv2 as gateway chassis
> +ovn-nbctl lrp-set-gateway-chassis router-to-underlay hv2
> +
> +ovn-nbctl show
> +ovn-sbctl show
> +
> +# Dump a bunch of info helpful for debugging if there's a failure.
> +
> +echo "------ OVN dump ------"
> +ovn-nbctl show
> +ovn-sbctl show
> +
> +echo "------ hv1 dump ------"
> +as hv1 ovs-vsctl show
> +as hv1 ovs-vsctl list Open_Vswitch
> +
> +echo "------ hv2 dump ------"
> +as hv2 ovs-vsctl show
> +as hv2 ovs-vsctl list Open_Vswitch
> +
> +sleep 1
> +
> +echo "----------- Post Traffic hv1 dump -----------"
> +as hv1 ovs-ofctl -O OpenFlow13 dump-flows br-int
> +as hv1 ovs-appctl fdb/show br-phys
> +
> +echo "----------- Post Traffic hv2 dump -----------"
> +as hv2 ovs-ofctl -O OpenFlow13 dump-flows br-int
> +as hv2 ovs-appctl fdb/show br-phys
> +
> +AT_CHECK([as hv2 ovs-appctl fdb/show br-phys | grep 00:00:01:01:02:07 |
> grep 1000 | wc -l], [0], [[1
> +]])
> +
> +echo
> "ffffffffffff000001010207810003e808060001080006040001000001010207ac1f0001000000000000ac1f0001"
> > expected
> +OVN_CHECK_PACKETS([hv2/snoopvif-tx.pcap], [expected])
> +
>  OVN_CLEANUP([hv1],[hv2])
>
>  AT_CLEANUP
> +
> +
> +AT_SETUP([ovn -- 2 HVs, 2 lports/HV, localnet ports, DVR N-S Ping])
> +ovn_start
> +
> +# In this test cases we create 3 switches, all connected to same
> +# physical network (through br-phys on each HV). LS1 and LS2 have
> +# 1 VIF each. Each HV has 1 VIF port. The first digit
> +# of VIF port name indicates the hypervisor it is bound to, e.g.
> +# lp23 means VIF 3 on hv2.
> +#
> +# All the switches are connected to a logical router "router".
> +#
> +# Each switch's VLAN tag and their logical switch ports are:
> +#   - ls1:
> +#       - tagged with VLAN 101
> +#       - ports: lp11
> +#   - ls2:
> +#       - tagged with VLAN 201
> +#       - ports: lp22
> +#   - ls-underlay:
> +#       - tagged with VLAN 1000
> +# Note: a localnet port is created for each switch to connect to
> +# physical network.
> +
> +for i in 1 2; do
> +    ls_name=ls$i
> +    ovn-nbctl ls-add $ls_name bridged
> +    ln_port_name=ln$i
> +    if test $i -eq 1; then
> +        ovn-nbctl lsp-add $ls_name $ln_port_name "" 101
> +    elif test $i -eq 2; then
> +        ovn-nbctl lsp-add $ls_name $ln_port_name "" 201
> +    fi
> +    ovn-nbctl lsp-set-addresses $ln_port_name unknown
> +    ovn-nbctl lsp-set-type $ln_port_name localnet
> +    ovn-nbctl lsp-set-options $ln_port_name network_name=phys
> +done
> +
> +# lsp_to_ls LSP
> +#
> +# Prints the name of the logical switch that contains LSP.
> +lsp_to_ls () {
> +    case $1 in dnl (
> +        lp?[[11]]) echo ls1 ;; dnl (
> +        lp?[[12]]) echo ls2 ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +vif_to_hv () {
> +    case $1 in dnl (
> +        vif[[1]]?) echo hv1 ;; dnl (
> +        vif[[2]]?) echo hv2 ;; dnl (
> +        vif?[[north]]?) echo hv4 ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +ip_to_hex() {
> +       printf "%02x%02x%02x%02x" "$@"
> +}
> +
> +net_add n1
> +for i in 1 2; do
> +    sim_add hv$i
> +    as hv$i
> +    ovs-vsctl add-br br-phys
> +    ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
> +    ovs-vsctl set open .
> external-ids:ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:$i$i"
> +    ovn_attach n1 br-phys 192.168.0.$i
> +
> +    ovs-vsctl add-port br-int vif$i$i -- \
> +        set Interface vif$i$i external-ids:iface-id=lp$i$i \
> +                              options:tx_pcap=hv$i/vif$i$i-tx.pcap \
> +                              options:rxq_pcap=hv$i/vif$i$i-rx.pcap \
> +                              ofport-request=$i$i
> +
> +    lsp_name=lp$i$i
> +    ls_name=$(lsp_to_ls $lsp_name)
> +
> +    ovn-nbctl lsp-add $ls_name $lsp_name
> +    ovn-nbctl lsp-set-addresses $lsp_name "f0:00:00:00:00:$i$i
> 192.168.$i.$i"
> +    ovn-nbctl lsp-set-port-security $lsp_name f0:00:00:00:00:$i$i
> +
> +    OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up $lsp_name` = xup])
> +
> +done
> +
> +ovn-nbctl ls-add ls-underlay bridged
> +ovn-nbctl lsp-add ls-underlay ln3 "" 1000
> +ovn-nbctl lsp-set-addresses ln3 unknown
> +ovn-nbctl lsp-set-type ln3 localnet
> +ovn-nbctl lsp-set-options ln3 network_name=phys
> +
> +ovn-nbctl ls-add ls-north bridged
> +ovn-nbctl lsp-add ls-north ln4 "" 1000
> +ovn-nbctl lsp-set-addresses ln4 unknown
> +ovn-nbctl lsp-set-type ln4 localnet
> +ovn-nbctl lsp-set-options ln4 network_name=phys
> +
> +# Add a VM on ls-north
> +ovn-nbctl lsp-add ls-north lp-north
> +ovn-nbctl lsp-set-addresses lp-north "f0:f0:00:00:00:11 172.31.0.10"
> +ovn-nbctl lsp-set-port-security lp-north f0:f0:00:00:00:11
> +
> +# Add 3rd hypervisor
> +sim_add hv3
> +as hv3 ovs-vsctl add-br br-phys
> +as hv3 ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
> +as hv3 ovs-vsctl set open .
> external-ids:ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:33"
> +as hv3 ovn_attach n1 br-phys 192.168.0.3
> +
> +# Add 4th hypervisor
> +sim_add hv4
> +as hv4 ovs-vsctl add-br br-phys
> +as hv4 ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
> +as hv4 ovs-vsctl set open .
> external-ids:ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:44"
> +as hv4 ovn_attach n1 br-phys 192.168.0.4
> +
> +as hv4 ovs-vsctl add-port br-int vif-north -- \
> +        set Interface vif-north external-ids:iface-id=lp-north \
> +                              options:tx_pcap=hv4/vif-north-tx.pcap \
> +                              options:rxq_pcap=hv4/vif-north-rx.pcap \
> +                              ofport-request=44
> +
> +ovn-nbctl lr-add router
> +ovn-nbctl lrp-add router router-to-ls1 00:00:01:01:02:03 192.168.1.3/24
> +ovn-nbctl [192.168.1.3]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__192.168.1.3_24-2Bovn-2Dnbctl&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=PIGJNMisAQ9iokicyVS4lKZ7fLKTOjQYSIV6R83EdO8&s=r3laW3QCkYmIZydSf8n5bHm0ObKIuSd3VACsekBmSbg&e=>
> lrp-add router router-to-ls2 00:00:01:01:02:05 192.168.2.3/24
> +ovn-nbctl [192.168.2.3]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__192.168.2.3_24-2Bovn-2Dnbctl&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=PIGJNMisAQ9iokicyVS4lKZ7fLKTOjQYSIV6R83EdO8&s=suQy9nYmhP89HVjKfN--Kvziv8XSkkzS9bXCDrfE1c4&e=>
> lrp-add router router-to-underlay 00:00:01:01:02:07 172.31.0.1/24
> [172.31.0.1]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__172.31.0.1_24&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=PIGJNMisAQ9iokicyVS4lKZ7fLKTOjQYSIV6R83EdO8&s=rqMxle8BgWOlhM3GlQ2s4e96C9zXLut8Ap0enbFWkfk&e=>
> +
> +ovn-nbctl lsp-add ls1 ls1-to-router -- set Logical_Switch_Port
> ls1-to-router type=router \
> +          options:router-port=router-to-ls1 -- lsp-set-addresses
> ls1-to-router router
> +ovn-nbctl lsp-add ls2 ls2-to-router -- set Logical_Switch_Port
> ls2-to-router type=router \
> +          options:router-port=router-to-ls2 -- lsp-set-addresses
> ls2-to-router router
> +ovn-nbctl lsp-add ls-underlay underlay-to-router -- set
> Logical_Switch_Port \
> +                              underlay-to-router type=router \
> +                              options:router-port=router-to-underlay \
> +                              -- lsp-set-addresses underlay-to-router
> router
> +
> +ovn-nbctl lrp-set-gateway-chassis router-to-underlay hv3
> +
> +ovn-nbctl --wait=sb sync
> +
> +sleep 2
> +
> +OVN_POPULATE_ARP
> +
> ++# lsp_to_ls LSP
> ++#
> ++# Prints the name of the logical switch that contains LSP.
> +lsp_to_ls () {
> +    case $1 in dnl (
> +        lp?[[11]]) echo ls1 ;; dnl (
> +        lp?[[12]]) echo ls2 ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +vif_to_ls () {
> +    case $1 in dnl (
> +        vif?[[11]]) echo ls1 ;; dnl (
> +        vif?[[12]]) echo ls2 ;; dnl (
> +        vif-north) echo ls-north ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +hv_to_num () {
> +    case $1 in dnl (
> +        hv1) echo 1 ;; dnl (
> +        hv2) echo 2 ;; dnl (
> +        hv3) echo 3 ;; dnl (
> +        hv4) echo 4 ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +vif_to_num () {
> +    case $1 in dnl (
> +        vif22) echo 22 ;; dnl (
> +        vif21) echo 21 ;; dnl (
> +        vif11) echo 11 ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +vif_to_hv () {
> +    case $1 in dnl (
> +        vif[[1]]?) echo hv1 ;; dnl (
> +        vif[[2]]?) echo hv2 ;; dnl (
> +        vif-north) echo hv4 ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +vif_to_lrp () {
> +    echo router-to-`vif_to_ls $1`
> +}
> +
> +ip_to_hex() {
> +       printf "%02x%02x%02x%02x" "$@"
> +}
> +
> +
> +test_ip() {
> +        # This packet has bad checksums but logical L3 routing doesn't
> check.
> +        local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5
> outport=$6
> +        local
> packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000
> +        shift; shift; shift; shift; shift
> +        hv=`vif_to_hv $inport`
> +        as $hv ovs-appctl netdev-dummy/receive $inport $packet
> +        in_ls=`vif_to_ls $inport`
> +        for outport; do
> +            out_ls=`vif_to_ls $outport`
> +            if test $in_ls = $out_ls; then
> +                # Ports on the same logical switch receive exactly the
> same packet.
> +                echo $packet
> +            else
> +                # Routing decrements TTL and updates source and dest MAC
> +                # (and checksum).
> +                out_lrp=`vif_to_lrp $outport`
> +                # For North-South, packet will come via gateway chassis,
> i.e hv3
> +                if test $inport = vif-north; then
> +                    echo
> f00000000011aabbccddee3308004500001c000000003f110100${src_ip}${dst_ip}0035111100080000
> >> $outport.expected
> +                fi
> +                if test $outport = vif-north; then
> +                    echo
> f0f000000011aabbccddee1108004500001c000000003f110100${src_ip}${dst_ip}0035111100080000
> >> $outport.expected
> +                fi
> +            fi >> $outport.expected
> +        done
> +}
> +
> +# Dump a bunch of info helpful for debugging if there's a failure.
> +
> +echo "------ OVN dump ------"
> +ovn-nbctl show
> +ovn-sbctl show
> +ovn-sbctl list port_binding
> +ovn-sbctl list mac_binding
> +
> +echo "------ hv1 dump ------"
> +as hv1 ovs-vsctl show
> +as hv1 ovs-vsctl list Open_Vswitch
> +
> +echo "------ hv2 dump ------"
> +as hv2 ovs-vsctl show
> +as hv2 ovs-vsctl list Open_Vswitch
> +
> +echo "------ hv3 dump ------"
> +as hv3 ovs-vsctl show
> +as hv3 ovs-vsctl list Open_Vswitch
> +
> +echo "------ hv4 dump ------"
> +as hv4 ovs-vsctl show
> +as hv4 ovs-vsctl list Open_Vswitch
> +
> +echo "Send traffic North to South"
> +
> +sip=`ip_to_hex 172 31 0 10`
> +dip=`ip_to_hex 192 168 1 1`
> +test_ip vif-north f0f000000011 000001010207 $sip $dip vif11
> +
> +sleep 1
> +
> +# Confirm that North to south traffic works fine and went through gateway
> chassis, i.e HV3
> +OVN_CHECK_PACKETS([hv1/vif11-tx.pcap], [vif11.expected])
> +
> +echo "Send traffic South to Nouth"
> +sip=`ip_to_hex 192 168 1 1`
> +dip=`ip_to_hex 172 31 0 10`
> +test_ip vif11 f00000000011 000001010203 $sip $dip vif-north
> +
> +sleep 1
> +
> +# Confirm that South to North traffic works fine.
> +OVN_CHECK_PACKETS_REMOVE_BROADCAST([hv4/vif-north-tx.pcap],
> [vif-north.expected])
> +
> +# Confirm that packets did not go out via tunnel port.
> +AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep table=32 | grep
> NXM_NX_TUN_METADATA0 | grep n_packets=0 | wc -l], [0], [[1
> +]])
> +
> +# Confirm that HV1 chassis mac is never seen on Gateway chassis, i.e HV3
> +AT_CHECK([as hv3 ovs-appctl fdb/show br-phys | grep aa:bb:cc:dd:ee:11 |
> wc -l], [0], [[0
> +]])
> +
> +echo "----------- Post Traffic hv1 dump -----------"
> +as hv1 ovs-ofctl -O OpenFlow13 dump-flows br-int
> +as hv1 ovs-appctl fdb/show br-phys
> +
> +echo "----------- Post Traffic hv2 dump -----------"
> +as hv2 ovs-ofctl -O OpenFlow13 dump-flows br-int
> +as hv2 ovs-appctl fdb/show br-phys
> +
> +echo "----------- Post Traffic hv3 dump -----------"
> +as hv3 ovs-ofctl -O OpenFlow13 dump-flows br-int
> +as hv3 ovs-appctl fdb/show br-phys
> +
> +echo "----------- Post Traffic hv4 dump -----------"
> +as hv4 ovs-ofctl -O OpenFlow13 dump-flows br-int
> +as hv4 ovs-appctl fdb/show br-phys
> +
> +OVN_CLEANUP([hv1],[hv2],[hv3],[hv4])
> +
> +AT_CLEANUP
> +
> +
> +AT_SETUP([ovn -- 2 HVs, 2 lports/HV, localnet ports, DVR N-S ARP
> handling])
> +ovn_start
> +
> +# In this test cases we create 3 switches, all connected to same
> +# physical network (through br-phys on each HV). LS1 and LS2 have
> +# 1 VIF each. Each HV has 1 VIF port. The first digit
> +# of VIF port name indicates the hypervisor it is bound to, e.g.
> +# lp23 means VIF 3 on hv2.
> +#
> +# All the switches are connected to a logical router "router".
> +#
> +# Each switch's VLAN tag and their logical switch ports are:
> +#   - ls1:
> +#       - tagged with VLAN 101
> +#       - ports: lp11
> +#   - ls2:
> +#       - tagged with VLAN 201
> +#       - ports: lp22
> +#   - ls-underlay:
> +#       - tagged with VLAN 1000
> +# Note: a localnet port is created for each switch to connect to
> +# physical network.
> +
> +for i in 1 2; do
> +    ls_name=ls$i
> +    ovn-nbctl ls-add $ls_name bridged
> +    ln_port_name=ln$i
> +    if test $i -eq 1; then
> +        ovn-nbctl lsp-add $ls_name $ln_port_name "" 101
> +    elif test $i -eq 2; then
> +        ovn-nbctl lsp-add $ls_name $ln_port_name "" 201
> +    fi
> +    ovn-nbctl lsp-set-addresses $ln_port_name unknown
> +    ovn-nbctl lsp-set-type $ln_port_name localnet
> +    ovn-nbctl lsp-set-options $ln_port_name network_name=phys
> +done
> +
> +# lsp_to_ls LSP
> +#
> +# Prints the name of the logical switch that contains LSP.
> +lsp_to_ls () {
> +    case $1 in dnl (
> +        lp?[[11]]) echo ls1 ;; dnl (
> +        lp?[[12]]) echo ls2 ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +vif_to_hv () {
> +    case $1 in dnl (
> +        vif[[1]]?) echo hv1 ;; dnl (
> +        vif[[2]]?) echo hv2 ;; dnl (
> +        vif?[[north]]?) echo hv4 ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +ip_to_hex() {
> +       printf "%02x%02x%02x%02x" "$@"
> +}
> +
> +net_add n1
> +for i in 1 2; do
> +    sim_add hv$i
> +    as hv$i
> +    ovs-vsctl add-br br-phys
> +    ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
> +    ovs-vsctl set open .
> external-ids:ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:$i$i"
> +    ovn_attach n1 br-phys 192.168.0.$i
> +
> +    ovs-vsctl add-port br-int vif$i$i -- \
> +        set Interface vif$i$i external-ids:iface-id=lp$i$i \
> +                              options:tx_pcap=hv$i/vif$i$i-tx.pcap \
> +                              options:rxq_pcap=hv$i/vif$i$i-rx.pcap \
> +                              ofport-request=$i$i
> +
> +    lsp_name=lp$i$i
> +    ls_name=$(lsp_to_ls $lsp_name)
> +
> +    ovn-nbctl lsp-add $ls_name $lsp_name
> +    ovn-nbctl lsp-set-addresses $lsp_name "f0:00:00:00:00:$i$i
> 192.168.$i.$i"
> +    ovn-nbctl lsp-set-port-security $lsp_name f0:00:00:00:00:$i$i
> +
> +    OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up $lsp_name` = xup])
> +
> +done
> +
> +ovn-nbctl ls-add ls-underlay bridged
> +ovn-nbctl lsp-add ls-underlay ln3 "" 1000
> +ovn-nbctl lsp-set-addresses ln3 unknown
> +ovn-nbctl lsp-set-type ln3 localnet
> +ovn-nbctl lsp-set-options ln3 network_name=phys
> +
> +ovn-nbctl ls-add ls-north bridged
> +ovn-nbctl lsp-add ls-north ln4 "" 1000
> +ovn-nbctl lsp-set-addresses ln4 unknown
> +ovn-nbctl lsp-set-type ln4 localnet
> +ovn-nbctl lsp-set-options ln4 network_name=phys
> +
> +# Add a VM on ls-north
> +ovn-nbctl lsp-add ls-north lp-north
> +ovn-nbctl lsp-set-addresses lp-north "f0:f0:00:00:00:11 172.31.0.10"
> +ovn-nbctl lsp-set-port-security lp-north f0:f0:00:00:00:11
> +
> +# Add 3rd hypervisor
> +sim_add hv3
> +as hv3 ovs-vsctl add-br br-phys
> +as hv3 ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
> +as hv3 ovs-vsctl set open .
> external-ids:ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:33"
> +as hv3 ovn_attach n1 br-phys 192.168.0.3
> +
> +# Add 4th hypervisor
> +sim_add hv4
> +as hv4 ovs-vsctl add-br br-phys
> +as hv4 ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
> +as hv4 ovs-vsctl set open .
> external-ids:ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:44"
> +as hv4 ovn_attach n1 br-phys 192.168.0.4
> +
> +as hv4 ovs-vsctl add-port br-int vif-north -- \
> +        set Interface vif-north external-ids:iface-id=lp-north \
> +                              options:tx_pcap=hv4/vif-north-tx.pcap \
> +                              options:rxq_pcap=hv4/vif-north-rx.pcap \
> +                              ofport-request=44
> +
> +ovn-nbctl lr-add router
> +ovn-nbctl lrp-add router router-to-ls1 00:00:01:01:02:03 192.168.1.3/24
> +ovn-nbctl [192.168.1.3]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__192.168.1.3_24-2Bovn-2Dnbctl&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=PIGJNMisAQ9iokicyVS4lKZ7fLKTOjQYSIV6R83EdO8&s=r3laW3QCkYmIZydSf8n5bHm0ObKIuSd3VACsekBmSbg&e=>
> lrp-add router router-to-ls2 00:00:01:01:02:05 192.168.2.3/24
> +ovn-nbctl [192.168.2.3]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__192.168.2.3_24-2Bovn-2Dnbctl&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=PIGJNMisAQ9iokicyVS4lKZ7fLKTOjQYSIV6R83EdO8&s=suQy9nYmhP89HVjKfN--Kvziv8XSkkzS9bXCDrfE1c4&e=>
> lrp-add router router-to-underlay 00:00:01:01:02:07 172.31.0.1/24
> [172.31.0.1]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__172.31.0.1_24&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=PIGJNMisAQ9iokicyVS4lKZ7fLKTOjQYSIV6R83EdO8&s=rqMxle8BgWOlhM3GlQ2s4e96C9zXLut8Ap0enbFWkfk&e=>
> +
> +ovn-nbctl lsp-add ls1 ls1-to-router -- set Logical_Switch_Port
> ls1-to-router type=router \
> +          options:router-port=router-to-ls1 -- lsp-set-addresses
> ls1-to-router router
> +ovn-nbctl lsp-add ls2 ls2-to-router -- set Logical_Switch_Port
> ls2-to-router type=router \
> +          options:router-port=router-to-ls2 -- lsp-set-addresses
> ls2-to-router router
> +ovn-nbctl lsp-add ls-underlay underlay-to-router -- set
> Logical_Switch_Port \
> +                              underlay-to-router type=router \
> +                              options:router-port=router-to-underlay \
> +                              -- lsp-set-addresses underlay-to-router
> router
> +
> +
> +OVN_POPULATE_ARP
> +
> ++# lsp_to_ls LSP
> ++#
> ++# Prints the name of the logical switch that contains LSP.
> +lsp_to_ls () {
> +    case $1 in dnl (
> +        lp?[[11]]) echo ls1 ;; dnl (
> +        lp?[[12]]) echo ls2 ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +vif_to_ls () {
> +    case $1 in dnl (
> +        vif?[[11]]) echo ls1 ;; dnl (
> +        vif?[[12]]) echo ls2 ;; dnl (
> +        vif-north) echo ls-north ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +hv_to_num () {
> +    case $1 in dnl (
> +        hv1) echo 1 ;; dnl (
> +        hv2) echo 2 ;; dnl (
> +        hv3) echo 3 ;; dnl (
> +        hv4) echo 4 ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +vif_to_num () {
> +    case $1 in dnl (
> +        vif22) echo 22 ;; dnl (
> +        vif21) echo 21 ;; dnl (
> +        vif11) echo 11 ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +vif_to_hv () {
> +    case $1 in dnl (
> +        vif[[1]]?) echo hv1 ;; dnl (
> +        vif[[2]]?) echo hv2 ;; dnl (
> +        vif-north) echo hv4 ;; dnl (
> +        *) AT_FAIL_IF([:]) ;;
> +    esac
> +}
> +
> +vif_to_lrp () {
> +    echo router-to-`vif_to_ls $1`
> +}
> +
> +ip_to_hex() {
> +       printf "%02x%02x%02x%02x" "$@"
> +}
> +
> +# Dump a bunch of info helpful for debugging if there's a failure.
> +
> +echo "------ OVN dump ------"
> +ovn-nbctl show
> +ovn-sbctl show
> +ovn-sbctl list port_binding
> +ovn-sbctl list mac_binding
> +
> +echo "------ hv1 dump ------"
> +as hv1 ovs-vsctl show
> +as hv1 ovs-vsctl list Open_Vswitch
> +
> +echo "------ hv2 dump ------"
> +as hv2 ovs-vsctl show
> +as hv2 ovs-vsctl list Open_Vswitch
> +
> +echo "------ hv3 dump ------"
> +as hv3 ovs-vsctl show
> +as hv3 ovs-vsctl list Open_Vswitch
> +
> +echo "------ hv4 dump ------"
> +as hv4 ovs-vsctl show
> +as hv4 ovs-vsctl list Open_Vswitch
> +
> +# test_arp INPORT SHA SPA TPA [REPLY_HA]
> +#
> +# Causes a packet to be received on INPORT.  The packet is an ARP
> +# request with SHA, SPA, and TPA as specified.  If REPLY_HA is provided,
> then
> +# it should be the hardware address of the target to expect to receive in
> an
> +# ARP reply; otherwise no reply is expected.
> +#
> +# INPORT is an logical switch port number, e.g. 11 for vif11.
> +# SHA and REPLY_HA are each 12 hex digits.
> +# SPA and TPA are each 8 hex digits.
> +test_arp() {
> +    local inport=$1 sha=$2 spa=$3 tpa=$4 reply_ha=$5
> +    local
> request=ffffffffffff${sha}08060001080006040001${sha}${spa}ffffffffffff${tpa}
> +    hv=`vif_to_hv $inport`
> +    as $hv ovs-appctl netdev-dummy/receive $inport $request
> +
> +    if test X$reply_ha = X; then
> +        # Expect to receive the broadcast ARP on the other logical switch
> ports
> +        # if no reply is expected.
> +        local i j
> +        for i in 1 2 3; do
> +            for j in 1 2 3; do
> +                if test $i$j != $inport; then
> +                    echo $request >> $i$j.expected
> +                fi
> +            done
> +        done
> +    else
> +        # Expect to receive the reply, if any.
> +        local
> reply=${sha}${reply_ha}08060001080006040002${reply_ha}${tpa}${sha}${spa}
> +        local
> reply_vid=${sha}${reply_ha}810003e808060001080006040002${reply_ha}${tpa}${sha}${spa}
> +        echo $reply_vid >> ${inport}_vid.expected
> +        echo $reply >> $inport.expected
> +    fi
> +}
> +
> +sip=`ip_to_hex 172 31 0 10`
> +tip=`ip_to_hex 172 31 0 1`
> +
> +test_arp vif-north f0f000000011 $sip $tip
> +# Confirm that vif-north does not get ARP reply
> +AT_CHECK([wc -l hv4/vif-north-tx.pcap | awk '{print $1}'], [0], [[0
> +]])
> +
> +# Set a hypervisor as gateway chassis, for router port 172.31.0.1
> +ovn-nbctl lrp-set-gateway-chassis router-to-underlay hv3
> +ovn-nbctl --wait=sb sync
> +sleep 2
> +
> +test_arp vif-north f0f000000011 $sip $tip 000001010207
> +
> +sleep 1
> +
> +# Confirm that vif-north gets a single ARP reply this time
> +OVN_CHECK_PACKETS_REMOVE_BROADCAST([hv4/vif-north-tx.pcap],
> [vif-north.expected])
> +
> +# Confirm that only redirect chassis allowed arp resolution.
> +OVN_CHECK_PACKETS_REMOVE_BROADCAST([hv3/br-phys_n1-tx.pcap],
> [vif-north_vid.expected])
> +sed -i '/ffffffffffff/d' hv3/br-phys_n1-tx.packets
> +AT_CHECK([grep 000001010207 hv3/br-phys_n1-tx.packets | wc -l], [0], [[1
> +]])
> +
> +# Confirm that other OVN chassis did not generate ARP reply.
> +$PYTHON "$top_srcdir/utilities/ovs-pcap.in [ovs-pcap.in]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__ovs-2Dpcap.in&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=PIGJNMisAQ9iokicyVS4lKZ7fLKTOjQYSIV6R83EdO8&s=2C3bpksCPiN-64fg1Las63zBhPREoL9p8vojGneVx9o&e=>"
> hv1/br-phys_n1-tx.pcap > hv1/br-phys_n1-tx.packets
> +$PYTHON "$top_srcdir/utilities/ovs-pcap.in [ovs-pcap.in]
> <https://urldefense.proofpoint.com/v2/url?u=http-3A__ovs-2Dpcap.in&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=PIGJNMisAQ9iokicyVS4lKZ7fLKTOjQYSIV6R83EdO8&s=2C3bpksCPiN-64fg1Las63zBhPREoL9p8vojGneVx9o&e=>"
> hv2/br-phys_n1-tx.pcap > hv2/br-phys_n1-tx.packets
> +
> +AT_CHECK([grep 000001010207 hv1/br-phys_n1-tx.packets | wc -l], [0], [[0
> +]])
> +AT_CHECK([grep 000001010207 hv2/br-phys_n1-tx.packets | wc -l], [0], [[0
> +]])
> +
> +echo "----------- Post Traffic hv1 dump -----------"
> +as hv1 ovs-ofctl -O OpenFlow13 dump-flows br-int
> +as hv1 ovs-appctl fdb/show br-phys
> +
> +echo "----------- Post Traffic hv2 dump -----------"
> +as hv2 ovs-ofctl -O OpenFlow13 dump-flows br-int
> +as hv2 ovs-appctl fdb/show br-phys
> +
> +echo "----------- Post Traffic hv3 dump -----------"
> +as hv3 ovs-ofctl -O OpenFlow13 dump-flows br-int
> +as hv3 ovs-appctl fdb/show br-phys
> +
> +echo "----------- Post Traffic hv4 dump -----------"
> +as hv4 ovs-ofctl -O OpenFlow13 dump-flows br-int
> +as hv4 ovs-appctl fdb/show br-phys
> +
> +OVN_CLEANUP([hv1],[hv2],[hv3],[hv4])
> +
> +AT_CLEANUP
> --
> 1.8.3.1
>
> _______________________________________________
> dev mailing list
> d...@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> [mail.openvswitch.org]
> <https://urldefense.proofpoint.com/v2/url?u=https-3A__mail.openvswitch.org_mailman_listinfo_ovs-2Ddev&d=DwMFaQ&c=s883GpUCOChKOHiocYtGcg&r=mZwX9gFQgeJHzTg-68aCJgsODyUEVsHGFOfL90J6MJY&m=PIGJNMisAQ9iokicyVS4lKZ7fLKTOjQYSIV6R83EdO8&s=Nints8x76fVjfvJvi7wl7Z201OHUMfS3oO7Dhq2JJ7Y&e=>
>
>
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to