[ovs-dev] [RFC v2 11/11] ovn: Add "localnet" logical port type.

Russell Bryant rbryant at redhat.com
Thu Jul 16 22:06:19 UTC 2015


Introduce a new logical port type called "localnet".  A logical port
with this type also has an option called "network_name".  A "localnet"
logical port represents a connection to a locally accessible network.
ovn-controller will use the ovn-bridge-mappings configuration to
figure out which patch port on br-int should be used for this port.

Signed-off-by: Russell Bryant <rbryant at redhat.com>
---
 ovn/controller/physical.c | 123 +++++++++++++++++++++++++++++++++++-----------
 ovn/ovn-nb.xml            |  15 ++++--
 ovn/ovn-sb.xml            |  22 +++++++--
 3 files changed, 124 insertions(+), 36 deletions(-)

diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c
index 9e7f2f4..e7dd98b 100644
--- a/ovn/controller/physical.c
+++ b/ovn/controller/physical.c
@@ -22,6 +22,7 @@
 #include "ovn-controller.h"
 #include "ovn/lib/ovn-sb-idl.h"
 #include "pipeline.h"
+#include "shash.h"
 #include "simap.h"
 #include "vswitch-idl.h"
 
@@ -42,11 +43,23 @@ physical_init(struct controller_ctx *ctx)
     ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_interface_col_external_ids);
 }
 
+static void
+init_input_match(struct match *match, ofp_port_t ofport, int tag)
+{
+    match_init_catchall(match);
+    match_set_in_port(match, ofport);
+    if (tag) {
+        match_set_dl_vlan(match, htons(tag));
+    }
+}
+
 void
 physical_run(struct controller_ctx *ctx)
 {
     struct simap lport_to_ofport = SIMAP_INITIALIZER(&lport_to_ofport);
     struct simap chassis_to_ofport = SIMAP_INITIALIZER(&chassis_to_ofport);
+    struct simap localnet_to_ofport = SIMAP_INITIALIZER(&localnet_to_ofport);
+
     for (int i = 0; i < ctx->br_int->n_ports; i++) {
         const struct ovsrec_port *port_rec = ctx->br_int->ports[i];
         if (!strcmp(port_rec->name, ctx->br_int_name)) {
@@ -71,8 +84,17 @@ physical_run(struct controller_ctx *ctx)
                 continue;
             }
 
-            /* Record as chassis or local logical port. */
-            if (chassis_id) {
+            /* Record as patch to local net, chassis, or local logical port. */
+            if (!strcmp(iface_rec->type, "patch")) {
+                const char *peer = smap_get(&iface_rec->options, "peer");
+                if (!peer) {
+                    continue;
+                }
+                const char *localnet = smap_get(&ctx->bridge_mappings, peer);
+                if (localnet) {
+                    simap_put(&localnet_to_ofport, localnet, ofport);
+                }
+            } else if (chassis_id) {
                 simap_put(&chassis_to_ofport, chassis_id, ofport);
                 break;
             } else {
@@ -88,6 +110,13 @@ physical_run(struct controller_ctx *ctx)
     struct ofpbuf ofpacts;
     ofpbuf_init(&ofpacts, 0);
 
+    struct localnet_flow {
+        struct shash_node node;
+        struct match match;
+        struct ofpbuf ofpacts;
+    };
+    struct shash localnet_inputs = SHASH_INITIALIZER(&localnet_inputs);
+
     /* Set up flows in table 0 for physical-to-logical translation and in table
      * 64 for logical-to-physical translation. */
     const struct sbrec_binding *binding;
@@ -99,10 +128,15 @@ physical_run(struct controller_ctx *ctx)
          * (and set 'local' to true). When 'parent_port' is set for a binding,
          * it implies a container sitting inside a VM reachable via a 'tag'.
          */
-
         int tag = 0;
         ofp_port_t ofport;
-        if (binding->parent_port) {
+        if (!strcmp(binding->type, "localnet")) {
+            const char *network = smap_get(&binding->options, "network_name");
+            if (!network) {
+                continue;
+            }
+            ofport = u16_to_ofp(simap_get(&localnet_to_ofport, network));
+        } else if (binding->parent_port) {
             ofport = u16_to_ofp(simap_get(&lport_to_ofport,
                                           binding->parent_port));
             if (ofport && binding->tag) {
@@ -134,6 +168,9 @@ physical_run(struct controller_ctx *ctx)
 
         struct match match;
         if (local) {
+            struct ofpbuf *local_ofpacts = &ofpacts;
+            bool add_input_flow = true;
+
             /* Packets that arrive from a vif can belong to a VM or
              * to a container located inside that VM. Packets that
              * arrive from containers have a tag (vlan) associated with them.
@@ -149,53 +186,67 @@ physical_run(struct controller_ctx *ctx)
              * For both types of traffic: set MFF_LOG_INPORT to the
              * logical input port, MFF_METADATA to the logical datapath, and
              * resubmit into the logical pipeline starting at table 16. */
-            match_init_catchall(&match);
-            ofpbuf_clear(&ofpacts);
-            match_set_in_port(&match, ofport);
-            if (tag) {
-                match_set_dl_vlan(&match, htons(tag));
+            if (!strcmp(binding->type, "localnet")) {
+                const char *network = smap_get(&binding->options, "network_name");
+                struct shash_node *node;
+                struct localnet_flow *ln_flow;
+                node = shash_find(&localnet_inputs, network);
+                if (!node) {
+                    ln_flow = xmalloc(sizeof *ln_flow);
+                    ofpbuf_init(&ln_flow->ofpacts, 0);
+                    init_input_match(&ln_flow->match, ofport, tag);
+                    node = shash_add(&localnet_inputs, network, ln_flow);
+                }
+                ln_flow = node->data;
+                local_ofpacts = &ln_flow->ofpacts;
+                add_input_flow = false;
+            } else {
+                ofpbuf_clear(local_ofpacts);
+                init_input_match(&match, ofport, tag);
             }
 
             /* Set MFF_METADATA. */
-            struct ofpact_set_field *sf = ofpact_put_SET_FIELD(&ofpacts);
+            struct ofpact_set_field *sf = ofpact_put_SET_FIELD(local_ofpacts);
             sf->field = mf_from_id(MFF_METADATA);
             sf->value.be64 = htonll(ldp);
             sf->mask.be64 = OVS_BE64_MAX;
 
             /* Set MFF_LOG_INPORT. */
-            sf = ofpact_put_SET_FIELD(&ofpacts);
+            sf = ofpact_put_SET_FIELD(local_ofpacts);
             sf->field = mf_from_id(MFF_LOG_INPORT);
             sf->value.be32 = htonl(binding->tunnel_key);
             sf->mask.be32 = OVS_BE32_MAX;
 
             /* Strip vlans. */
             if (tag) {
-                ofpact_put_STRIP_VLAN(&ofpacts);
+                ofpact_put_STRIP_VLAN(local_ofpacts);
             }
 
             /* Resubmit to first logical pipeline table. */
-            struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts);
+            struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(local_ofpacts);
             resubmit->in_port = OFPP_IN_PORT;
             resubmit->table_id = 16;
-            ofctrl_add_flow(0, tag ? 150 : 100, &match, &ofpacts);
+            if (add_input_flow) {
+                ofctrl_add_flow(0, tag ? 150 : 100, &match, &ofpacts);
 
-            /* Table 0, Priority 50.
-             * =====================
-             *
-             * For packets that arrive from a remote node destined to this
-             * local vif: deliver directly to the vif. If the destination
-             * is a container sitting behind a vif, tag the packets. */
-            match_init_catchall(&match);
-            ofpbuf_clear(&ofpacts);
-            match_set_tun_id(&match, htonll(binding->tunnel_key));
-            if (tag) {
-                struct ofpact_vlan_vid *vlan_vid;
-                vlan_vid = ofpact_put_SET_VLAN_VID(&ofpacts);
-                vlan_vid->vlan_vid = tag;
-                vlan_vid->push_vlan_if_needed = true;
+                /* Table 0, Priority 50.
+                 * =====================
+                 *
+                 * For packets that arrive from a remote node destined to this
+                 * local vif: deliver directly to the vif. If the destination
+                 * is a container sitting behind a vif, tag the packets. */
+                match_init_catchall(&match);
+                ofpbuf_clear(&ofpacts);
+                match_set_tun_id(&match, htonll(binding->tunnel_key));
+                if (tag) {
+                    struct ofpact_vlan_vid *vlan_vid;
+                    vlan_vid = ofpact_put_SET_VLAN_VID(&ofpacts);
+                    vlan_vid->vlan_vid = tag;
+                    vlan_vid->push_vlan_if_needed = true;
+                }
+                ofpact_put_OUTPUT(&ofpacts)->port = ofport;
+                ofctrl_add_flow(0, 50, &match, &ofpacts);
             }
-            ofpact_put_OUTPUT(&ofpacts)->port = ofport;
-            ofctrl_add_flow(0, 50, &match, &ofpacts);
         }
 
         /* Table 64, Priority 100.
@@ -244,7 +295,19 @@ physical_run(struct controller_ctx *ctx)
         ofctrl_add_flow(64, 50, &match, &ofpacts);
     }
 
+    struct shash_node *ln_flow_node, *ln_flow_node_next;
+    struct localnet_flow *ln_flow;
+    SHASH_FOR_EACH_SAFE (ln_flow_node, ln_flow_node_next, &localnet_inputs) {
+        ln_flow = ln_flow_node->data;
+        shash_delete(&localnet_inputs, ln_flow_node);
+        ofctrl_add_flow(0, 100, &ln_flow->match, &ln_flow->ofpacts);
+        ofpbuf_uninit(&ln_flow->ofpacts);
+        free(ln_flow);
+    }
+    shash_destroy(&localnet_inputs);
+
     ofpbuf_uninit(&ofpacts);
     simap_destroy(&lport_to_ofport);
     simap_destroy(&chassis_to_ofport);
+    simap_destroy(&localnet_to_ofport);
 }
diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
index fed6195..a3d1cd9 100644
--- a/ovn/ovn-nb.xml
+++ b/ovn/ovn-nb.xml
@@ -116,13 +116,22 @@
       </p>
 
       <p>
-      There are no other logical port types implemented yet.
+      When this column is set to <em>localnet</em>, this logical port represents a
+      connection to a locally accessible network from each ovn-controller instance.
       </p>
     </column>
 
     <column name="options">
-        This column provides key/value settings specific to the logical port
-        <ref column="type"/>.
+      <p>
+      This column provides key/value settings specific to the logical port
+      <ref column="type"/>.
+      </p>
+
+      <p>
+      When <ref column="type"/> is set to <em>localnet</em>, you must set the option
+      <em>network_name</em>.  ovn-controller uses local configuration to determine
+      exactly how to connect to this locally accessible network.
+      </p>
     </column>
 
     <column name="parent_name">
diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml
index 468cbe8..1915a60 100644
--- a/ovn/ovn-sb.xml
+++ b/ovn/ovn-sb.xml
@@ -681,13 +681,29 @@
       </p>
 
       <p>
-      There are no other logical port types implemented yet.
+      When this column is set to <em>localnet</em>, this logical port represents a
+      connection to a locally accessible network from each ovn-controller instance.
       </p>
     </column>
 
     <column name="options">
-        This column provides key/value settings specific to the logical port
-        <ref column="type"/>.
+      <p>
+      This column provides key/value settings specific to the logical port
+      <ref column="type"/>.
+      </p>
+
+      <p>
+      When <ref column="type"/> is set to <em>localnet</em>, you must set the option
+      <em>network_name</em>.  ovn-controller uses the configuration entry
+      <em>ovn-bridge-mappings</em> to determine how to connect to this network.
+      <em>ovn-bridge-mappings</em> is a list of network names mapped to a local
+      OVS bridge that provides access to that network.  An example of configuring
+      <em>ovn-bridge-mappings</em> would be:
+      </p>
+
+      <p>
+      <em>$ ovs-vsctl set open . external-ids:ovn-bridge-mappings=physnet1:br-eth0,physnet2:br-eth1</em>
+      </p>
     </column>
 
     <column name="tunnel_key">
-- 
2.4.3




More information about the dev mailing list