[ovs-dev] [PATCH v4] OVN localport type support

Daniel Alvarez Sanchez dalvarez at redhat.com
Fri May 26 12:10:55 UTC 2017


Hi Ben,

Thanks for proposing this optimization.
I've tried it and it works. These flows are inserted in table 32 when I
have a logical switch with two logical ports and one localport:

 cookie=0x0, duration=528.253s, table=32, n_packets=416, n_bytes=17584,
idle_age=1, priority=150,reg14=0x3,metadata=0x9 actions=resubmit(,33)

Also, if I try to ping a port in a different chassis from a localport, the
ARP request gets dropped in table 34:

 cookie=0x0, duration=568.319s, table=34, n_packets=448, n_bytes=18816,
idle_age=1, priority=100,reg10=0/0x1,reg14=0x3,reg15=0x3,metadata=0x9
actions=drop

If I insert an static entry in the ARP table for that remote port, then the
packet gets forwarded to table 33 but dropped there due to no hits.

I just submitted a version 5 of the patch including the links to OpenStack
documentation (the patch got already merged) and a minor indentation issue.

Thanks once again!
Daniel

On Fri, May 26, 2017 at 6:46 AM, Ben Pfaff <blp at ovn.org> wrote:

> On Tue, May 23, 2017 at 03:13:08PM +0200, Daniel Alvarez Sanchez wrote:
> > On Tue, May 23, 2017 at 10:01 AM, Miguel Angel Ajo Pelayo <
> > majopela at redhat.com> wrote:
> >
> > > If we forsee use cases with several local ports by logical
> switch/chassis
> > > could one option be to allocate a bit in REG10 to mark local ports,
> > > and then have a single rule that matches reg10 to drop
> output/forwarding
> > > of packets?
> > >
> > > I like the idea... let's see what others say about this, I don't know
> how
> > strict we want to be consuming
> > bits from registers.
> > Thanks Miguel for the suggestion :)
>
> I don't think we need a bit from a register here.  Here's my suggested
> incremental followed by a full patch.  It passes the test, at least.
> Will you take a look?
>
> diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c
> index c98b3053130c..2172dd849893 100644
> --- a/ovn/controller/physical.c
> +++ b/ovn/controller/physical.c
> @@ -293,8 +293,7 @@ consider_port_binding(enum mf_field_id mff_ovn_geneve,
>                        const struct sbrec_port_binding *binding,
>                        const struct sbrec_chassis *chassis,
>                        struct ofpbuf *ofpacts_p,
> -                      struct hmap *flow_table,
> -                      const struct sset *local_lports)
> +                      struct hmap *flow_table)
>  {
>      uint32_t dp_key = binding->datapath->tunnel_key;
>      uint32_t port_key = binding->tunnel_key;
> @@ -602,32 +601,6 @@ consider_port_binding(enum mf_field_id mff_ovn_geneve,
>      } else {
>          /* Remote port connected by tunnel */
>
> -        /* Table 32, priority 150.
> -         * =======================
> -         *
> -         * Drop traffic originated from a localport to a remote
> destination.
> -         */
> -        const char *localport;
> -        SSET_FOR_EACH (localport, local_lports) {
> -            /* Iterate over all local logical ports and insert a drop
> -             * rule with higher priority for every localport in this
> -             * datapath. */
> -            const struct sbrec_port_binding *pb = lport_lookup_by_name(
> -                lports, localport);
> -            if (pb && pb->datapath->tunnel_key == dp_key &&
> -                !strcmp(pb->type, "localport")) {
> -                match_init_catchall(&match);
> -                ofpbuf_clear(ofpacts_p);
> -                /* Match localport logical in_port. */
> -                match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0,
> -                              pb->tunnel_key);
> -                /* Match MFF_LOG_DATAPATH, MFF_LOG_OUTPORT. */
> -                match_set_metadata(&match, htonll(dp_key));
> -                match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0,
> port_key);
> -                ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, 0,
> -                                &match, ofpacts_p);
> -            }
> -        }
>          /* Table 32, priority 100.
>           * =======================
>           *
> @@ -919,7 +892,7 @@ physical_run(struct controller_ctx *ctx, enum
> mf_field_id mff_ovn_geneve,
>      SBREC_PORT_BINDING_FOR_EACH (binding, ctx->ovnsb_idl) {
>          consider_port_binding(mff_ovn_geneve, ct_zones, lports,
>                                local_datapaths, binding, chassis,
> -                              &ofpacts, flow_table, local_lports);
> +                              &ofpacts, flow_table);
>      }
>
>      /* Handle output to multicast groups, in tables 32 and 33. */
> @@ -1016,15 +989,40 @@ physical_run(struct controller_ctx *ctx, enum
> mf_field_id mff_ovn_geneve,
>       */
>      struct match match;
>      match_init_catchall(&match);
> -    ofpbuf_clear(&ofpacts);
>      match_set_reg_masked(&match, MFF_LOG_FLAGS - MFF_REG0,
>                           MLF_RCV_FROM_VXLAN, MLF_RCV_FROM_VXLAN);
>
>      /* Resubmit to table 33. */
> +    ofpbuf_clear(&ofpacts);
>      put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
>      ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, 0,
>                      &match, &ofpacts);
>
> +    /* Table 32, priority 150.
> +     * =======================
> +     *
> +     * Handles packets received from ports of type "localport".  These
> ports
> +     * are present on every hypervisor.  Traffic that originates at one
> should
> +     * never go over a tunnel to a remote hypervisor, so resubmit them to
> table
> +     * 33 for local delivery. */
> +    match_init_catchall(&match);
> +    ofpbuf_clear(&ofpacts);
> +    put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
> +    const char *localport;
> +    SSET_FOR_EACH (localport, local_lports) {
> +        /* Iterate over all local logical ports and insert a drop
> +         * rule with higher priority for every localport in this
> +         * datapath. */
> +        const struct sbrec_port_binding *pb = lport_lookup_by_name(
> +            lports, localport);
> +        if (pb && !strcmp(pb->type, "localport")) {
> +            match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0,
> pb->tunnel_key);
> +            match_set_metadata(&match, htonll(pb->datapath->tunnel_key));
> +            ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, 0,
> +                            &match, &ofpacts);
> +        }
> +    }
> +
>      /* Table 32, Priority 0.
>       * =======================
>       *
> diff --git a/ovn/ovn-architecture.7.xml b/ovn/ovn-architecture.7.xml
> index 2d2d0cc88435..3983a93ee114 100644
> --- a/ovn/ovn-architecture.7.xml
> +++ b/ovn/ovn-architecture.7.xml
> @@ -1000,23 +1000,38 @@
>          hypervisor.  Each flow's actions implement sending a packet to
> the port
>          it matches.  For unicast logical output ports on remote
> hypervisors,
>          the actions set the tunnel key to the correct value, then send the
> -        packet on the tunnel port to the correct hypervisor (unless the
> packet
> -        comes from a localport, in which case it will be dropped). (When
> the
> -        remote hypervisor receives the packet, table 0 there will
> recognize it
> -        as a tunneled packet and pass it along to table 33.)  For
> multicast
> -        logical output ports, the actions send one copy of the packet to
> each
> -        remote hypervisor, in the same way as for unicast destinations.
> If a
> +        packet on the tunnel port to the correct hypervisor.  (When the
> remote
> +        hypervisor receives the packet, table 0 there will recognize it
> as a
> +        tunneled packet and pass it along to table 33.)  For multicast
> logical
> +        output ports, the actions send one copy of the packet to each
> remote
> +        hypervisor, in the same way as for unicast destinations.  If a
>          multicast group includes a logical port or ports on the local
>          hypervisor, then its actions also resubmit to table 33.  Table 32
> also
> -        includes a fallback flow that resubmits to table 33 if there is no
> -        other match.  Table 32 also contains 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 16 to determine the output port.
> +        includes:
>        </p>
>
> +      <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 16 to
> +          determine the output port.
> +        </li>
> +        <li>
> +          A higher-priority rule to match packets received from ports of
> type
> +          <code>localport</code>, based on the logical input port, and
> resubmit
> +          these packets to table 33 for local delivery.  Ports of type
> +          <code>localport</code> exist on every hypervisor and by
> definition
> +          their traffic should never go out through a tunnel.
> +        </li>
> +        <li>
> +          A fallback flow that resubmits to table 33 if there is no other
> +          match.
> +        </li>
> +      </ul>
> +
>        <p>
>          Flows in table 33 resemble those in table 32 but for logical
> ports that
>          reside locally rather than remotely.  For unicast logical output
> ports
>
> --8<--------------------------cut here-------------------------->8--
>
> From: Daniel Alvarez <dalvarez at redhat.com>
> Date: Wed, 10 May 2017 08:35:45 +0000
> Subject: [PATCH] OVN localport type support
>
> This patch introduces a new type of OVN ports called "localport".
> These ports will be present in every hypervisor and may have the
> same IP/MAC addresses. They are not bound to any chassis and traffic
> to these ports will never go through a tunnel.
>
> Its main use case is the OpenStack metadata API support which relies
> on a local agent running on every hypervisor and serving metadata to
> VM's locally. This service is described in detail at [0].
>
> An example to illustrate the purpose of this patch:
>
> - One logical switch sw0 with 2 ports (p1, p2) and 1 localport (lp)
> - Two hypervisors: HV1 and HV2
> - p1 in HV1 (OVS port with external-id:iface-id="p1")
> - p2 in HV2 (OVS port with external-id:iface-id="p2")
> - lp in both hypevisors (OVS port with external-id:iface-id="lp")
> - p1 should be able to reach p2 and viceversa
> - lp on HV1 should be able to reach p1 but not p2
> - lp on HV2 should be able to reach p2 but not p1
>
> Explicit drop rules are inserted in table 32 with priority 150
> in order to prevent traffic originated at a localport to go over
> a tunnel.
>
> [0] https://review.openstack.org/#/c/452811/
>
> Signed-off-by: Daniel Alvarez <dalvarez at redhat.com>
> Signed-off-by: Ben Pfaff <blp at ovn.org>
> ---
>  ovn/controller/binding.c        |   3 +-
>  ovn/controller/ovn-controller.c |   2 +-
>  ovn/controller/physical.c       |  30 +++++++++-
>  ovn/controller/physical.h       |   4 +-
>  ovn/northd/ovn-northd.8.xml     |   8 +--
>  ovn/northd/ovn-northd.c         |   6 +-
>  ovn/ovn-architecture.7.xml      |  44 ++++++++++++---
>  ovn/ovn-nb.xml                  |   9 +++
>  ovn/ovn-sb.xml                  |  14 +++++
>  tests/ovn.at                    | 122 ++++++++++++++++++++++++++++++
> ++++++++++
>  10 files changed, 224 insertions(+), 18 deletions(-)
>
> diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c
> index 95e9deb322b4..83a75434ec79 100644
> --- a/ovn/controller/binding.c
> +++ b/ovn/controller/binding.c
> @@ -380,7 +380,8 @@ consider_local_datapath(struct controller_ctx *ctx,
>          if (iface_rec && qos_map && ctx->ovs_idl_txn) {
>              get_qos_params(binding_rec, qos_map);
>          }
> -        our_chassis = true;
> +       if(strcmp(binding_rec->type, "localport"))
> +            our_chassis = true;
>      } else if (!strcmp(binding_rec->type, "l2gateway")) {
>          const char *chassis_id = smap_get(&binding_rec->options,
>                                            "l2gateway-chassis");
> diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-
> controller.c
> index f22551d6dcf3..0f4dd35723e6 100644
> --- a/ovn/controller/ovn-controller.c
> +++ b/ovn/controller/ovn-controller.c
> @@ -655,7 +655,7 @@ main(int argc, char *argv[])
>
>                      physical_run(&ctx, mff_ovn_geneve,
>                                   br_int, chassis, &ct_zones, &lports,
> -                                 &flow_table, &local_datapaths);
> +                                 &flow_table, &local_datapaths,
> &local_lports);
>
>                      ofctrl_put(&flow_table, &pending_ct_zones,
>                                 get_nb_cfg(ctx.ovnsb_idl));
> diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c
> index 457fc45414bd..2172dd849893 100644
> --- a/ovn/controller/physical.c
> +++ b/ovn/controller/physical.c
> @@ -769,7 +769,8 @@ physical_run(struct controller_ctx *ctx, enum
> mf_field_id mff_ovn_geneve,
>               const struct ovsrec_bridge *br_int,
>               const struct sbrec_chassis *chassis,
>               const struct simap *ct_zones, struct lport_index *lports,
> -             struct hmap *flow_table, struct hmap *local_datapaths)
> +             struct hmap *flow_table, struct hmap *local_datapaths,
> +             const struct sset *local_lports)
>  {
>
>      /* This bool tracks physical mapping changes. */
> @@ -988,15 +989,40 @@ physical_run(struct controller_ctx *ctx, enum
> mf_field_id mff_ovn_geneve,
>       */
>      struct match match;
>      match_init_catchall(&match);
> -    ofpbuf_clear(&ofpacts);
>      match_set_reg_masked(&match, MFF_LOG_FLAGS - MFF_REG0,
>                           MLF_RCV_FROM_VXLAN, MLF_RCV_FROM_VXLAN);
>
>      /* Resubmit to table 33. */
> +    ofpbuf_clear(&ofpacts);
>      put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
>      ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, 0,
>                      &match, &ofpacts);
>
> +    /* Table 32, priority 150.
> +     * =======================
> +     *
> +     * Handles packets received from ports of type "localport".  These
> ports
> +     * are present on every hypervisor.  Traffic that originates at one
> should
> +     * never go over a tunnel to a remote hypervisor, so resubmit them to
> table
> +     * 33 for local delivery. */
> +    match_init_catchall(&match);
> +    ofpbuf_clear(&ofpacts);
> +    put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
> +    const char *localport;
> +    SSET_FOR_EACH (localport, local_lports) {
> +        /* Iterate over all local logical ports and insert a drop
> +         * rule with higher priority for every localport in this
> +         * datapath. */
> +        const struct sbrec_port_binding *pb = lport_lookup_by_name(
> +            lports, localport);
> +        if (pb && !strcmp(pb->type, "localport")) {
> +            match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0,
> pb->tunnel_key);
> +            match_set_metadata(&match, htonll(pb->datapath->tunnel_key));
> +            ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, 0,
> +                            &match, &ofpacts);
> +        }
> +    }
> +
>      /* Table 32, Priority 0.
>       * =======================
>       *
> diff --git a/ovn/controller/physical.h b/ovn/controller/physical.h
> index e2debed89362..66aa80e2d998 100644
> --- a/ovn/controller/physical.h
> +++ b/ovn/controller/physical.h
> @@ -32,6 +32,7 @@ struct hmap;
>  struct ovsdb_idl;
>  struct ovsrec_bridge;
>  struct simap;
> +struct sset;
>
>  /* OVN Geneve option information.
>   *
> @@ -45,6 +46,7 @@ void physical_run(struct controller_ctx *, enum
> mf_field_id mff_ovn_geneve,
>                    const struct ovsrec_bridge *br_int,
>                    const struct sbrec_chassis *chassis,
>                    const struct simap *ct_zones, struct lport_index *,
> -                  struct hmap *flow_table, struct hmap *local_datapaths);
> +                  struct hmap *flow_table, struct hmap *local_datapaths,
> +                  const struct sset *local_lports);
>
>  #endif /* ovn/physical.h */
> diff --git a/ovn/northd/ovn-northd.8.xml b/ovn/northd/ovn-northd.8.xml
> index c0b4c5eb0ead..7ff524508c73 100644
> --- a/ovn/northd/ovn-northd.8.xml
> +++ b/ovn/northd/ovn-northd.8.xml
> @@ -492,8 +492,8 @@ output;
>          </pre>
>
>          <p>
> -          These flows are omitted for logical ports (other than router
> ports)
> -          that are down.
> +          These flows are omitted for logical ports (other than router
> ports or
> +          <code>localport</code> ports) that are down.
>          </p>
>        </li>
>
> @@ -519,8 +519,8 @@ nd_na {
>          </pre>
>
>          <p>
> -          These flows are omitted for logical ports (other than router
> ports)
> -          that are down.
> +          These flows are omitted for logical ports (other than router
> ports or
> +          <code>localport</code> ports) that are down.
>          </p>
>        </li>
>
> diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
> index 83db75338557..a3bd859afe58 100644
> --- a/ovn/northd/ovn-northd.c
> +++ b/ovn/northd/ovn-northd.c
> @@ -3305,9 +3305,11 @@ build_lswitch_flows(struct hmap *datapaths, struct
> hmap *ports,
>          /*
>           * Add ARP/ND reply flows if either the
>           *  - port is up or
> -         *  - port type is router
> +         *  - port type is router or
> +         *  - port type is localport
>           */
> -        if (!lsp_is_up(op->nbsp) && strcmp(op->nbsp->type, "router")) {
> +        if (!lsp_is_up(op->nbsp) && strcmp(op->nbsp->type, "router") &&
> +            strcmp(op->nbsp->type, "localport")) {
>              continue;
>          }
>
> diff --git a/ovn/ovn-architecture.7.xml b/ovn/ovn-architecture.7.xml
> index d8114f1f9dee..3983a93ee114 100644
> --- a/ovn/ovn-architecture.7.xml
> +++ b/ovn/ovn-architecture.7.xml
> @@ -409,6 +409,20 @@
>            logical patch ports at each such point of connectivity, one on
>            each side.
>          </li>
> +        <li>
> +          <dfn>Localport ports</dfn> represent the points of local
> +          connectivity between logical switches and VIFs. These ports are
> +          present in every chassis (not bound to any particular one) and
> +          traffic from them will never go through a tunnel. A
> +          <code>localport</code> is expected to only generate traffic
> destined
> +          for a local destination, typically in response to a request it
> +          received.
> +          One use case is how OpenStack Neutron uses a
> <code>localport</code>
> +          port for serving metadata to VM's residing on every hypervisor.
> A
> +          metadata proxy process is attached to this port on every host
> and all
> +          VM's within the same network will reach it at the same IP/MAC
> address
> +          without any traffic being sent over a tunnel.
> +        </li>
>        </ul>
>      </li>
>    </ul>
> @@ -993,15 +1007,31 @@
>          hypervisor, in the same way as for unicast destinations.  If a
>          multicast group includes a logical port or ports on the local
>          hypervisor, then its actions also resubmit to table 33.  Table 32
> also
> -        includes a fallback flow that resubmits to table 33 if there is no
> -        other match.  Table 32 also contains 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 16 to determine the output port.
> +        includes:
>        </p>
>
> +      <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 16 to
> +          determine the output port.
> +        </li>
> +        <li>
> +          A higher-priority rule to match packets received from ports of
> type
> +          <code>localport</code>, based on the logical input port, and
> resubmit
> +          these packets to table 33 for local delivery.  Ports of type
> +          <code>localport</code> exist on every hypervisor and by
> definition
> +          their traffic should never go out through a tunnel.
> +        </li>
> +        <li>
> +          A fallback flow that resubmits to table 33 if there is no other
> +          match.
> +        </li>
> +      </ul>
> +
>        <p>
>          Flows in table 33 resemble those in table 32 but for logical
> ports that
>          reside locally rather than remotely.  For unicast logical output
> ports
> diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
> index f5be9e24b7bc..eb348fe59c4b 100644
> --- a/ovn/ovn-nb.xml
> +++ b/ovn/ovn-nb.xml
> @@ -283,6 +283,15 @@
>              to model direct connectivity to an existing network.
>            </dd>
>
> +          <dt><code>localport</code></dt>
> +          <dd>
> +            A connection to a local VIF. Traffic that arrives on a
> +            <code>localport</code> is never forwarded over a tunnel to
> another
> +            chassis. These ports are present on every chassis and have
> the same
> +            address in all of them. This is used to model connectivity to
> local
> +            services that run on every hypervisor.
> +          </dd>
> +
>            <dt><code>l2gateway</code></dt>
>            <dd>
>              A connection to a physical network.
> diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml
> index 387adb8069d3..f3c321222c0d 100644
> --- a/ovn/ovn-sb.xml
> +++ b/ovn/ovn-sb.xml
> @@ -1802,6 +1802,11 @@ tcp.flags = RST;
>              connectivity to the corresponding physical network.
>            </dd>
>
> +          <dt>localport</dt>
> +          <dd>
> +            Always empty.  A localport port is present on every chassis.
> +          </dd>
> +
>            <dt>l3gateway</dt>
>            <dd>
>              The physical location of the L3 gateway.  To successfully
> identify a
> @@ -1882,6 +1887,15 @@ tcp.flags = RST;
>              to model direct connectivity to an existing network.
>            </dd>
>
> +          <dt><code>localport</code></dt>
> +          <dd>
> +            A connection to a local VIF. Traffic that arrives on a
> +            <code>localport</code> is never forwarded over a tunnel to
> another
> +            chassis. These ports are present on every chassis and have
> the same
> +            address in all of them. This is used to model connectivity to
> local
> +            services that run on every hypervisor.
> +          </dd>
> +
>            <dt><code>l2gateway</code></dt>
>            <dd>
>              An L2 connection to a physical network.  The chassis this
> diff --git a/tests/ovn.at b/tests/ovn.at
> index b30315e57034..8abf45ae7701 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -7374,3 +7374,125 @@ OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
>  OVN_CLEANUP([hv1],[hv2])
>
>  AT_CLEANUP
> +
> +AT_SETUP([ovn -- 2 HVs, 1 lport/HV, localport ports])
> +AT_SKIP_IF([test $HAVE_PYTHON = no])
> +ovn_start
> +
> +ovn-nbctl ls-add ls1
> +
> +# Add localport to the switch
> +ovn-nbctl lsp-add ls1 lp01
> +ovn-nbctl lsp-set-addresses lp01 f0:00:00:00:00:01
> +ovn-nbctl lsp-set-type lp01 localport
> +
> +net_add n1
> +
> +for i in 1 2; do
> +    sim_add hv$i
> +    as hv$i
> +    ovs-vsctl add-br br-phys
> +    ovn_attach n1 br-phys 192.168.0.$i
> +    ovs-vsctl add-port br-int vif01 -- \
> +        set Interface vif01 external-ids:iface-id=lp01 \
> +                              options:tx_pcap=hv${i}/vif01-tx.pcap \
> +                              options:rxq_pcap=hv${i}/vif01-rx.pcap \
> +                              ofport-request=${i}0
> +
> +    ovs-vsctl add-port br-int vif${i}1 -- \
> +        set Interface vif${i}1 external-ids:iface-id=lp${i}1 \
> +                              options:tx_pcap=hv${i}/vif${i}1-tx.pcap \
> +                              options:rxq_pcap=hv${i}/vif${i}1-rx.pcap \
> +                              ofport-request=${i}1
> +
> +    ovn-nbctl lsp-add ls1 lp${i}1
> +    ovn-nbctl lsp-set-addresses lp${i}1 f0:00:00:00:00:${i}1
> +    ovn-nbctl lsp-set-port-security lp${i}1 f0:00:00:00:00:${i}1
> +
> +        OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up lp${i}1` = xup])
> +done
> +
> +ovn-nbctl --wait=sb sync
> +ovn-sbctl dump-flows
> +
> +ovn_populate_arp
> +
> +# Given the name of a logical port, prints the name of the hypervisor
> +# on which it is located.
> +vif_to_hv() {
> +    echo hv${1%?}
> +}
> +#
> +# test_packet INPORT DST SRC ETHTYPE EOUT LOUT DEFHV
> +#
> +# This shell function causes a packet to be received on INPORT.  The
> packet's
> +# content has Ethernet destination DST and source SRC (each exactly 12 hex
> +# digits) and Ethernet type ETHTYPE (4 hex digits).  INPORT is specified
> as
> +# logical switch port numbers, e.g. 11 for vif11.
> +#
> +# EOUT is the end-to-end output port, that is, where the packet will end
> up
> +# after possibly bouncing through one or more localnet ports.  LOUT is the
> +# logical output port, which might be a localnet port, as seen by
> ovn-trace
> +# (which doesn't know what localnet ports are connected to and therefore
> can't
> +# figure out the end-to-end answer).
> +#
> +# DEFHV is the default hypervisor from where the packet is going to be
> sent
> +# if the source port is a localport.
> +for i in 1 2; do
> +    for j in 0 1; do
> +        : > $i$j.expected
> +    done
> +done
> +test_packet() {
> +    local inport=$1 dst=$2 src=$3 eth=$4 eout=$5 lout=$6 defhv=$7
> +    echo "$@"
> +
> +    # First try tracing the packet.
> +    uflow="inport==\"lp$inport\" && eth.dst==$dst && eth.src==$src &&
> eth.type==0x$eth"
> +    if test $lout != drop; then
> +        echo "output(\"$lout\");"
> +    fi > expout
> +    AT_CAPTURE_FILE([trace])
> +    AT_CHECK([ovn-trace --all ls1 "$uflow" | tee trace | sed '1,/Minimal
> trace/d'], [0], [expout])
> +
> +    # Then actually send a packet, for an end-to-end test.
> +    local packet=$(echo $dst$src | sed 's/://g')${eth}
> +    hv=`vif_to_hv $inport`
> +    # If hypervisor 0 (localport) use the defhv parameter
> +    if test $hv == hv0; then
> +        hv=$defhv
> +    fi
> +    vif=vif$inport
> +    as $hv ovs-appctl netdev-dummy/receive $vif $packet
> +    if test $eout != drop; then
> +        echo $packet >> ${eout#lp}.expected
> +    fi
> +}
> +
> +
> +# lp11 and lp21 are on different hypervisors
> +test_packet 11 f0:00:00:00:00:21 f0:00:00:00:00:11 1121 lp21 lp21
> +test_packet 21 f0:00:00:00:00:11 f0:00:00:00:00:21 2111 lp11 lp11
> +
> +# Both VIFs should be able to reach the localport on their own HV
> +test_packet 11 f0:00:00:00:00:01 f0:00:00:00:00:11 1101 lp01 lp01
> +test_packet 21 f0:00:00:00:00:01 f0:00:00:00:00:21 2101 lp01 lp01
> +
> +# Packet sent from localport on same hv should reach the vif
> +test_packet 01 f0:00:00:00:00:11 f0:00:00:00:00:01 0111 lp11 lp11 hv1
> +test_packet 01 f0:00:00:00:00:21 f0:00:00:00:00:01 0121 lp21 lp21 hv2
> +
> +# Packet sent from localport on different hv should be dropped
> +test_packet 01 f0:00:00:00:00:21 f0:00:00:00:00:01 0121 drop lp21 hv1
> +test_packet 01 f0:00:00:00:00:11 f0:00:00:00:00:01 0111 drop lp11 hv2
> +
> +# Now check the packets actually received against the ones expected.
> +for i in 1 2; do
> +    for j in 0 1; do
> +        OVN_CHECK_PACKETS([hv$i/vif$i$j-tx.pcap], [$i$j.expected])
> +    done
> +done
> +
> +OVN_CLEANUP([hv1],[hv2])
> +
> +AT_CLEANUP
> --
> 2.10.2
>
>


More information about the dev mailing list