This was more or less implemented inside lflow.c until now, but some upcoming code that shouldn't be in that file needs to use it too.
This also adds a second index on lports, so that lports can be looked up based on the logical datapath tunnel key and the logical port tunnel key. An upcoming commit will add a user for this new index. Signed-off-by: Ben Pfaff <b...@ovn.org> --- ovn/controller/automake.mk | 2 + ovn/controller/lflow.c | 181 ++++++++++------------------------------ ovn/controller/lflow.h | 10 ++- ovn/controller/lport.c | 157 ++++++++++++++++++++++++++++++++++ ovn/controller/lport.h | 67 +++++++++++++++ ovn/controller/ovn-controller.c | 36 ++++---- 6 files changed, 299 insertions(+), 154 deletions(-) create mode 100644 ovn/controller/lport.c create mode 100644 ovn/controller/lport.h diff --git a/ovn/controller/automake.mk b/ovn/controller/automake.mk index cadfa9c..cf57bbd 100644 --- a/ovn/controller/automake.mk +++ b/ovn/controller/automake.mk @@ -8,6 +8,8 @@ ovn_controller_ovn_controller_SOURCES = \ ovn/controller/encaps.h \ ovn/controller/lflow.c \ ovn/controller/lflow.h \ + ovn/controller/lport.c \ + ovn/controller/lport.h \ ovn/controller/ofctrl.c \ ovn/controller/ofctrl.h \ ovn/controller/pinctrl.c \ diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c index 912c609..bd08ad6 100644 --- a/ovn/controller/lflow.c +++ b/ovn/controller/lflow.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015 Nicira, Inc. +/* Copyright (c) 2015, 2016 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,12 +15,13 @@ #include <config.h> #include "lflow.h" +#include "lport.h" #include "dynamic-string.h" #include "ofctrl.h" #include "ofp-actions.h" #include "ofpbuf.h" #include "openvswitch/vlog.h" -#include "ovn/controller/ovn-controller.h" +#include "ovn-controller.h" #include "ovn/lib/actions.h" #include "ovn/lib/expr.h" #include "ovn/lib/ovn-sb-idl.h" @@ -43,8 +44,8 @@ add_logical_register(struct shash *symtab, enum mf_field_id id) expr_symtab_add_field(symtab, name, id, NULL, false); } -static void -symtab_init(void) +void +lflow_init(void) { shash_init(&symtab); @@ -155,161 +156,62 @@ symtab_init(void) expr_symtab_add_field(&symtab, "sctp.dst", MFF_SCTP_DST, "sctp", false); } -/* Logical datapaths and logical port numbers. */ - -enum ldp_type { - LDP_TYPE_ROUTER, - LDP_TYPE_SWITCH, -}; - -/* A logical datapath. - * - * 'ports' maps 'logical_port' names to 'tunnel_key' values in the OVN_SB - * Port_Binding table within the logical datapath. */ -struct logical_datapath { - struct hmap_node hmap_node; /* Indexed on 'uuid'. */ - struct uuid uuid; /* UUID from Datapath_Binding row. */ - uint32_t tunnel_key; /* 'tunnel_key' from Datapath_Binding row. */ - struct simap ports; /* Logical port name to port number. */ - enum ldp_type type; /* Type of logical datapath */ +struct lookup_port_aux { + const struct lport_index *lports; + const struct mcgroup_index *mcgroups; + const struct sbrec_datapath_binding *dp; }; -/* Contains "struct logical_datapath"s. */ -static struct hmap logical_datapaths = HMAP_INITIALIZER(&logical_datapaths); - -/* Finds and returns the logical_datapath for 'binding', or NULL if no such - * logical_datapath exists. */ -static struct logical_datapath * -ldp_lookup(const struct sbrec_datapath_binding *binding) -{ - struct logical_datapath *ldp; - HMAP_FOR_EACH_IN_BUCKET (ldp, hmap_node, uuid_hash(&binding->header_.uuid), - &logical_datapaths) { - if (uuid_equals(&ldp->uuid, &binding->header_.uuid)) { - return ldp; - } - } - return NULL; -} - -/* Creates a new logical_datapath for the given 'binding'. */ -static struct logical_datapath * -ldp_create(const struct sbrec_datapath_binding *binding) -{ - struct logical_datapath *ldp; - - ldp = xmalloc(sizeof *ldp); - hmap_insert(&logical_datapaths, &ldp->hmap_node, - uuid_hash(&binding->header_.uuid)); - ldp->uuid = binding->header_.uuid; - ldp->tunnel_key = binding->tunnel_key; - const char *ls = smap_get(&binding->external_ids, "logical-switch"); - ldp->type = ls ? LDP_TYPE_SWITCH : LDP_TYPE_ROUTER; - simap_init(&ldp->ports); - return ldp; -} - -static struct logical_datapath * -ldp_lookup_or_create(const struct sbrec_datapath_binding *binding) -{ - struct logical_datapath *ldp = ldp_lookup(binding); - return ldp ? ldp : ldp_create(binding); -} - -static void -ldp_free(struct logical_datapath *ldp) +static bool +lookup_port_cb(const void *aux_, const char *port_name, unsigned int *portp) { - simap_destroy(&ldp->ports); - hmap_remove(&logical_datapaths, &ldp->hmap_node); - free(ldp); -} + const struct lookup_port_aux *aux = aux_; -/* Iterates through all of the records in the Port_Binding table, updating the - * table of logical_datapaths to match the values found in active - * Port_Bindings. */ -static void -ldp_run(struct controller_ctx *ctx) -{ - struct logical_datapath *ldp; - HMAP_FOR_EACH (ldp, hmap_node, &logical_datapaths) { - simap_clear(&ldp->ports); + const struct sbrec_port_binding *pb + = lport_lookup_by_name(aux->lports, port_name); + if (pb && pb->datapath == aux->dp) { + *portp = pb->tunnel_key; + return true; } - const struct sbrec_port_binding *binding; - SBREC_PORT_BINDING_FOR_EACH (binding, ctx->ovnsb_idl) { - struct logical_datapath *ldp = ldp_lookup_or_create(binding->datapath); - - simap_put(&ldp->ports, binding->logical_port, binding->tunnel_key); + const struct sbrec_multicast_group *mg + = mcgroup_lookup_by_dp_name(aux->mcgroups, aux->dp, port_name); + if (mg) { + *portp = mg->tunnel_key; + return true; } - const struct sbrec_multicast_group *mc; - SBREC_MULTICAST_GROUP_FOR_EACH (mc, ctx->ovnsb_idl) { - struct logical_datapath *ldp = ldp_lookup_or_create(mc->datapath); - simap_put(&ldp->ports, mc->name, mc->tunnel_key); - } - - struct logical_datapath *next_ldp; - HMAP_FOR_EACH_SAFE (ldp, next_ldp, hmap_node, &logical_datapaths) { - if (simap_is_empty(&ldp->ports)) { - ldp_free(ldp); - } - } -} - -static void -ldp_destroy(void) -{ - struct logical_datapath *ldp, *next_ldp; - HMAP_FOR_EACH_SAFE (ldp, next_ldp, hmap_node, &logical_datapaths) { - ldp_free(ldp); - } -} - -void -lflow_init(void) -{ - symtab_init(); + return false; } static bool -lookup_port_cb(const void *ldp_, const char *port_name, unsigned int *portp) +is_switch(const struct sbrec_datapath_binding *ldp) { - const struct logical_datapath *ldp = ldp_; - const struct simap_node *node = simap_find(&ldp->ports, port_name); - if (!node) { - return false; - } - *portp = node->data; - return true; + return smap_get(&ldp->external_ids, "logical-switch") != NULL; + } /* Translates logical flows in the Logical_Flow table in the OVN_SB database * into OpenFlow flows. See ovn-architecture(7) for more information. */ void -lflow_run(struct controller_ctx *ctx, struct hmap *flow_table, - const struct simap *ct_zones, - struct hmap *local_datapaths) +lflow_run(struct controller_ctx *ctx, const struct lport_index *lports, + const struct mcgroup_index *mcgroups, + const struct hmap *local_datapaths, + const struct simap *ct_zones, struct hmap *flow_table) { struct hmap flows = HMAP_INITIALIZER(&flows); uint32_t conj_id_ofs = 1; - ldp_run(ctx); - const struct sbrec_logical_flow *lflow; SBREC_LOGICAL_FLOW_FOR_EACH (lflow, ctx->ovnsb_idl) { - /* Find the "struct logical_datapath" associated with this - * Logical_Flow row. If there's no such struct, that must be because - * no logical ports are bound to that logical datapath, so there's no - * point in maintaining any flows for it anyway, so skip it. */ - const struct logical_datapath *ldp; - ldp = ldp_lookup(lflow->logical_datapath); + /* Determine translation of logical table IDs to physical table IDs. */ + bool ingress = !strcmp(lflow->pipeline, "ingress"); + + const struct sbrec_datapath_binding *ldp = lflow->logical_datapath; if (!ldp) { continue; } - - bool ingress = !strcmp(lflow->pipeline, "ingress"); - - if (ldp->type == LDP_TYPE_SWITCH && !ingress) { + if (!ingress && is_switch(ldp)) { /* For a logical switch datapath, local_datapaths tells us if there * are any local ports for this datapath. If not, processing * logical flows for the egress pipeline of this datapath is @@ -356,10 +258,15 @@ lflow_run(struct controller_ctx *ctx, struct hmap *flow_table, char *error; ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub); + struct lookup_port_aux aux = { + .lports = lports, + .mcgroups = mcgroups, + .dp = lflow->logical_datapath + }; struct action_params ap = { .symtab = &symtab, .lookup_port = lookup_port_cb, - .aux = ldp, + .aux = &aux, .ct_zones = ct_zones, .n_tables = LOG_PIPELINE_LEN, @@ -400,14 +307,15 @@ lflow_run(struct controller_ctx *ctx, struct hmap *flow_table, expr = expr_simplify(expr); expr = expr_normalize(expr); - uint32_t n_conjs = expr_to_matches(expr, lookup_port_cb, ldp, + uint32_t n_conjs = expr_to_matches(expr, lookup_port_cb, &aux, &matches); expr_destroy(expr); /* Prepare the OpenFlow matches for adding to the flow table. */ struct expr_match *m; HMAP_FOR_EACH (m, hmap_node, &matches) { - match_set_metadata(&m->match, htonll(ldp->tunnel_key)); + match_set_metadata(&m->match, + htonll(lflow->logical_datapath->tunnel_key)); if (m->match.wc.masks.conj_id) { m->match.flow.conj_id += conj_id_ofs; } @@ -445,5 +353,4 @@ void lflow_destroy(void) { expr_symtab_destroy(&symtab); - ldp_destroy(); } diff --git a/ovn/controller/lflow.h b/ovn/controller/lflow.h index ccbad30..603edfd 100644 --- a/ovn/controller/lflow.h +++ b/ovn/controller/lflow.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015 Nicira, Inc. +/* Copyright (c) 2015, 2016 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,6 +37,8 @@ struct controller_ctx; struct hmap; +struct lport_index; +struct mcgroup_index; struct simap; struct uuid; @@ -56,9 +58,11 @@ struct uuid; #define LOG_PIPELINE_LEN 16 void lflow_init(void); -void lflow_run(struct controller_ctx *, struct hmap *flow_table, +void lflow_run(struct controller_ctx *, const struct lport_index *, + const struct mcgroup_index *, + const struct hmap *local_datapaths, const struct simap *ct_zones, - struct hmap *local_datapaths); + struct hmap *flow_table); void lflow_destroy(void); #endif /* ovn/lflow.h */ diff --git a/ovn/controller/lport.c b/ovn/controller/lport.c new file mode 100644 index 0000000..e4c6f8c --- /dev/null +++ b/ovn/controller/lport.c @@ -0,0 +1,157 @@ +/* Copyright (c) 2015, 2016 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 "lport.h" +#include "hash.h" +#include "openvswitch/vlog.h" +#include "ovn/lib/ovn-sb-idl.h" + +VLOG_DEFINE_THIS_MODULE(lport); + +/* A logical port. */ +struct lport { + struct hmap_node name_node; /* Index by name. */ + struct hmap_node key_node; /* Index by (dp_key, port_key). */ + const struct sbrec_port_binding *pb; +}; + +void +lport_index_init(struct lport_index *lports, struct ovsdb_idl *ovnsb_idl) +{ + hmap_init(&lports->by_name); + hmap_init(&lports->by_key); + + const struct sbrec_port_binding *pb; + SBREC_PORT_BINDING_FOR_EACH (pb, ovnsb_idl) { + if (lport_lookup_by_name(lports, pb->logical_port)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_WARN_RL(&rl, "duplicate logical port name '%s'", + pb->logical_port); + continue; + } + + struct lport *p = xmalloc(sizeof *p); + hmap_insert(&lports->by_name, &p->name_node, + hash_string(pb->logical_port, 0)); + hmap_insert(&lports->by_key, &p->key_node, + hash_int(pb->tunnel_key, pb->datapath->tunnel_key)); + p->pb = pb; + } +} + +void +lport_index_destroy(struct lport_index *lports) +{ + /* Destroy all of the "struct lport"s. + * + * We don't have to remove the node from both indexes. */ + struct lport *port, *next; + HMAP_FOR_EACH_SAFE (port, next, name_node, &lports->by_name) { + hmap_remove(&lports->by_name, &port->name_node); + free(port); + } + + hmap_destroy(&lports->by_name); + hmap_destroy(&lports->by_key); +} + +/* Finds and returns the lport with the given 'name', or NULL if no such lport + * exists. */ +const struct sbrec_port_binding * +lport_lookup_by_name(const struct lport_index *lports, const char *name) +{ + const struct lport *lport; + HMAP_FOR_EACH_WITH_HASH (lport, name_node, hash_string(name, 0), + &lports->by_name) { + if (!strcmp(lport->pb->logical_port, name)) { + return lport->pb; + } + } + return NULL; +} + +const struct sbrec_port_binding * +lport_lookup_by_key(const struct lport_index *lports, + uint32_t dp_key, uint16_t port_key) +{ + const struct lport *lport; + HMAP_FOR_EACH_WITH_HASH (lport, key_node, hash_int(port_key, dp_key), + &lports->by_key) { + if (port_key == lport->pb->tunnel_key + && dp_key == lport->pb->datapath->tunnel_key) { + return lport->pb; + } + } + return NULL; +} + +struct mcgroup { + struct hmap_node dp_name_node; /* Index by (logical datapath, name). */ + const struct sbrec_multicast_group *mg; +}; + +void +mcgroup_index_init(struct mcgroup_index *mcgroups, struct ovsdb_idl *ovnsb_idl) +{ + hmap_init(&mcgroups->by_dp_name); + + const struct sbrec_multicast_group *sb; + SBREC_MULTICAST_GROUP_FOR_EACH (sb, ovnsb_idl) { + const struct uuid *dp_uuid = &sb->datapath->header_.uuid; + if (mcgroup_lookup_by_dp_name(mcgroups, sb->datapath, sb->name)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_WARN_RL(&rl, "datapath "UUID_FMT" contains duplicate " + "multicast group '%s'", UUID_ARGS(dp_uuid), sb->name); + continue; + } + + struct mcgroup *m = xmalloc(sizeof *m); + hmap_insert(&mcgroups->by_dp_name, &m->dp_name_node, + hash_string(sb->name, uuid_hash(dp_uuid))); + m->mg = sb; + } +} + +void +mcgroup_index_destroy(struct mcgroup_index *mcgroups) +{ + struct mcgroup *mcgroup, *next; + HMAP_FOR_EACH_SAFE (mcgroup, next, dp_name_node, &mcgroups->by_dp_name) { + hmap_remove(&mcgroups->by_dp_name, &mcgroup->dp_name_node); + free(mcgroup); + } + + hmap_destroy(&mcgroups->by_dp_name); +} + +const struct sbrec_multicast_group * +mcgroup_lookup_by_dp_name(const struct mcgroup_index *mcgroups, + const struct sbrec_datapath_binding *dp, + const char *name) +{ + const struct uuid *dp_uuid = &dp->header_.uuid; + const struct mcgroup *mcgroup; + HMAP_FOR_EACH_WITH_HASH (mcgroup, dp_name_node, + hash_string(name, uuid_hash(dp_uuid)), + &mcgroups->by_dp_name) { + if (uuid_equals(&mcgroup->mg->datapath->header_.uuid, dp_uuid) + && !strcmp(mcgroup->mg->name, name)) { + return mcgroup->mg; + } + } + return NULL; +} diff --git a/ovn/controller/lport.h b/ovn/controller/lport.h new file mode 100644 index 0000000..f09e2eb --- /dev/null +++ b/ovn/controller/lport.h @@ -0,0 +1,67 @@ +/* Copyright (c) 2015, 2016 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. + */ + +#ifndef OVN_LPORT_H +#define OVN_LPORT_H 1 + +#include <stdint.h> +#include "hmap.h" + +struct ovsdb_idl; +struct sbrec_datapath_binding; + +/* Logical port and multicast group indexes + * ======================================== + * + * This data structure holds multiple indexes over logical ports, to allow for + * efficient searching for logical ports by name or number. + */ + +struct lport_index { + struct hmap by_name; + struct hmap by_key; +}; + +void lport_index_init(struct lport_index *, struct ovsdb_idl *); +void lport_index_destroy(struct lport_index *); + +const struct sbrec_port_binding *lport_lookup_by_name( + const struct lport_index *, const char *name); +const struct sbrec_port_binding *lport_lookup_by_key( + const struct lport_index *, uint32_t dp_key, uint16_t port_key); + +/* Multicast group index + * ===================== + * + * This is separate from the logical port index because of namespace issues: + * logical port names are globally unique, but multicast group names are only + * unique within the scope of a logical datapath. + * + * Multicast groups could be indexed by number also, but so far the clients do + * not need this index. */ + +struct mcgroup_index { + struct hmap by_dp_name; +}; + +void mcgroup_index_init(struct mcgroup_index *, struct ovsdb_idl *); +void mcgroup_index_destroy(struct mcgroup_index *); + +const struct sbrec_multicast_group *mcgroup_lookup_by_dp_name( + const struct mcgroup_index *, + const struct sbrec_datapath_binding *, + const char *name); + +#endif /* ovn/lport.h */ diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c index 9799a19..517ca2a 100644 --- a/ovn/controller/ovn-controller.c +++ b/ovn/controller/ovn-controller.c @@ -23,33 +23,33 @@ #include <stdlib.h> #include <string.h> +#include "binding.h" +#include "chassis.h" #include "command-line.h" #include "compiler.h" #include "daemon.h" #include "dirs.h" #include "dynamic-string.h" +#include "encaps.h" +#include "fatal-signal.h" +#include "hmap.h" +#include "lflow.h" +#include "lib/vswitch-idl.h" +#include "lport.h" +#include "ofctrl.h" #include "openvswitch/vconn.h" #include "openvswitch/vlog.h" #include "ovn/lib/ovn-sb-idl.h" +#include "patch.h" +#include "physical.h" +#include "pinctrl.h" #include "poll-loop.h" -#include "fatal-signal.h" -#include "lib/hmap.h" -#include "lib/vswitch-idl.h" #include "smap.h" -#include "stream.h" #include "stream-ssl.h" +#include "stream.h" #include "unixctl.h" #include "util.h" -#include "ofctrl.h" -#include "pinctrl.h" -#include "binding.h" -#include "chassis.h" -#include "encaps.h" -#include "patch.h" -#include "physical.h" -#include "lflow.h" - VLOG_DEFINE_THIS_MODULE(main); static unixctl_cb_func ovn_controller_exit; @@ -295,18 +295,26 @@ main(int argc, char *argv[]) if (br_int) { patch_run(&ctx, br_int, &local_datapaths); + struct lport_index lports; + struct mcgroup_index mcgroups; + lport_index_init(&lports, ctx.ovnsb_idl); + mcgroup_index_init(&mcgroups, ctx.ovnsb_idl); + enum mf_field_id mff_ovn_geneve = ofctrl_run(br_int); pinctrl_run(br_int); struct hmap flow_table = HMAP_INITIALIZER(&flow_table); - lflow_run(&ctx, &flow_table, &ct_zones, &local_datapaths); + lflow_run(&ctx, &lports, &mcgroups, &local_datapaths, + &ct_zones, &flow_table); if (chassis_id) { physical_run(&ctx, mff_ovn_geneve, br_int, chassis_id, &ct_zones, &flow_table); } ofctrl_put(&flow_table); hmap_destroy(&flow_table); + mcgroup_index_destroy(&mcgroups); + lport_index_destroy(&lports); } /* local_datapaths contains bare hmap_node instances. -- 2.1.3 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev