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

Russell Bryant rbryant at redhat.com
Mon Jul 6 17:45:03 UTC 2015


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




More information about the dev mailing list