[ovs-dev] [RFC] ovn: physical network integraiton (WIP)

Salvatore Orlando salv.orlando at gmail.com
Tue Jul 7 22:06:05 UTC 2015


Reading your post and the associated patch it seems that you're treating
the physical network as a logical port from a pipeline perspective but
exposing it as a logical switch attribute from a NB DB perspective. Is that
correct?

If my previous statement is correct, I wonder why not treat it always as a
logical port and then perhaps leverage OVN gateways? This might or might
not represent what a Neutron provider network is, but it surely represent a
viable implementation of its main use case: mapping a logical network to a
physical VLAN in the data centre, and keeping control of security policing
and IP addressing over logical ports created on such network.

>From what I gather this might simplify the broadcast issue you mentioned,
as you probably won't need anymore a specialised action.
We probably will still have the name overlap issue when doing neutron
integration, but this is probably an issue that can be worked around easily.

I think the solution you propose to define mappings for the physical
network, which is very similar to Neutron's reference control plane, is
viable too and can also work in the case where the physical network is
represented as a specialised output port. Have you considered this
approach?

I apologise if I did not comment inline, but your post was quite long and
it did not seem practical.

Salvatore


On 6 July 2015 at 19:45, Russell Bryant <rbryant at redhat.com> wrote:

> CC: Ben Pfaff <blp at nicira.com>
>
> ---
>  ovn/northd/ovn-northd.c | 42 ++++++++++++++++++++++++++++++++++++++++--
>  ovn/ovn-nb.ovsschema    |  6 ++++++
>  ovn/ovn-nb.xml          | 18 ++++++++++++++++++
>  ovn/ovn-nbctl.c         | 29 +++++++++++++++++++++++++----
>  ovn/ovn-sb.xml          |  2 ++
>  5 files changed, 91 insertions(+), 6 deletions(-)
>
> During the OVN meeting last week I mentioned that I would share what I had
> so
> far on this.  It's far from complete.  So far I was just looking at what
> was
> needed in the northbound schema and how that would map to the Pipeline in
> the
> southbound DB.
>
> There was a previous thread that discussed the Neutron API extension called
> "provider networks" that this is related to:
>
>   http://openvswitch.org/pipermail/dev/2015-June/056765.html
>
> My approach so far is focused on the common use case and isn't trying to
> support
> anything more.  It allows you to specify a physical network and optionally
> a
> VLAN ID on a logical switch.  If these are set, the intention is that the
> logical switch participates in existing L2 network instead of building an
> overlay.
>
> With this patch, I can run the following setup that creates 3 logical
> switches:
>
>  1) one "normal" logical switch with no physical network specified
>
>  2) one logical switch with a physical network and VLAN ID specified
>
>   + ovn-nbctl lswitch-add sw0
>   + ovn-nbctl lswitch-add sw1 physnet1 50
>   + ovn-nbctl lport-add sw0 sw0-port1
>   + ovn-nbctl lport-add sw0 sw0-port2
>   + ovn-nbctl lport-add sw1 sw1-port1
>   + ovn-nbctl lport-add sw1 sw1-port2
>   + ovn-nbctl lport-set-macs sw0-port1 00:00:00:00:00:01
>   + ovn-nbctl lport-set-macs sw0-port2 00:00:00:00:00:02
>   + ovn-nbctl lport-set-macs sw1-port1 00:00:00:00:00:03
>   + ovn-nbctl lport-set-macs sw1-port2 00:00:00:00:00:04
>   + ovn-nbctl lport-set-port-security sw0-port1 00:00:00:00:00:01
>   + ovn-nbctl lport-set-port-security sw0-port2 00:00:00:00:00:02
>   + ovn-nbctl lport-set-port-security sw1-port1 00:00:00:00:00:03
>   + ovn-nbctl lport-set-port-security sw1-port2 00:00:00:00:00:04
>   + ovs-vsctl add-port br-int lport1 -- set Interface lport1
> external_ids:iface-id=sw0-port1
>   + ovs-vsctl add-port br-int lport2 -- set Interface lport2
> external_ids:iface-id=sw0-port2
>   + ovs-vsctl add-port br-int lport3 -- set Interface lport3
> external_ids:iface-id=sw1-port1
>   + ovs-vsctl add-port br-int lport4 -- set Interface lport4
> external_ids:iface-id=sw1-port2
>
> and here is the resulting Pipeline:
>
>   $ ovn-pipeline.py
>
> +--------------------------------------+-----------------------------------------------------------------------------------------------+--------------------------------------+--------------------------------------------------------------+----------+----------+
>   |                _uuid                 |
>             actions                                            |
>  logical_datapath           |                            match
>                | priority | table_id |
>
> +--------------------------------------+-----------------------------------------------------------------------------------------------+--------------------------------------+--------------------------------------------------------------+----------+----------+
>   | c35ef6a4-aabe-4ae1-aa2a-d5de754ced86 | "drop;"
>                                                                |
> c409aec4-c61f-462e-b11f-ceb8530e4480 | "eth.src[40]"
>                         | 100      |    0     |
>   | 809b8436-5417-418f-9777-19d2617b6f83 | "drop;"
>                                                                |
> c409aec4-c61f-462e-b11f-ceb8530e4480 | vlan.present
>                          | 100      |    0     |
>   | 055291de-0d59-4e7d-b933-123b97d24eba | "next;"
>                                                                |
> c409aec4-c61f-462e-b11f-ceb8530e4480 | "inport == \"sw0-port1\" && eth.src
> == {00:00:00:00:00:01}"  | 50       |    0     |
>   | 61d85d82-3a0e-413d-afe0-ce5b45584a07 | "next;"
>                                                                |
> c409aec4-c61f-462e-b11f-ceb8530e4480 | "inport == \"sw0-port2\" && eth.src
> == {00:00:00:00:00:02}"  | 50       |    0     |
>   | 9b583a79-cecb-423c-a282-58033476bfa4 | "drop;"
>                                                                |
> c409aec4-c61f-462e-b11f-ceb8530e4480 | "1"
>                         | 0        |    0     |
>   | 4a96d92e-c257-4e20-8952-d8f270674f7c | "outport = \"sw0-port2\"; next;
> outport = \"sw0-port1\"; next;"                               |
> c409aec4-c61f-462e-b11f-ceb8530e4480 | "eth.dst[40]"
>                         | 100      |    1     |
>   | 1384f65b-3aa6-4f4c-9174-a7ad3682852c | "outport = \"sw0-port1\";
> next;"                                                              |
> c409aec4-c61f-462e-b11f-ceb8530e4480 | "eth.dst == 00:00:00:00:00:01"
>                          | 50       |    1     |
>   | 15e473fd-0fde-4935-a9ef-fa797db54223 | "outport = \"sw0-port2\";
> next;"                                                              |
> c409aec4-c61f-462e-b11f-ceb8530e4480 | "eth.dst == 00:00:00:00:00:02"
>                          | 50       |    1     |
>   | 82cd5499-e152-486c-819b-f73a39335265 | "next;"
>                                                                |
> c409aec4-c61f-462e-b11f-ceb8530e4480 | "1"
>                         | 0        |    2     |
>   | 994a3e0a-be21-42bd-9036-a22cbf6114ef | "output;"
>                                                                |
> c409aec4-c61f-462e-b11f-ceb8530e4480 | "eth.dst[40]"
>                         | 100      |    3     |
>   | d24319c7-f597-4f5d-b521-1964cea39804 | "output;"
>                                                                |
> c409aec4-c61f-462e-b11f-ceb8530e4480 | "outport == \"sw0-port1\" && eth.dst
> == {00:00:00:00:00:01}" | 50       |    3     |
>   | d26a34f8-55de-477b-ae73-1dfc595af77a | "output;"
>                                                                |
> c409aec4-c61f-462e-b11f-ceb8530e4480 | "outport == \"sw0-port2\" && eth.dst
> == {00:00:00:00:00:02}" | 50       |    3     |
>   | dba7561d-b81e-46a6-b824-b484ce69af2d | "drop;"
>                                                                |
> ffd51033-7206-4072-abf1-fefd4ae416a7 | "eth.src[40]"
>                         | 100      |    0     |
>   | 65bab5ea-cbf5-493c-8e98-f1c44647cb24 | "drop;"
>                                                                |
> ffd51033-7206-4072-abf1-fefd4ae416a7 | vlan.present
>                          | 100      |    0     |
>   | b0c5e1da-21d6-43a9-9e80-9ef60045e77e | "next;"
>                                                                |
> ffd51033-7206-4072-abf1-fefd4ae416a7 | "inport == \"sw1-port1\" && eth.src
> == {00:00:00:00:00:03}"  | 50       |    0     |
>   | 611e78f2-4044-487f-ab9d-34962ac90178 | "next;"
>                                                                |
> ffd51033-7206-4072-abf1-fefd4ae416a7 | "inport == \"sw1-port2\" && eth.src
> == {00:00:00:00:00:04}"  | 50       |    0     |
>   | a8f7ed4b-497b-4843-949b-4ce4ee6d796d | "drop;"
>                                                                |
> ffd51033-7206-4072-abf1-fefd4ae416a7 | "inport == \"sw1-port1\""
>                         | 40       |    0     |
>   | 1739a4f5-f8cf-4015-bf97-dba01858c3c5 | "drop;"
>                                                                |
> ffd51033-7206-4072-abf1-fefd4ae416a7 | "inport == \"sw1-port2\""
>                         | 40       |    0     |
>   | 0f644204-f00e-4ad3-96d5-2ca7bbb30198 | "next;"
>                                                                |
> ffd51033-7206-4072-abf1-fefd4ae416a7 | "1"
>                         | 0        |    0     |
>   | 31a90046-92c8-4f65-8172-040eba56ed30 | "outport = \"physnet1\"; next;
> outport = \"sw1-port2\"; next; outport = \"sw1-port1\"; next;" |
> ffd51033-7206-4072-abf1-fefd4ae416a7 | "eth.dst[40]"
>                         | 100      |    1     |
>   | c1ce1c42-5330-45d4-9563-9d7305d38cb3 | "outport = \"sw1-port1\";
> next;"                                                              |
> ffd51033-7206-4072-abf1-fefd4ae416a7 | "eth.dst == 00:00:00:00:00:03"
>                          | 50       |    1     |
>   | 65c77542-ad61-44ed-9c5d-6cd15f2ad4e6 | "outport = \"sw1-port2\";
> next;"                                                              |
> ffd51033-7206-4072-abf1-fefd4ae416a7 | "eth.dst == 00:00:00:00:00:04"
>                          | 50       |    1     |
>   | 8c4dbd70-6759-419f-a242-0e61508376b2 | "outport = \"physnet1\";
> next;"                                                               |
> ffd51033-7206-4072-abf1-fefd4ae416a7 | "1"
>                         | 0        |    1     |
>   | 928cb3d8-9fdf-4375-a525-e9199b2f8735 | "next;"
>                                                                |
> ffd51033-7206-4072-abf1-fefd4ae416a7 | "1"
>                         | 0        |    2     |
>   | 54102e76-07a6-48f1-b19e-bbae91897b0d | "output;"
>                                                                |
> ffd51033-7206-4072-abf1-fefd4ae416a7 | "eth.dst[40]"
>                         | 100      |    3     |
>   | 34b151db-a203-48a1-9cec-4417f409968c | "output;"
>                                                                |
> ffd51033-7206-4072-abf1-fefd4ae416a7 | "outport == \"physnet1\""
>                         | 50       |    3     |
>   | 5c0a4013-4207-4a37-85ee-e8b1dc8c2dfe | "output;"
>                                                                |
> ffd51033-7206-4072-abf1-fefd4ae416a7 | "outport == \"sw1-port1\" && eth.dst
> == {00:00:00:00:00:03}" | 50       |    3     |
>   | 7f0fac60-f6b2-4666-a6c9-269b6a74dba7 | "output;"
>                                                                |
> ffd51033-7206-4072-abf1-fefd4ae416a7 | "outport == \"sw1-port2\" && eth.dst
> == {00:00:00:00:00:04}" | 50       |    3     |
>
> +--------------------------------------+-----------------------------------------------------------------------------------------------+--------------------------------------+--------------------------------------------------------------+----------+----------+
>
> I still have a couple of issues with how this works.  First, I'm
> specifying the
> physical network name as an output port.  If a logical port had the same
> name,
> this would cause a problem, but perhaps that's a reasonable constraint if
> it's
> documented - "You can't name a logical port the same name as the logical
> switch
> physical_network".
>
> In the case of a logical switch with a "physical network" specified, I
> would
> expect the outport behavior for a logical port to:
>
>   - output the packet to the port if it's local
>
>   - if not local, output the packet to the port used to reach the physical
>     network (specified in the local ovn-controller configuration)
>


> The ovn-controller configuration would be a set of mappings between network
> names and the ovs bridge used to connect to that network.
>
>       $ ovs-vsctl set Open_vSwitch .
> external-ids:bridge_mappings=physnet1:br-eth1,physnet2:br-eth2
>
> The current Pipeline breaks down with how broadcast is handled right now.
> I
> don't have a way to say "send the packet to the physical network *and*
> every
> logical port that is local".  My only idea right now would be to define a
> new
> action called "broadcast" and let ovn-controller implement it however is
> appropriate for that logical switch.
>
> diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
> index c790a90..0d6a9ba 100644
> --- a/ovn/northd/ovn-northd.c
> +++ b/ovn/northd/ovn-northd.c
> @@ -241,6 +241,12 @@ lport_is_enabled(const struct nbrec_logical_port
> *lport)
>      return !lport->enabled || *lport->enabled;
>  }
>
> +static bool
> +lswitch_has_physical_network(const struct nbrec_logical_switch *lswitch)
> +{
> +    return lswitch->physical_network && *lswitch->physical_network;
> +}
> +
>  /* Updates the Pipeline table in the OVN_SB database, constructing its
> contents
>   * based on the OVN_NB database. */
>  static void
> @@ -276,8 +282,10 @@ build_pipeline(struct northd_context *ctx)
>          /* Port security flows have priority 50 (see below) and will
> continue
>           * to the next table if packet source is acceptable. */
>
> -        /* Otherwise drop the packet. */
> -        pipeline_add(&pc, lswitch, 0, 0, "1", "drop;");
> +        /* Otherwise drop the packet unless this lswitch is integrated
> with
> +         * a physical network. */
> +        pipeline_add(&pc, lswitch, 0, 0, "1",
> +                lswitch_has_physical_network(lswitch) ? "next;" :
> "drop;");
>      }
>
>      /* Table 0: Ingress port security. */
> @@ -287,6 +295,13 @@ build_pipeline(struct northd_context *ctx)
>              struct ds match = DS_EMPTY_INITIALIZER;
>              ds_put_cstr(&match, "inport == ");
>              json_string_escape(lport->name, &match);
> +            /* When this lswitch is integrated with a physical network, we
> +             * want to explicitly drop packets that we know came from a
> +             * logical port but didn't pass port security, because the
> +             * default after this will be to accept instead of drop. */
> +            if (lswitch_has_physical_network(lswitch)) {
> +                pipeline_add(&pc, lswitch, 0, 40, ds_cstr(&match),
> "drop;");
> +            }
>              build_port_security("eth.src",
>                                  lport->port_security,
> lport->n_port_security,
>                                  &match);
> @@ -308,6 +323,17 @@ build_pipeline(struct northd_context *ctx)
>
>          ds_init(&bcast);
>          ds_init(&unknown);
> +
> +        if (lswitch_has_physical_network(lswitch)) {
> +            ds_put_cstr(&bcast, "outport = ");
> +            json_string_escape(lswitch->physical_network, &bcast);
> +            ds_put_cstr(&bcast, "; next; ");
> +
> +            ds_put_cstr(&unknown, "outport = ");
> +            json_string_escape(lswitch->physical_network, &unknown);
> +            ds_put_cstr(&unknown, "; next; ");
> +        }
> +
>          for (size_t i = 0; i < lswitch->n_ports; i++) {
>              const struct nbrec_logical_port *lport = lswitch->ports[i];
>
> @@ -391,6 +417,18 @@ build_pipeline(struct northd_context *ctx)
>
>              ds_destroy(&match);
>          }
> +
> +        if (lswitch_has_physical_network(lswitch)) {
> +            struct ds match;
> +
> +            ds_init(&match);
> +            ds_put_cstr(&match, "outport == ");
> +            json_string_escape(lswitch->physical_network, &match);
> +
> +            pipeline_add(&pc, lswitch, 3, 50, ds_cstr(&match), "output;");
> +
> +            ds_destroy(&match);
> +        }
>      }
>
>      /* Delete any existing Pipeline rows that were not re-generated.  */
> diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema
> index f7da779..24af83a 100644
> --- a/ovn/ovn-nb.ovsschema
> +++ b/ovn/ovn-nb.ovsschema
> @@ -18,6 +18,12 @@
>                                                   "refTable":
> "Logical_Router_Port",
>                                                   "refType": "strong"},
>                                           "min": 0, "max": 1}},
> +                "physical_network": {"type": "string"},
> +                "physical_network_tag": {
> +                     "type": {"key": {"type": "integer",
> +                                      "minInteger": 0,
> +                                      "maxInteger": 4095},
> +                              "min": 0, "max": 1}},
>                  "external_ids": {
>                      "type": {"key": "string", "value": "string",
>                               "min": 0, "max": "unlimited"}}},
> diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
> index cafba14..cfc4a93 100644
> --- a/ovn/ovn-nb.xml
> +++ b/ovn/ovn-nb.xml
> @@ -55,6 +55,24 @@
>        </p>
>      </column>
>
> +    <column name="physical_network">
> +      <p>
> +        If a physical_network name is specified, all logical ports on
> this switch
> +        will be connected to an existing network instead of OVN
> implementing
> +        the network as an overlay.  Connectivity to this network is via
> an OVS
> +        bridge that has been configured in ovn-controller's bridge
> mappings
> +        configuration in the <ref db="Open_vSwitch"/> database.
> +      </p>
> +    </column>
> +
> +    <column name="physical_network_tag">
> +      <p>
> +        This option is only relevant if <ref column="physical_network"/>
> +        is also set.  If a VLAN ID is provided in this column, traffic
> sent to the
> +        <ref column="physical_network"/> will be tagged with this VLAN ID.
> +      </p>
> +    </column>
> +
>      <column name="router_port">
>        <p>
>          The router port to which this logical switch is connected, or
> empty if
> diff --git a/ovn/ovn-nbctl.c b/ovn/ovn-nbctl.c
> index bcc5028..3c9925b 100644
> --- a/ovn/ovn-nbctl.c
> +++ b/ovn/ovn-nbctl.c
> @@ -53,7 +53,11 @@ General commands:\n\
>    show LSWITCH              print overview of database contents for
> LSWITCH\n\
>  \n\
>  Logical switch commands:\n\
> -  lswitch-add [LSWITCH]     create a logical switch named LSWITCH\n\
> +  lswitch-add [LSWITCH] [PHYSNET] [TAG]\n\
> +                            create a logical switch named LSWITCH.
> Optionally\n\
> +                            specify the name of the physical network that
> this\n\
> +                            logical switch should map to.  If a physical
> network\n\
> +                            is specified, a VLAN ID may also be
> specified.\n\
>    lswitch-del LSWITCH       delete LSWITCH and all its ports\n\
>    lswitch-list              print the names of all logical switches\n\
>    lswitch-set-external-id LSWITCH KEY [VALUE]\n\
> @@ -143,6 +147,12 @@ print_lswitch(const struct nbrec_logical_switch
> *lswitch)
>  {
>      printf("    lswitch "UUID_FMT" (%s)\n",
>             UUID_ARGS(&lswitch->header_.uuid), lswitch->name);
> +    if (lswitch->physical_network) {
> +        printf("        physical network: %s (%"PRId64")\n",
> +                lswitch->physical_network,
> +                lswitch->physical_network_tag ?
> +                    lswitch->physical_network_tag[0] : 0);
> +    }
>
>      for (size_t i = 0; i < lswitch->n_ports; i++) {
>          const struct nbrec_logical_port *lport = lswitch->ports[i];
> @@ -187,9 +197,20 @@ do_lswitch_add(struct ovs_cmdl_context *ctx)
>      struct nbrec_logical_switch *lswitch;
>
>      lswitch = nbrec_logical_switch_insert(nb_ctx->txn);
> -    if (ctx->argc == 2) {
> +    if (ctx->argc > 1) {
>          nbrec_logical_switch_set_name(lswitch, ctx->argv[1]);
>      }
> +    if (ctx->argc > 2) {
> +        nbrec_logical_switch_set_physical_network(lswitch, ctx->argv[2]);
> +    }
> +    if (ctx->argc > 3) {
> +        int64_t tag;
> +        if (!ovs_scan(ctx->argv[3], "%"SCNd64, &tag) || tag < 0 || tag >
> 4095) {
> +            VLOG_WARN("Invalid tag '%s'", ctx->argv[4]);
> +            return;
> +        }
> +        nbrec_logical_switch_set_physical_network_tag(lswitch, &tag, 1);
> +    }
>  }
>
>  static void
> @@ -695,9 +716,9 @@ static const struct ovs_cmdl_command all_commands[] = {
>      },
>      {
>          .name = "lswitch-add",
> -        .usage = "[LSWITCH]",
> +        .usage = "[LSWITCH] [PHYSNET] [TAG]",
>          .min_args = 0,
> -        .max_args = 1,
> +        .max_args = 3,
>          .handler = do_lswitch_add,
>      },
>      {
> diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml
> index 52fe969..9619cf3 100644
> --- a/ovn/ovn-sb.xml
> +++ b/ovn/ovn-sb.xml
> @@ -572,6 +572,8 @@
>            <code>outport</code>.  Output to the ingress port is implicitly
>            dropped, that is, <code>output</code> becomes a no-op if
>            <code>outport</code> == <code>inport</code>.
> +          If instead <code>outport</code> refers to a physical network
> instead
> +          of a logical port, the packet will be sent out on that network.
>          </dd>
>
>          <dt><code>next;</code></dt>
> --
> 2.4.3
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
>



More information about the dev mailing list