[ovs-dev] [PATCH v4 ovn] Add VXLAN support for non-VTEP datapath bindings

Ihar Hrachyshka ihrachys at redhat.com
Wed Sep 16 01:48:45 UTC 2020


On Thu, Sep 3, 2020 at 2:24 PM Numan Siddique <numans at ovn.org> wrote:
>
> Hi Ihar,
>
> Overall the patch LGTM.
>
> I have few comments. Please see below.
>
> Thanks
> Numan
>
>
> On Wed, Aug 26, 2020 at 10:45 PM Ihar Hrachyshka <ihrachys at redhat.com> wrote:
>>
>> Because of limited space in VXLAN VNI to pass over all three of -
>> datapath id, ingress port, egress port - the implementation ignores
>> ingress; and splits the remaining 24 bits of VNI into two chunks, 12
>> bits each - one for datapath and one for egress port.
>>
>> Limitations: because ingress port is not passed, ACLs that rely on it
>> won't work with VXLAN; reduced number of networks and ports per
>> network (max 4096 for both).
>>
>> NB consumers may use NB_Global options:max_tunid to determine maximum
>> capacity for logical switches supported by the setup.
>>
>> Renamed MLF_RCV_FROM_VXLAN_BIT into MLF_RCV_FROM_VTEP_BIT to reflect
>> the new use case.
>
>
> A small correction:
>
> s/MLF_RCV_FROM_VTEP_BIT/MLF_RCV_FROM_RAMP_BIT
>
>
>>
>> Added test scenarios that ping through VXLAN tunnel between two
>> hypervisors added. Also max_tunid is validated.
>>
>> Changes:
>> - v2: run several dvr connectivity tests with vxlan tunnels.
>> - v2: update ovn-architecture.7 documentation.
>> - v3: added is_vxlan helper.
>> - v4: reduce max tunid when vxlan is enabled in cluster.
>> - v4: added options:max_tunid key for NB_Global.
>>
>
> Changes across patch versions need not go as a commit message. You can move the changes below
> after "---" in your next patch version.
>
>
>>
>> Signed-off-by: Ihar Hrachyshka <ihrachys at redhat.com>
>> ---
>>  controller/physical.c        |   84 ++-
>>  include/ovn/logical-fields.h |   12 +-
>>  lib/ovn-util.h               |    5 +
>>  northd/ovn-northd.c          |   78 ++-
>>  ovn-architecture.7.xml       |  103 +++-
>>  ovn-nb.xml                   |    5 +
>>  tests/ovn-macros.at          |    4 +-
>>  tests/ovn.at                 | 1083 +++++++++++++++++-----------------
>>  8 files changed, 728 insertions(+), 646 deletions(-)
>>
>> diff --git a/controller/physical.c b/controller/physical.c
>> index 535c77730..1eacafbfb 100644
>> --- a/controller/physical.c
>> +++ b/controller/physical.c
>> @@ -180,7 +180,8 @@ static void
>>  put_encapsulation(enum mf_field_id mff_ovn_geneve,
>>                    const struct chassis_tunnel *tun,
>>                    const struct sbrec_datapath_binding *datapath,
>> -                  uint16_t outport, struct ofpbuf *ofpacts)
>> +                  uint16_t outport, bool is_ramp_switch,
>> +                  struct ofpbuf *ofpacts)
>>  {
>>      if (tun->type == GENEVE) {
>>          put_load(datapath->tunnel_key, MFF_TUN_ID, 0, 24, ofpacts);
>> @@ -191,7 +192,10 @@ put_encapsulation(enum mf_field_id mff_ovn_geneve,
>>                   MFF_TUN_ID, 0, 64, ofpacts);
>>          put_move(MFF_LOG_INPORT, 0, MFF_TUN_ID, 40, 15, ofpacts);
>>      } else if (tun->type == VXLAN) {
>> -        put_load(datapath->tunnel_key, MFF_TUN_ID, 0, 24, ofpacts);
>> +        uint64_t vni = (is_ramp_switch?
>> +                        datapath->tunnel_key :
>> +                        datapath->tunnel_key | ((uint64_t) outport << 12));
>> +        put_load(vni, MFF_TUN_ID, 0, 24, ofpacts);
>>      } else {
>>          OVS_NOT_REACHED();
>>      }
>> @@ -323,8 +327,9 @@ put_remote_port_redirect_overlay(const struct
>>          if (!rem_tun) {
>>              return;
>>          }
>> -        put_encapsulation(mff_ovn_geneve, tun, binding->datapath,
>> -                          port_key, ofpacts_p);
>> +        put_encapsulation(mff_ovn_geneve, tun, binding->datapath, port_key,
>> +                          !strcmp(binding->type, "vtep"),
>> +                          ofpacts_p);
>>          /* Output to tunnel. */
>>          ofpact_put_OUTPUT(ofpacts_p)->port = rem_tun->ofport;
>>      } else {
>> @@ -360,8 +365,9 @@ put_remote_port_redirect_overlay(const struct
>>              return;
>>          }
>>
>> -        put_encapsulation(mff_ovn_geneve, tun, binding->datapath,
>> -                          port_key, ofpacts_p);
>> +        put_encapsulation(mff_ovn_geneve, tun, binding->datapath, port_key,
>> +                          !strcmp(binding->type, "vtep"),
>> +                          ofpacts_p);
>>
>>          /* Output to tunnels with active/backup */
>>          struct ofpact_bundle *bundle = ofpact_put_BUNDLE(ofpacts_p);
>> @@ -1370,7 +1376,7 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve,
>>
>>              if (!prev || tun->type != prev->type) {
>>                  put_encapsulation(mff_ovn_geneve, tun, mc->datapath,
>> -                                  mc->tunnel_key, &remote_ofpacts);
>> +                                  mc->tunnel_key, true, &remote_ofpacts);
>>                  prev = tun;
>>              }
>>              ofpact_put_OUTPUT(&remote_ofpacts)->port = tun->ofport;
>> @@ -1450,6 +1456,7 @@ void
>>  physical_run(struct physical_ctx *p_ctx,
>>               struct ovn_desired_flow_table *flow_table)
>>  {
>> +
>
> nit: Unrelated change.
>
>>      if (!hc_uuid) {
>>          hc_uuid = xmalloc(sizeof(struct uuid));
>>          uuid_generate(hc_uuid);
>> @@ -1615,11 +1622,12 @@ physical_run(struct physical_ctx *p_ctx,
>>       * Process packets that arrive from a remote hypervisor (by matching
>>       * on tunnel in_port). */
>>
>> -    /* Add flows for Geneve and STT encapsulations.  These
>> -     * encapsulations have metadata about the ingress and egress logical
>> -     * ports.  We set MFF_LOG_DATAPATH, MFF_LOG_INPORT, and
>> -     * MFF_LOG_OUTPORT from the tunnel key data, then resubmit to table
>> -     * 33 to handle packets to the local hypervisor. */
>> +    /* Add flows for Geneve, STT and VXLAN encapsulations.  Geneve and STT
>> +     * encapsulations have metadata about the ingress and egress logical ports.
>> +     * VXLAN encapsulations have metadata about the egress logical port only.
>> +     * We set MFF_LOG_DATAPATH, MFF_LOG_INPORT, and MFF_LOG_OUTPORT from the
>> +     * tunnel key data where possible, then resubmit to table 33 to handle
>> +     * packets to the local hypervisor. */
>>      HMAP_FOR_EACH (tun, hmap_node, &tunnels) {
>>          struct match match = MATCH_CATCHALL_INITIALIZER;
>>          match_set_in_port(&match, tun->ofport);
>> @@ -1648,11 +1656,7 @@ physical_run(struct physical_ctx *p_ctx,
>>                          &ofpacts, hc_uuid);
>>      }
>>
>> -    /* Add flows for VXLAN encapsulations.  Due to the limited amount of
>> -     * metadata, we only support VXLAN for connections to gateways.  The
>> -     * VNI is used to populate MFF_LOG_DATAPATH.  The gateway's logical
>> -     * port is set to MFF_LOG_INPORT.  Then the packet is resubmitted to
>> -     * table 16 to determine the logical egress port. */
>> +    /* Handle VXLAN encapsulations. */
>>      HMAP_FOR_EACH (tun, hmap_node, &tunnels) {
>>          if (tun->type != VXLAN) {
>>              continue;
>> @@ -1669,19 +1673,41 @@ physical_run(struct physical_ctx *p_ctx,
>>              }
>>
>>              match_set_in_port(&match, tun->ofport);
>> -            match_set_tun_id(&match, htonll(binding->datapath->tunnel_key));
>> -
>>              ofpbuf_clear(&ofpacts);
>> -            put_move(MFF_TUN_ID, 0,  MFF_LOG_DATAPATH, 0, 24, &ofpacts);
>> -            put_load(binding->tunnel_key, MFF_LOG_INPORT, 0, 15, &ofpacts);
>> -            /* For packets received from a vxlan tunnel, set a flag to that
>> -             * effect. */
>> -            put_load(1, MFF_LOG_FLAGS, MLF_RCV_FROM_VXLAN_BIT, 1, &ofpacts);
>> -            put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, &ofpacts);
>> -
>> -            ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 100,
>> -                            binding->header_.uuid.parts[0],
>> -                            &match, &ofpacts, hc_uuid);
>> +
>> +            if (!strcmp(binding->type, "vtep")) {
>> +                /* Add flows for ramp switches.  The VNI is used to populate
>> +                 * MFF_LOG_DATAPATH.  The gateway's logical port is set to
>> +                 * MFF_LOG_INPORT.  Then the packet is resubmitted to table 8
>> +                 * to determine the logical egress port. */
>> +                match_set_tun_id(&match,
>> +                                 htonll(binding->datapath->tunnel_key));
>> +
>> +                put_move(MFF_TUN_ID, 0,  MFF_LOG_DATAPATH, 0, 24, &ofpacts);
>> +                put_load(binding->tunnel_key, MFF_LOG_INPORT, 0, 15, &ofpacts);
>> +                /* For packets received from a ramp tunnel, set a flag to that
>> +                 * effect. */
>> +                put_load(1, MFF_LOG_FLAGS, MLF_RCV_FROM_RAMP_BIT, 1, &ofpacts);
>> +                put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, &ofpacts);
>> +
>> +                ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 100,
>> +                                binding->header_.uuid.parts[0],
>> +                                &match, &ofpacts, hc_uuid);
>> +            } else {
>> +                /* Add flows for non-VTEP tunnels. Split VNI into two 12-bit
>> +                 * sections and use them for datapath and outport IDs. */
>> +                match_set_tun_id_masked(
>> +                    &match,
>> +                    htonll(binding->datapath->tunnel_key),
>> +                    (OVS_FORCE ovs_be64) 0xff0f000000000000ULL);
>
>
> What is the need to have this match ?
>
> I think it should be fine if add OF flows like the way we add for geneve.
>
> If there are totally 'n' chassis, then in the case of geneve/stt we add
>    - 'n -1' OF flows on each chassis.
>
> In the case of vxlan we add
>   - (n -1) * (m) OF flows on a particular chassis where 'm' is the number of local datapaths if conditional monitoring is enabled, else
>     (n -1 ) * (x) OF flows where 'x' is the number of datapaths.
>
>
> I don't  think there is a need to add the flows for VxLAN in this hmap loop. Please correct me if I'm wrong here.
>
> You can just assume that vxlan is configured on all the chassis and move the code to add flows here - https://github.com/ovn-org/ovn/blob/master/controller/physical.c#L1639
> for table 0.
>
> To handle the use case  of both normal VxLAN tunnelling and VxLAN ramp scenario, you can probably add higher priority flows for ramp related flows.

You are right, there is no need to match against tun_id for non-ramp
vxlan case. I think I added this vxlan specific match while trying to
accommodate for ramp branch that already matched against tun_id
(though against all 24 bits; that's why I had to add a masked match
for just 12 bits for non-ramp case.)

I've moved flows up as you suggested and simplified the code a bit.

Thanks for the notice!

>
>
>
>> +
>> +                put_move(MFF_TUN_ID, 12, MFF_LOG_OUTPORT,  0, 12, &ofpacts);
>> +                put_move(MFF_TUN_ID, 0, MFF_LOG_DATAPATH, 0, 12, &ofpacts);
>> +
>> +                put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
>> +                ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 100, 0,
>> +                                &match, &ofpacts, hc_uuid);
>> +            }
>>          }
>>      }
>
>
>
>>
>>
>> diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
>> index 61d17d14f..1dff44dd1 100644
>> --- a/include/ovn/logical-fields.h
>> +++ b/include/ovn/logical-fields.h
>> @@ -51,7 +51,7 @@ void ovn_init_symtab(struct shash *symtab);
>>  /* MFF_LOG_FLAGS_REG bit assignments */
>>  enum mff_log_flags_bits {
>>      MLF_ALLOW_LOOPBACK_BIT = 0,
>> -    MLF_RCV_FROM_VXLAN_BIT = 1,
>> +    MLF_RCV_FROM_RAMP_BIT = 1,
>>      MLF_FORCE_SNAT_FOR_DNAT_BIT = 2,
>>      MLF_FORCE_SNAT_FOR_LB_BIT = 3,
>>      MLF_LOCAL_ONLY_BIT = 4,
>> @@ -64,11 +64,11 @@ enum mff_log_flags {
>>      /* Allow outputting back to inport. */
>>      MLF_ALLOW_LOOPBACK = (1 << MLF_ALLOW_LOOPBACK_BIT),
>>
>> -    /* Indicate that a packet was received from a VXLAN tunnel to
>> -     * compensate for the lack of egress port information available in
>> -     * VXLAN encapsulation.  Egress port information is available for
>> -     * Geneve and STT tunnel types. */
>> -    MLF_RCV_FROM_VXLAN = (1 << MLF_RCV_FROM_VXLAN_BIT),
>> +    /* Indicate that a packet was received from a ramp switch to compensate for
>> +     * the lack of egress port information available in ramp switch
>> +     * encapsulation.  Egress port information is available for Geneve, STT and
>> +     * regular VXLAN tunnel types. */
>> +    MLF_RCV_FROM_VXLAN = (1 << MLF_RCV_FROM_RAMP_BIT),
>
>
> Shouldn't this be -  MLF_RCV_FROM_RAMP = (1 << MLF_RCV_FROM_RAMP_BIT)  ?
>
>
>
>>
>>      /* Indicate that a packet needs a force SNAT in the gateway router when
>>       * DNAT has taken place. */
>> diff --git a/lib/ovn-util.h b/lib/ovn-util.h
>> index 0f7b501f1..58d41a582 100644
>> --- a/lib/ovn-util.h
>> +++ b/lib/ovn-util.h
>> @@ -16,6 +16,7 @@
>>  #ifndef OVN_UTIL_H
>>  #define OVN_UTIL_H 1
>>
>> +#include "lib/ovn-sb-idl.h"
>>  #include "lib/packets.h"
>>  #include "include/ovn/version.h"
>>
>> @@ -107,6 +108,10 @@ void ovn_conn_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
>>  #define OVN_MAX_DP_KEY_LOCAL (OVN_MAX_DP_KEY - OVN_MAX_DP_GLOBAL_NUM)
>>  #define OVN_MIN_DP_KEY_GLOBAL (OVN_MAX_DP_KEY_LOCAL + 1)
>>  #define OVN_MAX_DP_KEY_GLOBAL OVN_MAX_DP_KEY
>> +
>> +#define OVN_MAX_DP_VXLAN_KEY ((1u << 12) - 1)
>> +#define OVN_MAX_DP_VXLAN_KEY_LOCAL (OVN_MAX_DP_KEY - OVN_MAX_DP_GLOBAL_NUM)
>> +
>>  struct hmap;
>>  void ovn_destroy_tnlids(struct hmap *tnlids);
>>  void ovn_add_tnlid(struct hmap *set, uint32_t tnlid);
>> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
>> index 233125401..c7bd891d6 100644
>> --- a/northd/ovn-northd.c
>> +++ b/northd/ovn-northd.c
>> @@ -63,6 +63,7 @@ struct northd_context {
>>      struct ovsdb_idl *ovnsb_idl;
>>      struct ovsdb_idl_txn *ovnnb_txn;
>>      struct ovsdb_idl_txn *ovnsb_txn;
>> +    struct ovsdb_idl_index *sbrec_chassis_by_name;
>>      struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name;
>>      struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp;
>>      struct ovsdb_idl_index *sbrec_ip_mcast_by_dp;
>> @@ -1179,12 +1180,34 @@ join_datapaths(struct northd_context *ctx, struct hmap *datapaths,
>>      }
>>  }
>>
>> +static int is_vxlan_mode(struct ovsdb_idl *ovnsb_idl)
>> +{
>> +    const struct sbrec_chassis *chassis, *chassis_next;
>> +    SBREC_CHASSIS_FOR_EACH_SAFE (chassis, chassis_next, ovnsb_idl) {
>> +        for (int i = 0; i < chassis->n_encaps; i++) {
>> +            if (!strcmp(chassis->encaps[i]->type, "vxlan")) {
>> +                return 1;
>> +            }
>> +        }
>> +    }
>> +    return 0;
>> +}
>> +
>> +static uint32_t
>> +get_ovn_max_dp_key_local(struct northd_context *ctx) {
>> +    if (is_vxlan_mode(ctx->ovnsb_idl)) {
>> +        /* TODO: what to do with global tunids? */
>> +        return OVN_MAX_DP_VXLAN_KEY;
>> +    }
>> +    return OVN_MAX_DP_KEY - OVN_MAX_DP_GLOBAL_NUM;
>> +}
>> +
>>  static uint32_t
>> -ovn_datapath_allocate_key(struct hmap *dp_tnlids)
>> +ovn_datapath_allocate_key(struct northd_context *ctx, struct hmap *dp_tnlids)
>>  {
>>      static uint32_t hint;
>>      return ovn_allocate_tnlid(dp_tnlids, "datapath", OVN_MIN_DP_KEY_LOCAL,
>> -                              OVN_MAX_DP_KEY_LOCAL, &hint);
>> +                              get_ovn_max_dp_key_local(ctx), &hint);
>>  }
>>
>>  /* Updates the southbound Datapath_Binding table so that it contains the
>> @@ -1227,7 +1250,7 @@ build_datapaths(struct northd_context *ctx, struct hmap *datapaths,
>>              }
>>          }
>>          if (!tunnel_key) {
>> -            tunnel_key = ovn_datapath_allocate_key(&dp_tnlids);
>> +            tunnel_key = ovn_datapath_allocate_key(ctx, &dp_tnlids);
>>              if (!tunnel_key) {
>>                  break;
>>              }
>> @@ -11689,32 +11712,34 @@ ovnnb_db_run(struct northd_context *ctx,
>>          }
>>      }
>>
>> -    if (!mac_addr_prefix || !monitor_mac) {
>> -        struct smap options;
>> -        smap_clone(&options, &nb->options);
>> +    struct smap options;
>> +    smap_clone(&options, &nb->options);
>>
>> -        if (!mac_addr_prefix) {
>> -            eth_addr_random(&mac_prefix);
>> -            memset(&mac_prefix.ea[3], 0, 3);
>> +    if (!mac_addr_prefix) {
>> +        eth_addr_random(&mac_prefix);
>> +        memset(&mac_prefix.ea[3], 0, 3);
>>
>> -            smap_add_format(&options, "mac_prefix",
>> -                            "%02"PRIx8":%02"PRIx8":%02"PRIx8,
>> -                            mac_prefix.ea[0], mac_prefix.ea[1],
>> -                            mac_prefix.ea[2]);
>> -        }
>> +        smap_add_format(&options, "mac_prefix",
>> +                        "%02"PRIx8":%02"PRIx8":%02"PRIx8,
>> +                        mac_prefix.ea[0], mac_prefix.ea[1],
>> +                        mac_prefix.ea[2]);
>> +    }
>>
>> -        if (!monitor_mac) {
>> -            eth_addr_random(&svc_monitor_mac_ea);
>> -            snprintf(svc_monitor_mac, sizeof svc_monitor_mac,
>> -                     ETH_ADDR_FMT, ETH_ADDR_ARGS(svc_monitor_mac_ea));
>> -            smap_replace(&options, "svc_monitor_mac", svc_monitor_mac);
>> -        }
>> +    if (!monitor_mac) {
>> +        eth_addr_random(&svc_monitor_mac_ea);
>> +        snprintf(svc_monitor_mac, sizeof svc_monitor_mac,
>> +                 ETH_ADDR_FMT, ETH_ADDR_ARGS(svc_monitor_mac_ea));
>> +        smap_replace(&options, "svc_monitor_mac", svc_monitor_mac);
>> +    }
>>
>> -        nbrec_nb_global_verify_options(nb);
>> -        nbrec_nb_global_set_options(nb, &options);
>> +    char *max_tunid = xasprintf("%d", get_ovn_max_dp_key_local(ctx));
>> +    smap_replace(&options, "max_tunid", max_tunid);
>> +    free(max_tunid);
>>
>> -        smap_destroy(&options);
>> -    }
>> +    nbrec_nb_global_verify_options(nb);
>> +    nbrec_nb_global_set_options(nb, &options);
>> +
>> +    smap_destroy(&options);
>>
>>      /* Update the probe interval. */
>>      northd_probe_interval_nb = get_probe_interval(ovnnb_db, nb);
>> @@ -12567,6 +12592,10 @@ main(int argc, char *argv[])
>>      ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis);
>>      ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_name);
>>      ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_other_config);
>> +    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_encaps);
>> +
>> +    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_encap);
>> +    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_encap_col_type);
>>
>>      ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis_private);
>>      ovsdb_idl_add_column(ovnsb_idl_loop.idl,
>> @@ -12678,6 +12707,7 @@ main(int argc, char *argv[])
>>                  .ovnnb_txn = ovsdb_idl_loop_run(&ovnnb_idl_loop),
>>                  .ovnsb_idl = ovnsb_idl_loop.idl,
>>                  .ovnsb_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),
>> +                .sbrec_chassis_by_name = sbrec_chassis_by_name,
>>                  .sbrec_ha_chassis_grp_by_name = sbrec_ha_chassis_grp_by_name,
>>                  .sbrec_mcast_group_by_name_dp = sbrec_mcast_group_by_name_dp,
>>                  .sbrec_ip_mcast_by_dp = sbrec_ip_mcast_by_dp,
>> diff --git a/ovn-architecture.7.xml b/ovn-architecture.7.xml
>> index b1a462933..ac01fbc4c 100644
>> --- a/ovn-architecture.7.xml
>> +++ b/ovn-architecture.7.xml
>> @@ -1163,11 +1163,14 @@
>>
>>        <p>
>>          Geneve and STT tunnels pass this field as part of the tunnel key.
>> -        Although VXLAN tunnels do not explicitly carry a logical input port,
>> -        OVN only uses VXLAN to communicate with gateways that from OVN's
>> +        Ramp switch VXLAN tunnels do not explicitly carry a logical input port,
>> +        but since they are used to communicate with gateways that from OVN's
>>          perspective consist of only a single logical port, so that OVN can set
>>          the logical input port field to this one on ingress to the OVN logical
>> -        pipeline.
>> +        pipeline. As for regular VXLAN tunnels, they don't carry input port
>> +        field at all. This puts additional limitations on cluster
>> +        capabilities that are described in
>> +        <code>Tunnel Encapsulations</code> section.
>>        </p>
>>      </dd>
>>
>> @@ -1183,15 +1186,15 @@
>>        </p>
>>
>>        <p>
>> -        Geneve and STT tunnels pass this field as part of the tunnel key.
>> -        VXLAN tunnels do not transmit the logical output port field.
>> -        Since VXLAN tunnels do not carry a logical output port field in
>> -        the tunnel key, when a packet is received from VXLAN tunnel by
>> -        an OVN hypervisor, the packet is resubmitted to table 8 to
>> -        determine the output port(s);  when the packet reaches table 32,
>> +        Geneve, STT and regular VXLAN tunnels pass this field as part of the
>> +        tunnel key. Ramp switch VXLAN tunnels do not transmit the logical
>> +        output port field, and since they do not carry a logical output port
>> +        field in the tunnel key, when a packet is received from ramp switch
>> +        VXLAN tunnel by an OVN hypervisor, the packet is resubmitted to table 8
>> +        to determine the output port(s); when the packet reaches table 32,
>>          these packets are resubmitted to table 33 for local delivery by
>>          checking a MLF_RCV_FROM_VXLAN flag, which is set when the packet
>> -        arrives from a VXLAN tunnel.
>> +        arrives from a ramp tunnel.
>>        </p>
>>      </dd>
>>
>> @@ -1263,15 +1266,16 @@
>>        </p>
>>
>>        <p>
>> -        Table 0 also processes packets that arrive from other chassis.  It
>> +        Table 0 also processes packets that arrive from other chassis. It
>>          distinguishes them from other packets by ingress port, which is a
>> -        tunnel.  As with packets just entering the OVN pipeline, the actions
>> -        annotate these packets with logical datapath and logical ingress port
>> -        metadata.  In addition, the actions set the logical output port field,
>> +        tunnel. As with packets just entering the OVN pipeline, the actions
>> +        annotate these packets with logical datapath metadata. For tunnel types
>> +        that support it, they are also annotated with logical ingress port
>> +        metadata. In addition, the actions set the logical output port field,
>>          which is available because in OVN tunneling occurs after the logical
>> -        output port is known.  These three pieces of information are obtained
>> +        output port is known. These pieces of information are obtained
>>          from the tunnel encapsulation metadata (see <code>Tunnel
>> -        Encapsulations</code> for encoding details).  Then the actions resubmit
>> +        Encapsulations</code> for encoding details). Then the actions resubmit
>>          to table 33 to enter the logical egress pipeline.
>>        </p>
>>      </li>
>> @@ -1430,12 +1434,12 @@
>>
>>        <ul>
>>          <li>
>> -          A higher-priority rule to match packets received from VXLAN tunnels,
>> -          based on flag MLF_RCV_FROM_VXLAN, and resubmit these packets to table
>> -          33 for local delivery.  Packets received from VXLAN tunnels reach
>> -          here because of a lack of logical output port field in the tunnel key
>> -          and thus these packets needed to be submitted to table 8 to
>> -          determine the output port.
>> +          A higher-priority rule to match packets received from ramp switch
>> +          tunnels, based on flag MLF_RCV_FROM_VXLAN, and resubmit these packets
>> +          to table 33 for local delivery.  Packets received from ramp switch
>> +          tunnels reach here because of a lack of logical output port field in
>> +          the tunnel key and thus these packets needed to be submitted to table
>> +          8 to determine the output port.
>>          </li>
>>          <li>
>>            A higher-priority rule to match packets received from ports of type
>> @@ -2658,9 +2662,9 @@
>>    <h2>Tunnel Encapsulations</h2>
>>
>>    <p>
>> -    OVN annotates logical network packets that it sends from one hypervisor to
>> -    another with the following three pieces of metadata, which are encoded in
>> -    an encapsulation-specific fashion:
>> +    In general, OVN annotates logical network packets that it sends from one
>> +    hypervisor to another with the following three pieces of metadata, which
>> +    are encoded in an encapsulation-specific fashion:
>>    </p>
>>
>>    <ul>
>> @@ -2686,16 +2690,57 @@
>>    </ul>
>>
>>    <p>
>> -    For hypervisor-to-hypervisor traffic, OVN supports only Geneve and STT
>> -    encapsulations, for the following reasons:
>> +      When VXLAN is enabled on any hypervisor in a cluster, datapath and egress
>> +      port identifier ranges are reduced to 12-bits. This is done because only
>> +      STT and Geneve provide the large space for metadata (over 32 bits per
>> +      packet). To accommodate for VXLAN, 24 bits available are split as
>> +      follows:
>> +  </p>
>> +
>> +  <ul>
>> +    <li>
>> +      12-bit logical datapath identifier, derived from the
>> +      <code>tunnel_key</code> column in the OVN Southbound
>> +      <code>Datapath_Binding</code> table.
>> +    </li>
>> +
>> +    <li>
>> +      12-bit logical egress port identifier.  IDs 0 through 32767 have the same
>> +      meaning as for logical ingress ports.  IDs 32768 through 65535,
>> +      inclusive, may be assigned to logical multicast groups (see the
>> +      <code>tunnel_key</code> column in the OVN Southbound
>> +      <code>Multicast_Group</code> table).
>> +    </li>
>> +
>> +    <li>
>> +      No logical ingress port identifier.
>> +    </li>
>> +  </ul>
>> +
>> +  <p>
>> +      The limited space available for metadata when VXLAN tunnels are enabled
>> +      in a cluster put the following functional limitations onto features
>> +      available to users:
>>    </p>
>>
>>    <ul>
>>      <li>
>> -      Only STT and Geneve support the large amounts of metadata (over 32 bits
>> -      per packet) that OVN uses (as described above).
>> +      The maximum number of networks is reduced to 4096.
>> +    </li>
>> +    <li>
>> +      The maximum number of ports per network is reduced to 4096. (Including
>> +      multicast group ports.)
>> +    </li>
>> +    <li>
>> +      ACLs matching against logical ingress port identifiers are not supported.
>>      </li>
>> +  </ul>
>>
>> +  <p>
>> +      In addition to functional limitations described above, the following
>> +      should be considered before enabling it in your cluster:
>> +  </p>
>> +  <ul>
>>      <li>
>>        STT and Geneve use randomized UDP or TCP source ports that allows
>>        efficient distribution among multiple paths in environments that use ECMP
>> diff --git a/ovn-nb.xml b/ovn-nb.xml
>> index 9f3621dcd..66bd37ce1 100644
>> --- a/ovn-nb.xml
>> +++ b/ovn-nb.xml
>> @@ -147,6 +147,11 @@
>>          </p>
>>        </column>
>>
>> +      <column name="options" key="max_tunid">
>> +        The maximum supported tunnel ID. Depends on types of encapsulation
>> +        enabled in the cluster.
>> +      </column>
>> +
>>        <group title="Options for configuring interconnection route advertisement">
>>          <p>
>>            These options control how routes are advertised between OVN
>> diff --git a/tests/ovn-macros.at b/tests/ovn-macros.at
>> index c639c0ceb..a6719be83 100644
>> --- a/tests/ovn-macros.at
>> +++ b/tests/ovn-macros.at
>> @@ -215,7 +215,7 @@ net_attach () {
>>
>>  # ovn_az_attach AZ NETWORK BRIDGE IP [MASKLEN]
>>  ovn_az_attach() {
>> -    local az=$1 net=$2 bridge=$3 ip=$4 masklen=${5-24}
>> +    local az=$1 net=$2 bridge=$3 ip=$4 masklen=${5-24} encap=${6-geneve,vxlan}
>>      net_attach $net $bridge || return 1
>>
>>      mac=`ovs-vsctl get Interface $bridge mac_in_use | sed s/\"//g`
>> @@ -232,7 +232,7 @@ ovn_az_attach() {
>>      ovs-vsctl \
>>          -- set Open_vSwitch . external-ids:system-id=$sandbox \
>>          -- set Open_vSwitch . external-ids:ovn-remote=$ovn_remote \
>> -        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve,vxlan \
>> +        -- set Open_vSwitch . external-ids:ovn-encap-type=$encap \
>>          -- set Open_vSwitch . external-ids:ovn-encap-ip=$ip \
>>          -- --may-exist add-br br-int \
>>          -- set bridge br-int fail-mode=secure other-config:disable-in-band=true \
>> diff --git a/tests/ovn.at b/tests/ovn.at
>> index 8aabdf307..388236b51 100644
>> --- a/tests/ovn.at
>> +++ b/tests/ovn.at
>> @@ -17753,612 +17753,583 @@ AT_CHECK([ovn-nbctl -u $sockfile show])
>>  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
>> -    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
>> -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
>> -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 lrp-add router router-to-ls2 00:00:01:01:02:05 192.168.2.3/24
>> -ovn-nbctl lrp-add router router-to-underlay 00:00:01:01:02:07 172.31.0.1/24
>> -
>> -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" "$@"
>> -}
>> -
>> -# 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`
>> -
>> -# 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
>> -
>> -# 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
>> -
>> -OVS_WAIT_UNTIL([test x`ovn-sbctl --bare --columns chassis find port_binding  logical_port=cr-router-to-underlay | wc -l` = x1])
>> -
>> -test_arp vif-north f0f000000011 $sip $tip 000001010207
>> -
>> -# Confirm that vif-north gets a single ARP reply
>> -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])
>> -
>> -# Confirm that other OVN chassis did not generate ARP reply.
>> -$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/br-phys_n1-tx.pcap > hv1/br-phys_n1-tx.packets
>> -$PYTHON "$top_srcdir/utilities/ovs-pcap.in" 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
>> -
>> -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
>> -    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
>> -}
>> +m4_define([DVR_N_S_ARP_HANDLING],
>> +  [AT_SETUP([ovn -- 2 HVs, 2 lports/HV, localnet ports, DVR N-S ARP handling, encap $1])
>> +   set -x
>> +   encap=$1
>> +   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
>> +       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
>> -}
>> +   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 24 $encap
>> +
>> +       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
>> +   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
>> +   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 24 $encap
>> +
>> +   # 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 24 $encap
>> +
>> +   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 lrp-add router router-to-ls2 00:00:01:01:02:05 192.168.2.3/24
>> +   ovn-nbctl lrp-add router router-to-underlay 00:00:01:01:02:07 172.31.0.1/24
>> +
>> +   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
>> +
>> +   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
>> +   }
>>
>> -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
>> +   # 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
>> +   }
>>
>> -    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
>> +   sip=`printf "%02x%02x%02x%02x" 172 31 0 10`
>> +   tip=`printf "%02x%02x%02x%02x" 172 31 0 1`
>>
>> -    lsp_name=lp$i$i
>> -    ls_name=$(lsp_to_ls $lsp_name)
>> +   # 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
>>
>> -    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
>> +   # Dump a bunch of info helpful for debugging if there's a failure.
>>
>> -    OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up $lsp_name` = xup])
>> +   echo "------ OVN dump ------"
>> +   ovn-nbctl show
>> +   ovn-sbctl show
>> +   ovn-sbctl list port_binding
>> +   ovn-sbctl list mac_binding
>>
>> -done
>> +   echo "------ hv1 dump ------"
>> +   as hv1 ovs-vsctl show
>> +   as hv1 ovs-vsctl list Open_Vswitch
>>
>> -ovn-nbctl ls-add ls-underlay
>> -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
>> +   echo "------ hv2 dump ------"
>> +   as hv2 ovs-vsctl show
>> +   as hv2 ovs-vsctl list Open_Vswitch
>>
>> -ovn-nbctl ls-add ls-north
>> -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
>> +   echo "------ hv3 dump ------"
>> +   as hv3 ovs-vsctl show
>> +   as hv3 ovs-vsctl list Open_Vswitch
>>
>> -# 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
>> +   echo "------ hv4 dump ------"
>> +   as hv4 ovs-vsctl show
>> +   as hv4 ovs-vsctl list Open_Vswitch
>>
>> -# 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
>> +   OVS_WAIT_UNTIL([test x`ovn-sbctl --bare --columns chassis find port_binding  logical_port=cr-router-to-underlay | wc -l` = x1])
>>
>> -# 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
>> +   test_arp vif-north f0f000000011 $sip $tip 000001010207
>>
>> -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
>> +   # Confirm that vif-north gets a single ARP reply
>> +   OVN_CHECK_PACKETS_REMOVE_BROADCAST([hv4/vif-north-tx.pcap], [vif-north.expected])
>>
>> -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 lrp-add router router-to-ls2 00:00:01:01:02:05 192.168.2.3/24
>> -ovn-nbctl lrp-add router router-to-underlay 00:00:01:01:02:07 172.31.0.1/24
>> +   # Confirm that only redirect chassis allowed arp resolution.
>> +   OVN_CHECK_PACKETS_REMOVE_BROADCAST([hv3/br-phys_n1-tx.pcap], [vif-north_vid.expected])
>>
>> -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
>> +   # Confirm that other OVN chassis did not generate ARP reply.
>> +   $PYTHON "$ovs_srcdir//utilities/ovs-pcap.in" hv1/br-phys_n1-tx.pcap > hv1/br-phys_n1-tx.packets
>> +   $PYTHON "$ovs_srcdir//utilities/ovs-pcap.in" hv2/br-phys_n1-tx.pcap > hv2/br-phys_n1-tx.packets
>>
>> -ovn-nbctl lrp-set-gateway-chassis router-to-underlay hv3
>> -ovn-nbctl lrp-set-redirect-type router-to-underlay bridged
>> +   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
>> +]])
>>
>> -ovn-nbctl --wait=sb sync
>> +   # validate max_tunid reflects the type of encapsulation used
>> +   max_tunid=`ovn-nbctl get NB_Global . options:max_tunid | sed s/":"//g | sed s/\"//g`
>> +   echo $max_tunid
>> +   if [[ $encap = vxlan ]]; then
>> +       max_tunid_expected=4095
>> +   else
>> +       max_tunid_expected=16711680
>> +   fi
>> +   AT_CHECK([test $max_tunid -eq $max_tunid_expected])
>> +
>> +   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])
>> +
>> +DVR_N_S_ARP_HANDLING([geneve])
>> +DVR_N_S_ARP_HANDLING([vxlan])
>> +
>> +m4_define([DVR_N_S_PING],
>> +  [AT_SETUP([ovn -- 2 HVs, 2 lports/HV, localnet ports, DVR N-S Ping, encap $1])
>> +   AT_KEYWORDS([$1])
>> +   encap=$1
>> +   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
>> +       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
>> +   }
>>
>> -OVN_POPULATE_ARP
>> +   ip_to_hex() {
>> +          printf "%02x%02x%02x%02x" "$@"
>> +   }
>>
>> -# 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
>> -}
>> +   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 24 $encap
>> +
>> +       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
>> +   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
>> +   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 24 $encap
>> +
>> +   # 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 24 $encap
>> +
>> +   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 lrp-add router router-to-ls2 00:00:01:01:02:05 192.168.2.3/24
>> +   ovn-nbctl lrp-add router router-to-underlay 00:00:01:01:02:07 172.31.0.1/24
>> +
>> +   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 lrp-set-redirect-type router-to-underlay bridged
>> +
>> +   ovn-nbctl --wait=sb sync
>> +
>> +
>> +   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
>> -}
>> +   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
>> -}
>> +   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_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_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`
>> -}
>> +   vif_to_lrp () {
>> +       echo router-to-`vif_to_ls ${1}`
>> +   }
>>
>> -ip_to_hex() {
>> -       printf "%02x%02x%02x%02x" "$@"
>> -}
>> +   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 f0000000001100000101020308004500001c000000003f110100${src_ip}${dst_ip}0035111100080000 >> $outport.expected
>> -                fi
>> -                if test $outport = vif-north; then
>> -                    echo f0f00000001100000101020708004500001c000000003e110200${src_ip}${dst_ip}0035111100080000 >> $outport.expected
>> -                fi
>> -            fi >> $outport.expected
>> -        done
>> -}
>> +   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 f0000000001100000101020308004500001c000000003f110100${src_ip}${dst_ip}0035111100080000 >> $outport.expected
>> +                   fi
>> +                   if test $outport = vif-north; then
>> +                       echo f0f00000001100000101020708004500001c000000003e110200${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.
>> +   # 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 "------ 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 "------ 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 "------ 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 "------ 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 "------ hv4 dump ------"
>> +   as hv4 ovs-vsctl show
>> +   as hv4 ovs-vsctl list Open_Vswitch
>>
>> -echo "Send traffic North to South"
>> +   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
>> +   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
>>
>> -# Confirm that North to south traffic works fine.
>> -OVN_CHECK_PACKETS([hv1/vif11-tx.pcap], [vif11.expected])
>> +   # Confirm that North to south traffic works fine.
>> +   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
>> +   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
>>
>> -# Confirm that South to North traffic works fine.
>> -OVN_CHECK_PACKETS_REMOVE_BROADCAST([hv4/vif-north-tx.pcap], [vif-north.expected])
>> +   # 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], [[0
>> +   # 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], [[0
>>  ]])
>>
>> -# Confirm that packet went out via localnet port
>> -AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep table=65 | grep priority=150 | grep src=00:00:01:01:02:07 | grep n_packets=1 | wc -l], [0], [[1
>> +   # Confirm that packet went out via localnet port
>> +   AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep table=65 | grep priority=150 | grep src=00:00:01:01:02:07 | grep n_packets=1 | wc -l], [0], [[1
>>  ]])
>>
>> -echo "----------- Post Traffic hv1 dump -----------"
>> -as hv1 ovs-ofctl dump-flows br-int
>> -as hv1 ovs-ofctl show br-phys
>> -as hv1 ovs-appctl fdb/show br-phys
>> +   echo "----------- Post Traffic hv1 dump -----------"
>> +   as hv1 ovs-ofctl dump-flows br-int
>> +   as hv1 ovs-ofctl show br-phys
>> +   as hv1 ovs-appctl fdb/show br-phys
>>
>> -echo "----------- Post Traffic hv2 dump -----------"
>> -as hv2 ovs-ofctl dump-flows br-int
>> -as hv2 ovs-ofctl show br-phys
>> -as hv2 ovs-appctl fdb/show br-phys
>> +   echo "----------- Post Traffic hv2 dump -----------"
>> +   as hv2 ovs-ofctl dump-flows br-int
>> +   as hv2 ovs-ofctl show br-phys
>> +   as hv2 ovs-appctl fdb/show br-phys
>>
>> -echo "----------- Post Traffic hv3 dump -----------"
>> -as hv3 ovs-ofctl dump-flows br-int
>> -as hv3 ovs-ofctl show br-phys
>> -as hv3 ovs-appctl fdb/show br-phys
>> +   echo "----------- Post Traffic hv3 dump -----------"
>> +   as hv3 ovs-ofctl dump-flows br-int
>> +   as hv3 ovs-ofctl show br-phys
>> +   as hv3 ovs-appctl fdb/show br-phys
>>
>> -echo "----------- Post Traffic hv4 dump -----------"
>> -as hv4 ovs-ofctl dump-flows br-int
>> -as hv4 ovs-ofctl show br-phys
>> -as hv4 ovs-appctl fdb/show br-phys
>> +   echo "----------- Post Traffic hv4 dump -----------"
>> +   as hv4 ovs-ofctl dump-flows br-int
>> +   as hv4 ovs-ofctl show br-phys
>> +   as hv4 ovs-appctl fdb/show br-phys
>>
>> -OVN_CLEANUP([hv1],[hv2],[hv3],[hv4])
>> +   OVN_CLEANUP([hv1],[hv2],[hv3],[hv4])
>>
>> -AT_CLEANUP
>> +   AT_CLEANUP])
>> +
>> +DVR_N_S_PING([geneve])
>> +DVR_N_S_PING([vxlan])
>>
>>  AT_SETUP([ovn -- ARP lookup before learning])
>>  AT_KEYWORDS([virtual ports])
>> --
>> 2.26.2
>>
>> _______________________________________________
>> dev mailing list
>> dev at openvswitch.org
>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>>



More information about the dev mailing list