This last piece allows us to start testing and debugging a complete OVN
installation.  It is so far tested only in the sandbox, where the flows
created seem plausible at first glance.

Signed-off-by: Ben Pfaff <b...@nicira.com>
---
 ovn/controller/automake.mk                |   4 +-
 ovn/controller/ovn-controller.c           |   5 +
 ovn/controller/physical.c                 | 194 ++++++++++++++++++++++++++++++
 ovn/controller/{pipeline.h => physical.h} |  22 ++--
 ovn/controller/pipeline.c                 |  11 +-
 ovn/controller/pipeline.h                 |  19 +++
 6 files changed, 242 insertions(+), 13 deletions(-)
 create mode 100644 ovn/controller/physical.c
 copy ovn/controller/{pipeline.h => physical.h} (59%)

diff --git a/ovn/controller/automake.mk b/ovn/controller/automake.mk
index 74cfb62..01bb287 100644
--- a/ovn/controller/automake.mk
+++ b/ovn/controller/automake.mk
@@ -9,7 +9,9 @@ ovn_controller_ovn_controller_SOURCES = \
        ovn/controller/ovn-controller.c \
        ovn/controller/ovn-controller.h \
        ovn/controller/pipeline.c \
-       ovn/controller/pipeline.h
+       ovn/controller/pipeline.h \
+       ovn/controller/physical.c \
+       ovn/controller/physical.h
 ovn_controller_ovn_controller_LDADD = ovn/lib/libovn.la lib/libopenvswitch.la
 man_MANS += ovn/controller/ovn-controller.8
 EXTRA_DIST += ovn/controller/ovn-controller.8.xml
diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c
index 8007ce4..6744068 100644
--- a/ovn/controller/ovn-controller.c
+++ b/ovn/controller/ovn-controller.c
@@ -42,6 +42,7 @@
 #include "ofctrl.h"
 #include "bindings.h"
 #include "chassis.h"
+#include "physical.h"
 #include "pipeline.h"
 
 VLOG_DEFINE_THIS_MODULE(main);
@@ -183,6 +184,7 @@ main(int argc, char *argv[])
 
     chassis_init(&ctx);
     bindings_init(&ctx);
+    physical_init(&ctx);
 
     get_initial_snapshot(ctx.ovs_idl);
 
@@ -225,9 +227,12 @@ main(int argc, char *argv[])
             break;
         }
 
+        ofctrl_clear_flows();
+
         chassis_run(&ctx);
         bindings_run(&ctx);
         pipeline_run(&ctx);
+        physical_run(&ctx);
         ofctrl_run(&ctx);
         unixctl_server_run(unixctl);
 
diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c
new file mode 100644
index 0000000..55422d3
--- /dev/null
+++ b/ovn/controller/physical.c
@@ -0,0 +1,194 @@
+/* Copyright (c) 2015 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "physical.h"
+#include "match.h"
+#include "ofctrl.h"
+#include "ofp-actions.h"
+#include "ofpbuf.h"
+#include "ovn-controller.h"
+#include "ovn/lib/ovn-sb-idl.h"
+#include "pipeline.h"
+#include "simap.h"
+#include "vswitch-idl.h"
+
+void
+physical_init(struct controller_ctx *ctx)
+{
+    ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_bridge);
+    ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_bridge_col_ports);
+
+    ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_port);
+    ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_port_col_name);
+    ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_port_col_interfaces);
+    ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_port_col_external_ids);
+
+    ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_interface);
+    ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_interface_col_name);
+    ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_interface_col_ofport);
+    ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_interface_col_external_ids);
+}
+
+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);
+    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)) {
+            continue;
+        }
+
+        const char *chassis_id = smap_get(&port_rec->external_ids,
+                                          "ovn-chassis-id");
+        if (chassis_id && !strcmp(chassis_id, ctx->chassis_id)) {
+            continue;
+        }
+
+        for (int j = 0; j < port_rec->n_interfaces; j++) {
+            const struct ovsrec_interface *iface_rec = port_rec->interfaces[j];
+
+            /* Get OpenFlow port number. */
+            if (!iface_rec->n_ofport) {
+                continue;
+            }
+            int64_t ofport = iface_rec->ofport[0];
+            if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) {
+                continue;
+            }
+
+            /* Record as chassis or logical port. */
+            if (chassis_id) {
+                simap_put(&chassis_to_ofport, chassis_id, ofport);
+                break;
+            } else {
+                const char *iface_id = smap_get(&iface_rec->external_ids,
+                                                "iface-id");
+                if (iface_id) {
+                    simap_put(&lport_to_ofport, iface_id, ofport);
+                }
+            }
+        }
+    }
+
+    struct ofpbuf ofpacts;
+    ofpbuf_init(&ofpacts, 0);
+
+    /* Set up flows in table 0 for physical-to-logical translation and in table
+     * 64 for logical-to-physical translation. */
+    const struct sbrec_bindings *binding;
+    SBREC_BINDINGS_FOR_EACH (binding, ctx->ovnsb_idl) {
+        /* Find the Openflow port for the logical port, as 'ofport'.  If it's
+         * on a remote chassis, this is the OpenFlow port for the tunnel to
+         * that chassis (and set 'local' to false).  Otherwise, if it's on the
+         * chassis we're managing, this is the OpenFlow port for the vif itself
+         * (and set 'local' to true). */
+        ofp_port_t ofport = u16_to_ofp(simap_get(&lport_to_ofport,
+                                                 binding->logical_port));
+        bool local = ofport != 0;
+        if (!local) {
+            ofport = u16_to_ofp(simap_get(&chassis_to_ofport,
+                                          binding->chassis));
+            if (!ofport) {
+                continue;
+            }
+        }
+
+        /* Translate the logical datapath into the form we use in
+         * MFF_METADATA. */
+        uint32_t ldp = ldp_to_integer(&binding->logical_datapath);
+        if (!ldp) {
+            continue;
+        }
+
+        struct match match;
+        if (local) {
+            /* Table 0, Priority 100.
+             * ======================
+             *
+             * For packets that arrive from a vif: 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);
+
+            /* Set MFF_METADATA. */
+            struct ofpact_set_field *sf = ofpact_put_SET_FIELD(&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->field = mf_from_id(MFF_LOG_INPORT);
+            sf->value.be32 = htonl(binding->tunnel_key);
+            sf->mask.be32 = OVS_BE32_MAX;
+
+            /* Resubmit to first logical pipeline table. */
+            struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts);
+            resubmit->in_port = OFPP_IN_PORT;
+            resubmit->table_id = 16;
+            ofctrl_add_flow(0, 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. */
+            match_init_catchall(&match);
+            ofpbuf_clear(&ofpacts);
+            match_set_tun_id(&match, htonll(binding->tunnel_key));
+            ofpact_put_OUTPUT(&ofpacts)->port = ofport;
+            ofctrl_add_flow(0, 50, &match, &ofpacts);
+        }
+
+        /* Table 64, Priority 100.
+         * =======================
+         *
+         * Drop packets whose logical inport and outport are the same. */
+        match_init_catchall(&match);
+        ofpbuf_clear(&ofpacts);
+        match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0, binding->tunnel_key);
+        match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, binding->tunnel_key);
+        ofctrl_add_flow(64, 100, &match, &ofpacts);
+
+        /* Table 64, Priority 50.
+         * ======================
+         *
+         * For packets to remote machines, send them over a tunnel to the
+         * remote chassis.
+         *
+         * For packest to local vifs, deliver them directly. */
+        match_init_catchall(&match);
+        ofpbuf_clear(&ofpacts);
+        match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, binding->tunnel_key);
+        if (!local) {
+            /* Set MFF_TUN_ID. */
+            struct ofpact_set_field *sf = ofpact_put_SET_FIELD(&ofpacts);
+            sf->field = mf_from_id(MFF_TUN_ID);
+            sf->value.be64 = htonll(binding->tunnel_key);
+            sf->mask.be64 = OVS_BE64_MAX;
+        }
+        ofpact_put_OUTPUT(&ofpacts)->port = ofport;
+        ofctrl_add_flow(64, 50, &match, &ofpacts);
+    }
+
+    ofpbuf_uninit(&ofpacts);
+    simap_destroy(&lport_to_ofport);
+    simap_destroy(&chassis_to_ofport);
+}
diff --git a/ovn/controller/pipeline.h b/ovn/controller/physical.h
similarity index 59%
copy from ovn/controller/pipeline.h
copy to ovn/controller/physical.h
index a5ed51f..d0a3ac7 100644
--- a/ovn/controller/pipeline.h
+++ b/ovn/controller/physical.h
@@ -13,18 +13,20 @@
  * limitations under the License.
  */
 
+#ifndef OVN_PHYSICAL_H
+#define OVN_PHYSICAL_H 1
 
-#ifndef OVN_PIPELINE_H
-#define OVN_PIPELINE_H 1
+/* Logical/Physical Translation
+ * ============================
+ *
+ * This module implements physical-to-logical and logical-to-physical
+ * translation as separate OpenFlow tables that run before and after,
+ * respectively, the logical pipeline OpenFlow tables.
+ */
 
 struct controller_ctx;
 
-/* Logical ports. */
-#define MFF_LOG_INPORT  MFF_REG6 /* Logical input port. */
-#define MFF_LOG_OUTPORT MFF_REG7 /* Logical output port. */
-
-void pipeline_init(struct controller_ctx *);
-void pipeline_run(struct controller_ctx *);
-void pipeline_destroy(struct controller_ctx *);
+void physical_init(struct controller_ctx *);
+void physical_run(struct controller_ctx *);
 
-#endif /* ovn/pipeline.h */
+#endif /* ovn/physical.h */
diff --git a/ovn/controller/pipeline.c b/ovn/controller/pipeline.c
index 48756b0..902385f 100644
--- a/ovn/controller/pipeline.c
+++ b/ovn/controller/pipeline.c
@@ -172,6 +172,15 @@ ldp_lookup(const struct uuid *uuid)
     return NULL;
 }
 
+/* Finds and returns the integer value corresponding to the given 'uuid', or 0
+ * if no such logical datapath exists. */
+uint32_t
+ldp_to_integer(const struct uuid *logical_datapath)
+{
+    const struct logical_datapath *ldp = ldp_lookup(logical_datapath);
+    return ldp ? ldp->integer : 0;
+}
+
 /* Creates a new logical_datapath with the given 'uuid'. */
 static struct logical_datapath *
 ldp_create(const struct uuid *uuid)
@@ -252,8 +261,6 @@ pipeline_run(struct controller_ctx *ctx)
 
     ldp_run(ctx);
 
-    ofctrl_clear_flows();
-
     const struct sbrec_pipeline *pipeline;
     SBREC_PIPELINE_FOR_EACH (pipeline, ctx->ovnsb_idl) {
         /* Find the "struct logical_datapath" asssociated with this Pipeline
diff --git a/ovn/controller/pipeline.h b/ovn/controller/pipeline.h
index a5ed51f..9838d51 100644
--- a/ovn/controller/pipeline.h
+++ b/ovn/controller/pipeline.h
@@ -17,7 +17,24 @@
 #ifndef OVN_PIPELINE_H
 #define OVN_PIPELINE_H 1
 
+/* Pipeline table translation to OpenFlow
+ * ======================================
+ *
+ * The Pipeline table obtained from the OVN_Southbound database works in terms
+ * of logical entities, that is, logical flows among logical datapaths and
+ * logical ports.  This code translates these logical flows into OpenFlow flows
+ * that, again, work in terms of logical entities implemented through OpenFlow
+ * extensions (e.g. registers represent the logical input and output ports).
+ *
+ * Physical-to-logical and logical-to-physical translation are implemented in
+ * physical.[ch] as separate OpenFlow tables that run before and after,
+ * respectively, the logical pipeline OpenFlow tables.
+ */
+
+#include <stdint.h>
+
 struct controller_ctx;
+struct uuid;
 
 /* Logical ports. */
 #define MFF_LOG_INPORT  MFF_REG6 /* Logical input port. */
@@ -27,4 +44,6 @@ void pipeline_init(struct controller_ctx *);
 void pipeline_run(struct controller_ctx *);
 void pipeline_destroy(struct controller_ctx *);
 
+uint32_t ldp_to_integer(const struct uuid *logical_datapath);
+
 #endif /* ovn/pipeline.h */
-- 
2.1.3

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to