From patchwork Sat Oct 10 04:15:29 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 528530 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from archives.nicira.com (li376-54.members.linode.com [96.126.127.54]) by ozlabs.org (Postfix) with ESMTP id 4B15C140E3D for ; Sat, 10 Oct 2015 15:16:55 +1100 (AEDT) Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id E585C10B3E; Fri, 9 Oct 2015 21:16:11 -0700 (PDT) X-Original-To: dev@openvswitch.org Delivered-To: dev@openvswitch.org Received: from mx3v1.cudamail.com (mx3.cudamail.com [64.34.241.5]) by archives.nicira.com (Postfix) with ESMTPS id 25B9710AD5 for ; Fri, 9 Oct 2015 21:16:10 -0700 (PDT) Received: from bar4.cudamail.com (bar2 [192.168.15.2]) by mx3v1.cudamail.com (Postfix) with ESMTP id 8C6A1619848 for ; Fri, 9 Oct 2015 22:16:09 -0600 (MDT) X-ASG-Debug-ID: 1444450564-03dc213abe8e780001-byXFYA Received: from mx3-pf1.cudamail.com ([192.168.14.2]) by bar4.cudamail.com with ESMTP id UEsdHDZtcDa4gsoQ (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Fri, 09 Oct 2015 22:16:04 -0600 (MDT) X-Barracuda-Envelope-From: blp@nicira.com X-Barracuda-RBL-Trusted-Forwarder: 192.168.14.2 Received: from unknown (HELO mail-pa0-f47.google.com) (209.85.220.47) by mx3-pf1.cudamail.com with ESMTPS (RC4-SHA encrypted); 10 Oct 2015 04:16:04 -0000 Received-SPF: unknown (mx3-pf1.cudamail.com: Multiple SPF records returned) X-Barracuda-RBL-Trusted-Forwarder: 209.85.220.47 Received: by padhy16 with SMTP id hy16so103653956pad.1 for ; Fri, 09 Oct 2015 21:16:03 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ezquYGHBa+gYc1Ugaj4EITO5mbqnLFOjWWpugyjOdtc=; b=hCcVtqt6kQUrVz8UR4+q35P8qcNqeqRUvOiCPF8JJWi9cGffRYXUVg1oqwiUrnQ+TW gEkrjrJ+t0INBHqmvXvEGSY/uDzSDkA0fZ64e9FFKs8UX2uEuYO4JDBFgD9CiYyaKx8M GT/k1T+xOZjpY4/ae2DseQbiKN1pRvfr0Lfyoq5rySUwz62CBmuqEb19j3LxEuSOMXJY UVwD8+jtjVXUOZ+Gol6k+bHhUKMbKZxV2YUl3hiTwwfvpVJ6MrABC+PSIfkrBSGyG46v smvzahoOJ6IZpSTj3iok1mMM66TqrdJxHh4ugcu5x0iXrQPWLJaS8WnIkq5xDuvAqTxi s0Fg== X-Gm-Message-State: ALoCoQnArH4xsnx70ZkXK+Uo5Ik+MvaD7Du7fQHoi26kZCmaCfHfof4pzkxPMwrd3jNmvEudJPq+ X-Received: by 10.66.236.129 with SMTP id uu1mr19744241pac.34.1444450563164; Fri, 09 Oct 2015 21:16:03 -0700 (PDT) Received: from sigabrt.gateway.sonic.net (173-228-112-112.dsl.dynamic.fusionbroadband.com. [173.228.112.112]) by smtp.gmail.com with ESMTPSA id bk8sm5386937pad.18.2015.10.09.21.16.01 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 09 Oct 2015 21:16:01 -0700 (PDT) X-CudaMail-Envelope-Sender: blp@nicira.com X-Barracuda-Apparent-Source-IP: 173.228.112.112 From: Ben Pfaff To: dev@openvswitch.org X-CudaMail-Whitelist-To: dev@openvswitch.org X-CudaMail-MID: CM-V1-1008077599 X-CudaMail-DTE: 100915 X-CudaMail-Originating-IP: 209.85.220.47 Date: Fri, 9 Oct 2015 21:15:29 -0700 X-ASG-Orig-Subj: [##CM-V1-1008077599##][PATCH 08/23] ovn-controller: Factor patch port management into new "patch" module. Message-Id: <1444450544-11845-9-git-send-email-blp@nicira.com> X-Mailer: git-send-email 2.1.3 In-Reply-To: <1444450544-11845-1-git-send-email-blp@nicira.com> References: <1444450544-11845-1-git-send-email-blp@nicira.com> X-Barracuda-Connect: UNKNOWN[192.168.14.2] X-Barracuda-Start-Time: 1444450564 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://web.cudamail.com:443/cgi-mod/mark.cgi X-ASG-Whitelist: Header =?UTF-8?B?eFwtY3VkYW1haWxcLXdoaXRlbGlzdFwtdG8=?= X-Virus-Scanned: by bsmtpd at cudamail.com X-Barracuda-BRTS-Status: 1 Cc: Ben Pfaff Subject: [ovs-dev] [PATCH 08/23] ovn-controller: Factor patch port management into new "patch" module. X-BeenThere: dev@openvswitch.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dev-bounces@openvswitch.org Sender: "dev" Upcoming patches will introduce new extensive use of patch ports and it seems reasonable to put it into its own file. This is mostly code motion. Code changes are limited to those necessary to make the separated code compile, except for renaming init_bridge_mappings() to patch_run(). Signed-off-by: Ben Pfaff --- ovn/controller/automake.mk | 2 + ovn/controller/ovn-controller.c | 213 +----------------------- ovn/controller/ovn-controller.h | 3 + ovn/controller/patch.c | 232 +++++++++++++++++++++++++++ ovn/controller/{ovn-controller.h => patch.h} | 25 ++- 5 files changed, 251 insertions(+), 224 deletions(-) create mode 100644 ovn/controller/patch.c copy ovn/controller/{ovn-controller.h => patch.h} (59%) diff --git a/ovn/controller/automake.mk b/ovn/controller/automake.mk index 9c91420..fec9bf1 100644 --- a/ovn/controller/automake.mk +++ b/ovn/controller/automake.mk @@ -10,6 +10,8 @@ ovn_controller_ovn_controller_SOURCES = \ ovn/controller/lflow.h \ ovn/controller/ofctrl.c \ ovn/controller/ofctrl.h \ + ovn/controller/patch.c \ + ovn/controller/patch.h \ ovn/controller/ovn-controller.c \ ovn/controller/ovn-controller.h \ ovn/controller/physical.c \ diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c index 0371c38..9ba5413 100644 --- a/ovn/controller/ovn-controller.c +++ b/ovn/controller/ovn-controller.c @@ -43,6 +43,7 @@ #include "binding.h" #include "chassis.h" #include "encaps.h" +#include "patch.h" #include "physical.h" #include "lflow.h" @@ -71,7 +72,7 @@ get_chassis(struct ovsdb_idl *ovnsb_idl, const char *chassis_id) return chassis_rec; } -static const struct ovsrec_bridge * +const struct ovsrec_bridge * get_bridge(struct ovsdb_idl *ovs_idl, const char *br_name) { const struct ovsrec_bridge *br; @@ -153,214 +154,6 @@ get_chassis_id(const struct ovsdb_idl *ovs_idl) return cfg ? smap_get(&cfg->external_ids, "system-id") : NULL; } -static char * -patch_port_name(const struct ovsrec_bridge *b1, const struct ovsrec_bridge *b2) -{ - return xasprintf("patch-%s-to-%s", b1->name, b2->name); -} - -/* - * Return true if the port is a patch port from b1 to b2 - */ -static bool -match_patch_port(const struct ovsrec_port *port, - const struct ovsrec_bridge *b1, - const struct ovsrec_bridge *b2) -{ - struct ovsrec_interface *iface; - size_t i; - char *peer_port_name; - bool res = false; - - peer_port_name = patch_port_name(b2, b1); - - for (i = 0; i < port->n_interfaces; i++) { - iface = port->interfaces[i]; - if (strcmp(iface->type, "patch")) { - continue; - } - const char *peer; - peer = smap_get(&iface->options, "peer"); - if (peer && !strcmp(peer, peer_port_name)) { - res = true; - break; - } - } - - free(peer_port_name); - - return res; -} - -static void -create_patch_port(struct controller_ctx *ctx, - const char *network, - const struct ovsrec_bridge *b1, - const struct ovsrec_bridge *b2) -{ - if (!ctx->ovs_idl_txn) { - return; - } - - char *port_name = patch_port_name(b1, b2); - char *peer_port_name = patch_port_name(b2, b1); - - ovsdb_idl_txn_add_comment(ctx->ovs_idl_txn, - "ovn-controller: creating patch port '%s' from '%s' to '%s'", - port_name, b1->name, b2->name); - - struct ovsrec_interface *iface; - iface = ovsrec_interface_insert(ctx->ovs_idl_txn); - ovsrec_interface_set_name(iface, port_name); - ovsrec_interface_set_type(iface, "patch"); - const struct smap options = SMAP_CONST1(&options, "peer", peer_port_name); - ovsrec_interface_set_options(iface, &options); - - struct ovsrec_port *port; - port = ovsrec_port_insert(ctx->ovs_idl_txn); - ovsrec_port_set_name(port, port_name); - ovsrec_port_set_interfaces(port, &iface, 1); - const struct smap ids = SMAP_CONST1(&ids, "ovn-patch-port", network); - ovsrec_port_set_external_ids(port, &ids); - - struct ovsrec_port **ports; - ports = xmalloc(sizeof *ports * (b1->n_ports + 1)); - memcpy(ports, b1->ports, sizeof *ports * b1->n_ports); - ports[b1->n_ports] = port; - ovsrec_bridge_verify_ports(b1); - ovsrec_bridge_set_ports(b1, ports, b1->n_ports + 1); - - free(ports); - free(port_name); - free(peer_port_name); -} - -static void -create_patch_ports(struct controller_ctx *ctx, - const char *network, - struct shash *existing_ports, - const struct ovsrec_bridge *b1, - const struct ovsrec_bridge *b2) -{ - size_t i; - - for (i = 0; i < b1->n_ports; i++) { - if (match_patch_port(b1->ports[i], b1, b2)) { - /* Patch port already exists on b1 */ - shash_find_and_delete(existing_ports, b1->ports[i]->name); - break; - } - } - if (i == b1->n_ports) { - create_patch_port(ctx, network, b1, b2); - } -} - -static void -init_existing_ports(struct controller_ctx *ctx, - struct shash *existing_ports) -{ - const struct ovsrec_port *port; - - OVSREC_PORT_FOR_EACH (port, ctx->ovs_idl) { - if (smap_get(&port->external_ids, "ovn-patch-port")) { - shash_add(existing_ports, port->name, port); - } - } -} - -static void -remove_port(struct controller_ctx *ctx, - const struct ovsrec_port *port) -{ - const struct ovsrec_bridge *bridge; - - /* We know the port we want to delete, but we have to find the bridge its on - * to do so. Note this only runs on a config change that should be pretty - * rare. */ - OVSREC_BRIDGE_FOR_EACH (bridge, ctx->ovs_idl) { - size_t i; - for (i = 0; i < bridge->n_ports; i++) { - if (bridge->ports[i] != port) { - continue; - } - struct ovsrec_port **new_ports; - new_ports = xmemdup(bridge->ports, - sizeof *new_ports * (bridge->n_ports - 1)); - if (i != bridge->n_ports - 1) { - /* Removed port was not last */ - new_ports[i] = bridge->ports[bridge->n_ports - 1]; - } - ovsrec_bridge_verify_ports(bridge); - ovsrec_bridge_set_ports(bridge, new_ports, bridge->n_ports - 1); - free(new_ports); - ovsrec_port_delete(port); - return; - } - } -} - -static void -parse_bridge_mappings(struct controller_ctx *ctx, - const struct ovsrec_bridge *br_int, - const char *mappings_cfg) -{ - struct shash existing_ports = SHASH_INITIALIZER(&existing_ports); - init_existing_ports(ctx, &existing_ports); - - char *cur, *next, *start; - next = start = xstrdup(mappings_cfg); - while ((cur = strsep(&next, ",")) && *cur) { - char *network, *bridge = cur; - const struct ovsrec_bridge *ovs_bridge; - - network = strsep(&bridge, ":"); - if (!bridge || !*network || !*bridge) { - VLOG_ERR("Invalid ovn-bridge-mappings configuration: '%s'", - mappings_cfg); - break; - } - - ovs_bridge = get_bridge(ctx->ovs_idl, bridge); - if (!ovs_bridge) { - VLOG_WARN("Bridge '%s' not found for network '%s'", - bridge, network); - continue; - } - - create_patch_ports(ctx, network, &existing_ports, br_int, ovs_bridge); - create_patch_ports(ctx, network, &existing_ports, ovs_bridge, br_int); - } - free(start); - - /* Any ports left in existing_ports are related to configuration that has - * been removed, so we should delete the ports now. */ - struct shash_node *port_node, *port_next_node; - SHASH_FOR_EACH_SAFE (port_node, port_next_node, &existing_ports) { - struct ovsrec_port *port = port_node->data; - shash_delete(&existing_ports, port_node); - remove_port(ctx, port); - } - shash_destroy(&existing_ports); -} - -static void -init_bridge_mappings(struct controller_ctx *ctx, - const struct ovsrec_bridge *br_int) -{ - const char *mappings_cfg = ""; - const struct ovsrec_open_vswitch *cfg; - - cfg = ovsrec_open_vswitch_first(ctx->ovs_idl); - if (cfg) { - mappings_cfg = smap_get(&cfg->external_ids, "ovn-bridge-mappings"); - if (!mappings_cfg) { - mappings_cfg = ""; - } - } - parse_bridge_mappings(ctx, br_int, mappings_cfg); -} - /* Retrieves the OVN Southbound remote location from the * "external-ids:ovn-remote" key in 'ovs_idl' and returns a copy of it. * @@ -464,7 +257,7 @@ main(int argc, char *argv[]) /* Map bridges to local nets from ovn-bridge-mappings */ if (br_int) { - init_bridge_mappings(&ctx, br_int); + patch_run(&ctx, br_int); } if (chassis_id) { diff --git a/ovn/controller/ovn-controller.h b/ovn/controller/ovn-controller.h index 9766bc3..b8c48ff 100644 --- a/ovn/controller/ovn-controller.h +++ b/ovn/controller/ovn-controller.h @@ -27,6 +27,9 @@ struct controller_ctx { struct ovsdb_idl_txn *ovs_idl_txn; }; +const struct ovsrec_bridge *get_bridge(struct ovsdb_idl *, + const char *br_name); + const struct sbrec_chassis *get_chassis(struct ovsdb_idl *, const char *chassis_id); diff --git a/ovn/controller/patch.c b/ovn/controller/patch.c new file mode 100644 index 0000000..0d192fa --- /dev/null +++ b/ovn/controller/patch.c @@ -0,0 +1,232 @@ +/* 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 + +#include "patch.h" + +#include "hash.h" +#include "lib/vswitch-idl.h" +#include "openvswitch/vlog.h" +#include "ovn-controller.h" + +VLOG_DEFINE_THIS_MODULE(patch); + +static char * +patch_port_name(const struct ovsrec_bridge *b1, const struct ovsrec_bridge *b2) +{ + return xasprintf("patch-%s-to-%s", b1->name, b2->name); +} + +/* + * Return true if the port is a patch port from b1 to b2 + */ +static bool +match_patch_port(const struct ovsrec_port *port, + const struct ovsrec_bridge *b1, + const struct ovsrec_bridge *b2) +{ + struct ovsrec_interface *iface; + size_t i; + char *peer_port_name; + bool res = false; + + peer_port_name = patch_port_name(b2, b1); + + for (i = 0; i < port->n_interfaces; i++) { + iface = port->interfaces[i]; + if (strcmp(iface->type, "patch")) { + continue; + } + const char *peer; + peer = smap_get(&iface->options, "peer"); + if (peer && !strcmp(peer, peer_port_name)) { + res = true; + break; + } + } + + free(peer_port_name); + + return res; +} + +static void +create_patch_port(struct controller_ctx *ctx, + const char *network, + const struct ovsrec_bridge *b1, + const struct ovsrec_bridge *b2) +{ + if (!ctx->ovs_idl_txn) { + return; + } + + char *port_name = patch_port_name(b1, b2); + char *peer_port_name = patch_port_name(b2, b1); + + ovsdb_idl_txn_add_comment(ctx->ovs_idl_txn, + "ovn-controller: creating patch port '%s' from '%s' to '%s'", + port_name, b1->name, b2->name); + + struct ovsrec_interface *iface; + iface = ovsrec_interface_insert(ctx->ovs_idl_txn); + ovsrec_interface_set_name(iface, port_name); + ovsrec_interface_set_type(iface, "patch"); + const struct smap options = SMAP_CONST1(&options, "peer", peer_port_name); + ovsrec_interface_set_options(iface, &options); + + struct ovsrec_port *port; + port = ovsrec_port_insert(ctx->ovs_idl_txn); + ovsrec_port_set_name(port, port_name); + ovsrec_port_set_interfaces(port, &iface, 1); + const struct smap ids = SMAP_CONST1(&ids, "ovn-patch-port", network); + ovsrec_port_set_external_ids(port, &ids); + + struct ovsrec_port **ports; + ports = xmalloc(sizeof *ports * (b1->n_ports + 1)); + memcpy(ports, b1->ports, sizeof *ports * b1->n_ports); + ports[b1->n_ports] = port; + ovsrec_bridge_verify_ports(b1); + ovsrec_bridge_set_ports(b1, ports, b1->n_ports + 1); + + free(ports); + free(port_name); + free(peer_port_name); +} + +static void +create_patch_ports(struct controller_ctx *ctx, + const char *network, + struct shash *existing_ports, + const struct ovsrec_bridge *b1, + const struct ovsrec_bridge *b2) +{ + size_t i; + + for (i = 0; i < b1->n_ports; i++) { + if (match_patch_port(b1->ports[i], b1, b2)) { + /* Patch port already exists on b1 */ + shash_find_and_delete(existing_ports, b1->ports[i]->name); + break; + } + } + if (i == b1->n_ports) { + create_patch_port(ctx, network, b1, b2); + } +} + +static void +init_existing_ports(struct controller_ctx *ctx, + struct shash *existing_ports) +{ + const struct ovsrec_port *port; + + OVSREC_PORT_FOR_EACH (port, ctx->ovs_idl) { + if (smap_get(&port->external_ids, "ovn-patch-port")) { + shash_add(existing_ports, port->name, port); + } + } +} + +static void +remove_port(struct controller_ctx *ctx, + const struct ovsrec_port *port) +{ + const struct ovsrec_bridge *bridge; + + /* We know the port we want to delete, but we have to find the bridge its + * on to do so. Note this only runs on a config change that should be + * pretty rare. */ + OVSREC_BRIDGE_FOR_EACH (bridge, ctx->ovs_idl) { + size_t i; + for (i = 0; i < bridge->n_ports; i++) { + if (bridge->ports[i] != port) { + continue; + } + struct ovsrec_port **new_ports; + new_ports = xmemdup(bridge->ports, + sizeof *new_ports * (bridge->n_ports - 1)); + if (i != bridge->n_ports - 1) { + /* Removed port was not last */ + new_ports[i] = bridge->ports[bridge->n_ports - 1]; + } + ovsrec_bridge_verify_ports(bridge); + ovsrec_bridge_set_ports(bridge, new_ports, bridge->n_ports - 1); + free(new_ports); + ovsrec_port_delete(port); + return; + } + } +} + +static void +parse_bridge_mappings(struct controller_ctx *ctx, + const struct ovsrec_bridge *br_int, + const char *mappings_cfg) +{ + struct shash existing_ports = SHASH_INITIALIZER(&existing_ports); + init_existing_ports(ctx, &existing_ports); + + char *cur, *next, *start; + next = start = xstrdup(mappings_cfg); + while ((cur = strsep(&next, ",")) && *cur) { + char *network, *bridge = cur; + const struct ovsrec_bridge *ovs_bridge; + + network = strsep(&bridge, ":"); + if (!bridge || !*network || !*bridge) { + VLOG_ERR("Invalid ovn-bridge-mappings configuration: '%s'", + mappings_cfg); + break; + } + + ovs_bridge = get_bridge(ctx->ovs_idl, bridge); + if (!ovs_bridge) { + VLOG_WARN("Bridge '%s' not found for network '%s'", + bridge, network); + continue; + } + + create_patch_ports(ctx, network, &existing_ports, br_int, ovs_bridge); + create_patch_ports(ctx, network, &existing_ports, ovs_bridge, br_int); + } + free(start); + + /* Any ports left in existing_ports are related to configuration that has + * been removed, so we should delete the ports now. */ + struct shash_node *port_node, *port_next_node; + SHASH_FOR_EACH_SAFE (port_node, port_next_node, &existing_ports) { + struct ovsrec_port *port = port_node->data; + shash_delete(&existing_ports, port_node); + remove_port(ctx, port); + } + shash_destroy(&existing_ports); +} + +void +patch_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int) +{ + const char *mappings_cfg = ""; + const struct ovsrec_open_vswitch *cfg; + + cfg = ovsrec_open_vswitch_first(ctx->ovs_idl); + if (cfg) { + mappings_cfg = smap_get(&cfg->external_ids, "ovn-bridge-mappings"); + if (!mappings_cfg) { + mappings_cfg = ""; + } + } + parse_bridge_mappings(ctx, br_int, mappings_cfg); +} diff --git a/ovn/controller/ovn-controller.h b/ovn/controller/patch.h similarity index 59% copy from ovn/controller/ovn-controller.h copy to ovn/controller/patch.h index 9766bc3..f7db2fc 100644 --- a/ovn/controller/ovn-controller.h +++ b/ovn/controller/patch.h @@ -13,21 +13,18 @@ * limitations under the License. */ +#ifndef OVN_PATCH_H +#define OVN_PATCH_H 1 -#ifndef OVN_CONTROLLER_H -#define OVN_CONTROLLER_H 1 - -#include "ovn/lib/ovn-sb-idl.h" - -struct controller_ctx { - struct ovsdb_idl *ovnsb_idl; - struct ovsdb_idl_txn *ovnsb_idl_txn; +/* Patch Ports + * =========== + * + * This module adds and removes patch ports between the integration bridge and + * physical bridges, as directed by other-config:ovn-bridge-mappings. */ - struct ovsdb_idl *ovs_idl; - struct ovsdb_idl_txn *ovs_idl_txn; -}; +struct controller_ctx; +struct ovsrec_bridge; -const struct sbrec_chassis *get_chassis(struct ovsdb_idl *, - const char *chassis_id); +void patch_run(struct controller_ctx *, const struct ovsrec_bridge *br_int); -#endif /* ovn/ovn-controller.h */ +#endif /* ovn/patch.h */