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