From patchwork Tue Jul 13 21:55:46 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Numan Siddique X-Patchwork-Id: 1504893 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GPZG75BKTz9sX1 for ; Wed, 14 Jul 2021 07:56:15 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id EAAD260A3C; Tue, 13 Jul 2021 21:56:13 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 1zNljtCHao0H; Tue, 13 Jul 2021 21:56:11 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id 9684160620; Tue, 13 Jul 2021 21:56:10 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 6B6C4C001A; Tue, 13 Jul 2021 21:56:10 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 7DADBC000E for ; Tue, 13 Jul 2021 21:56:08 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 56214606BD for ; Tue, 13 Jul 2021 21:56:08 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id AHF1ocZ9qxWC for ; Tue, 13 Jul 2021 21:56:05 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by smtp3.osuosl.org (Postfix) with ESMTPS id 4511160620 for ; Tue, 13 Jul 2021 21:56:05 +0000 (UTC) Received: (Authenticated sender: numans@ovn.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 663801BF209; Tue, 13 Jul 2021 21:56:00 +0000 (UTC) From: numans@ovn.org To: dev@openvswitch.org Date: Tue, 13 Jul 2021 17:55:46 -0400 Message-Id: <20210713215546.249089-1-numans@ovn.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210713215439.248927-1-numans@ovn.org> References: <20210713215439.248927-1-numans@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 1/5] controller: Move 'struct local_datapath' to a separate file. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Numan Siddique This would uncomplicate the binding.c code a bit. The tracking data and the related functions are also moved to the file - ldata.h. This would help in an upcoming patch. Signed-off-by: Numan Siddique --- controller/automake.mk | 4 +- controller/binding.c | 362 +++++++---------------------------- controller/binding.h | 13 -- controller/ldata.c | 367 ++++++++++++++++++++++++++++++++++++ controller/ldata.h | 118 ++++++++++++ controller/lflow.c | 1 + controller/lport.c | 40 ++++ controller/lport.h | 7 +- controller/ovn-controller.c | 48 ++--- controller/ovn-controller.h | 32 ---- controller/patch.c | 1 + controller/physical.c | 1 + controller/pinctrl.c | 1 + 13 files changed, 615 insertions(+), 380 deletions(-) create mode 100644 controller/ldata.c create mode 100644 controller/ldata.h diff --git a/controller/automake.mk b/controller/automake.mk index 2f6c50890..a3c5c6af5 100644 --- a/controller/automake.mk +++ b/controller/automake.mk @@ -33,7 +33,9 @@ controller_ovn_controller_SOURCES = \ controller/physical.c \ controller/physical.h \ controller/mac-learn.c \ - controller/mac-learn.h + controller/mac-learn.h \ + controller/ldata.c \ + controller/ldata.h controller_ovn_controller_LDADD = lib/libovn.la $(OVS_LIBDIR)/libopenvswitch.la man_MANS += controller/ovn-controller.8 diff --git a/controller/binding.c b/controller/binding.c index 70bf13390..aa38a0848 100644 --- a/controller/binding.c +++ b/controller/binding.c @@ -14,13 +14,8 @@ */ #include -#include "binding.h" -#include "ha-chassis.h" -#include "if-status.h" -#include "lflow.h" -#include "lport.h" -#include "patch.h" +/* OVS includes. */ #include "lib/bitmap.h" #include "openvswitch/poll-loop.h" #include "lib/sset.h" @@ -29,9 +24,18 @@ #include "lib/vswitch-idl.h" #include "openvswitch/hmap.h" #include "openvswitch/vlog.h" + +/* OVN includes. */ +#include "binding.h" +#include "ha-chassis.h" +#include "if-status.h" +#include "ldata.h" +#include "lflow.h" #include "lib/chassis-index.h" #include "lib/ovn-sb-idl.h" +#include "lport.h" #include "ovn-controller.h" +#include "patch.h" VLOG_DEFINE_THIS_MODULE(binding); @@ -76,105 +80,27 @@ binding_register_ovs_idl(struct ovsdb_idl *ovs_idl) ovsdb_idl_add_column(ovs_idl, &ovsrec_qos_col_type); } -static struct tracked_binding_datapath *tracked_binding_datapath_create( - const struct sbrec_datapath_binding *, - bool is_new, struct hmap *tracked_dps); -static struct tracked_binding_datapath *tracked_binding_datapath_find( - struct hmap *, const struct sbrec_datapath_binding *); -static void tracked_binding_datapath_lport_add( - const struct sbrec_port_binding *, struct hmap *tracked_datapaths); static void update_lport_tracking(const struct sbrec_port_binding *pb, - struct hmap *tracked_dp_bindings); - -static void -add_local_datapath__(struct ovsdb_idl_index *sbrec_datapath_binding_by_key, - struct ovsdb_idl_index *sbrec_port_binding_by_datapath, - struct ovsdb_idl_index *sbrec_port_binding_by_name, - const struct sbrec_datapath_binding *datapath, - bool has_local_l3gateway, int depth, - struct hmap *local_datapaths, - struct hmap *tracked_datapaths) -{ - uint32_t dp_key = datapath->tunnel_key; - struct local_datapath *ld = get_local_datapath(local_datapaths, dp_key); - if (ld) { - if (has_local_l3gateway) { - ld->has_local_l3gateway = true; - } - return; - } + struct hmap *tracked_dp_bindings, + bool claimed); - ld = xzalloc(sizeof *ld); - hmap_insert(local_datapaths, &ld->hmap_node, dp_key); - ld->datapath = datapath; - ld->localnet_port = NULL; - ld->has_local_l3gateway = has_local_l3gateway; - - if (tracked_datapaths) { - struct tracked_binding_datapath *tdp = - tracked_binding_datapath_find(tracked_datapaths, datapath); - if (!tdp) { - tracked_binding_datapath_create(datapath, true, tracked_datapaths); - } else { - /* Its possible that there is already an entry in tracked datapaths - * for this 'datapath'. tracked_binding_datapath_lport_add() may - * have created it. Since the 'datapath' is added to the - * local datapaths, set 'tdp->is_new' to true so that the flows - * for this datapath are programmed properly. - * */ - tdp->is_new = true; - } - } +struct local_datpath_added_aux { + bool has_local_l3gateway; + struct hmap *tracked_datapaths; +}; - if (depth >= 100) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); - VLOG_WARN_RL(&rl, "datapaths nested too deep"); - return; +/* This function is called by local_datapath_add() if a new local_datapath + * is created. */ +static void +local_datapath_added(struct local_datapath *ld, void *aux) +{ + struct local_datpath_added_aux *aux_ = aux; + if (aux_->tracked_datapaths) { + tracked_datapath_add(ld->datapath, TRACKED_RESOURCE_NEW, + aux_->tracked_datapaths); } - struct sbrec_port_binding *target = - sbrec_port_binding_index_init_row(sbrec_port_binding_by_datapath); - sbrec_port_binding_index_set_datapath(target, datapath); - - const struct sbrec_port_binding *pb; - SBREC_PORT_BINDING_FOR_EACH_EQUAL (pb, target, - sbrec_port_binding_by_datapath) { - if (!strcmp(pb->type, "patch") || !strcmp(pb->type, "l3gateway")) { - const char *peer_name = smap_get(&pb->options, "peer"); - if (peer_name) { - const struct sbrec_port_binding *peer; - - peer = lport_lookup_by_name(sbrec_port_binding_by_name, - peer_name); - - if (peer && peer->datapath) { - if (!strcmp(pb->type, "patch")) { - /* Add the datapath to local datapath only for patch - * ports. For l3gateway ports, since gateway router - * resides on one chassis, we don't need to add. - * Otherwise, all other chassis might create patch - * ports between br-int and the provider bridge. */ - add_local_datapath__(sbrec_datapath_binding_by_key, - sbrec_port_binding_by_datapath, - sbrec_port_binding_by_name, - peer->datapath, false, - depth + 1, local_datapaths, - tracked_datapaths); - } - ld->n_peer_ports++; - if (ld->n_peer_ports > ld->n_allocated_peer_ports) { - ld->peer_ports = - x2nrealloc(ld->peer_ports, - &ld->n_allocated_peer_ports, - sizeof *ld->peer_ports); - } - ld->peer_ports[ld->n_peer_ports - 1].local = pb; - ld->peer_ports[ld->n_peer_ports - 1].remote = peer; - } - } - } - } - sbrec_port_binding_index_destroy_row(target); + ld->has_local_l3gateway = aux_->has_local_l3gateway; } static void @@ -185,11 +111,17 @@ add_local_datapath(struct ovsdb_idl_index *sbrec_datapath_binding_by_key, bool has_local_l3gateway, struct hmap *local_datapaths, struct hmap *tracked_datapaths) { - add_local_datapath__(sbrec_datapath_binding_by_key, - sbrec_port_binding_by_datapath, - sbrec_port_binding_by_name, - datapath, has_local_l3gateway, 0, local_datapaths, - tracked_datapaths); + struct local_datpath_added_aux aux = { + .has_local_l3gateway = has_local_l3gateway, + .tracked_datapaths = tracked_datapaths, + }; + + local_datapath_add(local_datapaths, datapath, + sbrec_datapath_binding_by_key, + sbrec_port_binding_by_datapath, + sbrec_port_binding_by_name, + local_datapath_added, + &aux); } static void @@ -546,7 +478,8 @@ update_related_lport(const struct sbrec_port_binding *pb, if (b_ctx->tracked_dp_bindings) { /* Add the 'pb' to the tracked_datapaths. */ - tracked_binding_datapath_lport_add(pb, b_ctx->tracked_dp_bindings); + tracked_datapath_lport_add(pb, TRACKED_RESOURCE_NEW, + b_ctx->tracked_dp_bindings); } } sset_add(&b_ctx->related_lports->lport_names, pb->logical_port); @@ -569,7 +502,8 @@ remove_related_lport(const struct sbrec_port_binding *pb, if (b_ctx->tracked_dp_bindings) { /* Add the 'pb' to the tracked_datapaths. */ - tracked_binding_datapath_lport_add(pb, b_ctx->tracked_dp_bindings); + tracked_datapath_lport_add(pb, TRACKED_RESOURCE_REMOVED, + b_ctx->tracked_dp_bindings); } } } @@ -914,74 +848,6 @@ is_lport_vif(const struct sbrec_port_binding *pb) return !pb->type[0]; } -static struct tracked_binding_datapath * -tracked_binding_datapath_create(const struct sbrec_datapath_binding *dp, - bool is_new, - struct hmap *tracked_datapaths) -{ - struct tracked_binding_datapath *t_dp = xzalloc(sizeof *t_dp); - t_dp->dp = dp; - t_dp->is_new = is_new; - shash_init(&t_dp->lports); - hmap_insert(tracked_datapaths, &t_dp->node, uuid_hash(&dp->header_.uuid)); - return t_dp; -} - -static struct tracked_binding_datapath * -tracked_binding_datapath_find(struct hmap *tracked_datapaths, - const struct sbrec_datapath_binding *dp) -{ - struct tracked_binding_datapath *t_dp; - size_t hash = uuid_hash(&dp->header_.uuid); - HMAP_FOR_EACH_WITH_HASH (t_dp, node, hash, tracked_datapaths) { - if (uuid_equals(&t_dp->dp->header_.uuid, &dp->header_.uuid)) { - return t_dp; - } - } - - return NULL; -} - -static void -tracked_binding_datapath_lport_add(const struct sbrec_port_binding *pb, - struct hmap *tracked_datapaths) -{ - if (!tracked_datapaths) { - return; - } - - struct tracked_binding_datapath *tracked_dp = - tracked_binding_datapath_find(tracked_datapaths, pb->datapath); - if (!tracked_dp) { - tracked_dp = tracked_binding_datapath_create(pb->datapath, false, - tracked_datapaths); - } - - /* Check if the lport is already present or not. - * If it is already present, then just update the 'pb' field. */ - struct tracked_binding_lport *lport = - shash_find_data(&tracked_dp->lports, pb->logical_port); - - if (!lport) { - lport = xmalloc(sizeof *lport); - shash_add(&tracked_dp->lports, pb->logical_port, lport); - } - - lport->pb = pb; -} - -void -binding_tracked_dp_destroy(struct hmap *tracked_datapaths) -{ - struct tracked_binding_datapath *t_dp; - HMAP_FOR_EACH_POP (t_dp, node, tracked_datapaths) { - shash_destroy_free_data(&t_dp->lports); - free(t_dp); - } - - hmap_destroy(tracked_datapaths); -} - static enum en_lport_type get_lport_type(const struct sbrec_port_binding *pb) { @@ -1116,7 +982,7 @@ claim_lport(const struct sbrec_port_binding *pb, sbrec_port_binding_set_chassis(pb, chassis_rec); if (tracked_datapaths) { - update_lport_tracking(pb, tracked_datapaths); + update_lport_tracking(pb, tracked_datapaths, true); } } @@ -1165,7 +1031,7 @@ release_lport(const struct sbrec_port_binding *pb, bool sb_readonly, sbrec_port_binding_set_virtual_parent(pb, NULL); } - update_lport_tracking(pb, tracked_datapaths); + update_lport_tracking(pb, tracked_datapaths, false); if_status_mgr_release_iface(if_mgr, pb->logical_port); VLOG_INFO("Releasing lport %s from this chassis.", pb->logical_port); return true; @@ -1802,42 +1668,6 @@ binding_cleanup(struct ovsdb_idl_txn *ovnsb_idl_txn, return !any_changes; } -static const struct sbrec_port_binding * -get_peer_lport__(const struct sbrec_port_binding *pb, - struct binding_ctx_in *b_ctx_in) -{ - const char *peer_name = smap_get(&pb->options, "peer"); - - if (!peer_name) { - return NULL; - } - - const struct sbrec_port_binding *peer; - peer = lport_lookup_by_name(b_ctx_in->sbrec_port_binding_by_name, - peer_name); - return (peer && peer->datapath) ? peer : NULL; -} - -static const struct sbrec_port_binding * -get_l3gw_peer_lport(const struct sbrec_port_binding *pb, - struct binding_ctx_in *b_ctx_in) -{ - if (strcmp(pb->type, "l3gateway")) { - return NULL; - } - return get_peer_lport__(pb, b_ctx_in); -} - -static const struct sbrec_port_binding * -get_peer_lport(const struct sbrec_port_binding *pb, - struct binding_ctx_in *b_ctx_in) -{ - if (strcmp(pb->type, "patch")) { - return NULL; - } - return get_peer_lport__(pb, b_ctx_in); -} - /* This function adds the local datapath of the 'peer' of * lport 'pb' to the local datapaths if it is not yet added. */ @@ -1847,61 +1677,16 @@ add_local_datapath_peer_port(const struct sbrec_port_binding *pb, struct binding_ctx_out *b_ctx_out, struct local_datapath *ld) { - const struct sbrec_port_binding *peer; - peer = get_peer_lport(pb, b_ctx_in); - - if (!peer) { - return; - } - - bool present = false; - for (size_t i = 0; i < ld->n_peer_ports; i++) { - if (ld->peer_ports[i].local == pb) { - present = true; - break; - } - } - - if (!present) { - ld->n_peer_ports++; - if (ld->n_peer_ports > ld->n_allocated_peer_ports) { - ld->peer_ports = - x2nrealloc(ld->peer_ports, - &ld->n_allocated_peer_ports, - sizeof *ld->peer_ports); - } - ld->peer_ports[ld->n_peer_ports - 1].local = pb; - ld->peer_ports[ld->n_peer_ports - 1].remote = peer; - } - - struct local_datapath *peer_ld = - get_local_datapath(b_ctx_out->local_datapaths, - peer->datapath->tunnel_key); - if (!peer_ld) { - add_local_datapath__(b_ctx_in->sbrec_datapath_binding_by_key, - b_ctx_in->sbrec_port_binding_by_datapath, - b_ctx_in->sbrec_port_binding_by_name, - peer->datapath, false, - 1, b_ctx_out->local_datapaths, - b_ctx_out->tracked_dp_bindings); - return; - } - - for (size_t i = 0; i < peer_ld->n_peer_ports; i++) { - if (peer_ld->peer_ports[i].local == peer) { - return; - } - } + struct local_datpath_added_aux aux = { + .has_local_l3gateway = false, + .tracked_datapaths = b_ctx_out->tracked_dp_bindings, + }; - peer_ld->n_peer_ports++; - if (peer_ld->n_peer_ports > peer_ld->n_allocated_peer_ports) { - peer_ld->peer_ports = - x2nrealloc(peer_ld->peer_ports, - &peer_ld->n_allocated_peer_ports, - sizeof *peer_ld->peer_ports); - } - peer_ld->peer_ports[peer_ld->n_peer_ports - 1].local = peer; - peer_ld->peer_ports[peer_ld->n_peer_ports - 1].remote = pb; + local_datapath_add_peer_port(pb, b_ctx_in->sbrec_datapath_binding_by_key, + b_ctx_in->sbrec_port_binding_by_datapath, + b_ctx_in->sbrec_port_binding_by_name, + ld, b_ctx_out->local_datapaths, + local_datapath_added, &aux); } static void @@ -1909,34 +1694,7 @@ remove_local_datapath_peer_port(const struct sbrec_port_binding *pb, struct local_datapath *ld, struct hmap *local_datapaths) { - size_t i = 0; - for (i = 0; i < ld->n_peer_ports; i++) { - if (ld->peer_ports[i].local == pb) { - break; - } - } - - if (i == ld->n_peer_ports) { - return; - } - - const struct sbrec_port_binding *peer = ld->peer_ports[i].remote; - - /* Possible improvement: We can shrink the allocated peer ports - * if (ld->n_peer_ports < ld->n_allocated_peer_ports / 2). - */ - ld->peer_ports[i].local = ld->peer_ports[ld->n_peer_ports - 1].local; - ld->peer_ports[i].remote = ld->peer_ports[ld->n_peer_ports - 1].remote; - ld->n_peer_ports--; - - struct local_datapath *peer_ld = - get_local_datapath(local_datapaths, peer->datapath->tunnel_key); - if (peer_ld) { - /* Remove the peer port from the peer datapath. The peer - * datapath also tries to remove its peer lport, but that would - * be no-op. */ - remove_local_datapath_peer_port(peer, peer_ld, local_datapaths); - } + local_datapath_remove_peer_port(pb, ld, local_datapaths); } static void @@ -1967,13 +1725,16 @@ remove_pb_from_local_datapath(const struct sbrec_port_binding *pb, static void update_lport_tracking(const struct sbrec_port_binding *pb, - struct hmap *tracked_dp_bindings) + struct hmap *tracked_dp_bindings, + bool claimed) { if (!tracked_dp_bindings) { return; } - tracked_binding_datapath_lport_add(pb, tracked_dp_bindings); + tracked_datapath_lport_add( + pb, claimed ? TRACKED_RESOURCE_NEW : TRACKED_RESOURCE_REMOVED, + tracked_dp_bindings); } /* Considers the ovs iface 'iface_rec' for claiming. @@ -2287,7 +2048,7 @@ handle_deleted_lport(const struct sbrec_port_binding *pb, /* If the binding is not local, if 'pb' is a L3 gateway port, we should * remove its peer, if that one is local. */ - pb = get_l3gw_peer_lport(pb, b_ctx_in); + pb = lport_get_l3gw_peer(pb, b_ctx_in->sbrec_port_binding_by_name); if (pb) { ld = get_local_datapath(b_ctx_out->local_datapaths, pb->datapath->tunnel_key); @@ -2570,7 +2331,10 @@ delete_done: * */ const struct sbrec_port_binding *peer; struct local_datapath *peer_ld = NULL; - peer = get_peer_lport(pb, b_ctx_in); + peer = + lport_get_peer(pb, + b_ctx_in->sbrec_port_binding_by_name); + if (peer) { peer_ld = get_local_datapath(b_ctx_out->local_datapaths, diff --git a/controller/binding.h b/controller/binding.h index 77197e742..b1717bd2b 100644 --- a/controller/binding.h +++ b/controller/binding.h @@ -121,19 +121,6 @@ void local_binding_set_up(struct shash *local_bindings, const char *pb_name, void local_binding_set_down(struct shash *local_bindings, const char *pb_name, bool sb_readonly, bool ovs_readonly); -/* Represents a tracked binding logical port. */ -struct tracked_binding_lport { - const struct sbrec_port_binding *pb; -}; - -/* Represent a tracked binding datapath. */ -struct tracked_binding_datapath { - struct hmap_node node; - const struct sbrec_datapath_binding *dp; - bool is_new; - struct shash lports; /* shash of struct tracked_binding_lport. */ -}; - void binding_register_ovs_idl(struct ovsdb_idl *); void binding_run(struct binding_ctx_in *, struct binding_ctx_out *); bool binding_cleanup(struct ovsdb_idl_txn *ovnsb_idl_txn, diff --git a/controller/ldata.c b/controller/ldata.c new file mode 100644 index 000000000..fe19eaf39 --- /dev/null +++ b/controller/ldata.c @@ -0,0 +1,367 @@ +/* Copyright (c) 2021, Red Hat, 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 + +/* OVS includes. */ +#include "include/openvswitch/json.h" +#include "lib/hmapx.h" +#include "lib/util.h" +#include "openvswitch/vlog.h" + +/* OVN includes. */ +#include "ldata.h" +#include "lport.h" +#include "lib/ovn-util.h" +#include "lib/ovn-sb-idl.h" + +VLOG_DEFINE_THIS_MODULE(ldata); + +static struct local_datapath *local_datapath_add__( + struct hmap *local_datapaths, + const struct sbrec_datapath_binding *, + struct ovsdb_idl_index *sbrec_datapath_binding_by_key, + struct ovsdb_idl_index *sbrec_port_binding_by_datapath, + struct ovsdb_idl_index *sbrec_port_binding_by_name, + int depth, + void (*datapath_added)(struct local_datapath *, + void *aux), + void *aux); + +static struct tracked_datapath *tracked_datapath_create( + const struct sbrec_datapath_binding *dp, + enum en_tracked_resource_type tracked_type, + struct hmap *tracked_datapaths); + +struct local_datapath * +get_local_datapath(const struct hmap *local_datapaths, uint32_t tunnel_key) +{ + struct hmap_node *node = hmap_first_with_hash(local_datapaths, tunnel_key); + return (node + ? CONTAINER_OF(node, struct local_datapath, hmap_node) + : NULL); +} + +struct local_datapath * +local_datapath_alloc(const struct sbrec_datapath_binding *dp) +{ + struct local_datapath *ld = xzalloc(sizeof *ld); + ld->datapath = dp; + ld->is_switch = datapath_is_switch(dp); + + return ld; +} + +void +local_datapaths_destroy(struct hmap *local_datapaths) +{ + struct local_datapath *ld; + HMAP_FOR_EACH_POP (ld, hmap_node, local_datapaths) { + local_datapath_destroy(ld); + } + + hmap_destroy(local_datapaths); +} + +void +local_datapath_destroy(struct local_datapath *ld) +{ + free(ld->peer_ports); + free(ld); +} + +void +local_datapath_add(struct hmap *local_datapaths, + const struct sbrec_datapath_binding *dp, + struct ovsdb_idl_index *sbrec_datapath_binding_by_key, + struct ovsdb_idl_index *sbrec_port_binding_by_datapath, + struct ovsdb_idl_index *sbrec_port_binding_by_name, + void (*datapath_added_cb)( + struct local_datapath *ld, + void *aux), + void *aux) +{ + local_datapath_add__(local_datapaths, dp, sbrec_datapath_binding_by_key, + sbrec_port_binding_by_datapath, + sbrec_port_binding_by_name, 0, + datapath_added_cb, aux); +} + +void +local_datapath_add_peer_port( + const struct sbrec_port_binding *pb, + struct ovsdb_idl_index *sbrec_datapath_binding_by_key, + struct ovsdb_idl_index *sbrec_port_binding_by_datapath, + struct ovsdb_idl_index *sbrec_port_binding_by_name, + struct local_datapath *ld, + struct hmap *local_datapaths, + void (*datapath_added_cb)( + struct local_datapath *ld, + void *aux), + void *aux) +{ + const struct sbrec_port_binding *peer; + peer = lport_get_peer(pb, sbrec_port_binding_by_name); + + if (!peer) { + return; + } + + bool present = false; + for (size_t i = 0; i < ld->n_peer_ports; i++) { + if (ld->peer_ports[i].local == pb) { + present = true; + break; + } + } + + if (!present) { + ld->n_peer_ports++; + if (ld->n_peer_ports > ld->n_allocated_peer_ports) { + ld->peer_ports = + x2nrealloc(ld->peer_ports, + &ld->n_allocated_peer_ports, + sizeof *ld->peer_ports); + } + ld->peer_ports[ld->n_peer_ports - 1].local = pb; + ld->peer_ports[ld->n_peer_ports - 1].remote = peer; + } + + struct local_datapath *peer_ld = + get_local_datapath(local_datapaths, + peer->datapath->tunnel_key); + if (!peer_ld) { + local_datapath_add__(local_datapaths, peer->datapath, + sbrec_datapath_binding_by_key, + sbrec_port_binding_by_datapath, + sbrec_port_binding_by_name, 1, + datapath_added_cb, aux); + return; + } + + for (size_t i = 0; i < peer_ld->n_peer_ports; i++) { + if (peer_ld->peer_ports[i].local == peer) { + return; + } + } + + peer_ld->n_peer_ports++; + if (peer_ld->n_peer_ports > peer_ld->n_allocated_peer_ports) { + peer_ld->peer_ports = + x2nrealloc(peer_ld->peer_ports, + &peer_ld->n_allocated_peer_ports, + sizeof *peer_ld->peer_ports); + } + peer_ld->peer_ports[peer_ld->n_peer_ports - 1].local = peer; + peer_ld->peer_ports[peer_ld->n_peer_ports - 1].remote = pb; +} + +void +local_datapath_remove_peer_port(const struct sbrec_port_binding *pb, + struct local_datapath *ld, + struct hmap *local_datapaths) +{ + size_t i = 0; + for (i = 0; i < ld->n_peer_ports; i++) { + if (ld->peer_ports[i].local == pb) { + break; + } + } + + if (i == ld->n_peer_ports) { + return; + } + + const struct sbrec_port_binding *peer = ld->peer_ports[i].remote; + + /* Possible improvement: We can shrink the allocated peer ports + * if (ld->n_peer_ports < ld->n_allocated_peer_ports / 2). + */ + ld->peer_ports[i].local = ld->peer_ports[ld->n_peer_ports - 1].local; + ld->peer_ports[i].remote = ld->peer_ports[ld->n_peer_ports - 1].remote; + ld->n_peer_ports--; + + struct local_datapath *peer_ld = + get_local_datapath(local_datapaths, peer->datapath->tunnel_key); + if (peer_ld) { + /* Remove the peer port from the peer datapath. The peer + * datapath also tries to remove its peer lport, but that would + * be no-op. */ + local_datapath_remove_peer_port(peer, peer_ld, local_datapaths); + } +} + +/* track datapath functions. */ +struct tracked_datapath * +tracked_datapath_add(const struct sbrec_datapath_binding *dp, + enum en_tracked_resource_type tracked_type, + struct hmap *tracked_datapaths) +{ + struct tracked_datapath *t_dp = + tracked_datapath_find(tracked_datapaths, dp); + if (!t_dp) { + t_dp = tracked_datapath_create(dp, tracked_type, tracked_datapaths); + } else { + t_dp->tracked_type = tracked_type; + } + + return t_dp; +} + +struct tracked_datapath * +tracked_datapath_find(struct hmap *tracked_datapaths, + const struct sbrec_datapath_binding *dp) +{ + struct tracked_datapath *t_dp; + size_t hash = uuid_hash(&dp->header_.uuid); + HMAP_FOR_EACH_WITH_HASH (t_dp, node, hash, tracked_datapaths) { + if (uuid_equals(&t_dp->dp->header_.uuid, &dp->header_.uuid)) { + return t_dp; + } + } + + return NULL; +} + +void +tracked_datapath_lport_add(const struct sbrec_port_binding *pb, + enum en_tracked_resource_type tracked_type, + struct hmap *tracked_datapaths) +{ + struct tracked_datapath *tracked_dp = + tracked_datapath_find(tracked_datapaths, pb->datapath); + if (!tracked_dp) { + tracked_dp = tracked_datapath_create(pb->datapath, + TRACKED_RESOURCE_UPDATED, + tracked_datapaths); + } + + /* Check if the lport is already present or not. + * If it is already present, then just update the 'pb' field. */ + struct tracked_lport *lport = + shash_find_data(&tracked_dp->lports, pb->logical_port); + + if (!lport) { + lport = xmalloc(sizeof *lport); + shash_add(&tracked_dp->lports, pb->logical_port, lport); + } + + lport->pb = pb; + lport->tracked_type = tracked_type; +} + +void +tracked_datapaths_destroy(struct hmap *tracked_datapaths) +{ + struct tracked_datapath *t_dp; + HMAP_FOR_EACH_POP (t_dp, node, tracked_datapaths) { + shash_destroy_free_data(&t_dp->lports); + free(t_dp); + } + + hmap_destroy(tracked_datapaths); +} + +/* static functions. */ +static struct local_datapath * +local_datapath_add__(struct hmap *local_datapaths, + const struct sbrec_datapath_binding *dp, + struct ovsdb_idl_index *sbrec_datapath_binding_by_key, + struct ovsdb_idl_index *sbrec_port_binding_by_datapath, + struct ovsdb_idl_index *sbrec_port_binding_by_name, + int depth, + void (*datapath_added_cb)( + struct local_datapath *ld, + void *aux), + void *aux) +{ + uint32_t dp_key = dp->tunnel_key; + struct local_datapath *ld = get_local_datapath(local_datapaths, dp_key); + if (ld) { + return ld; + } + + ld = local_datapath_alloc(dp); + hmap_insert(local_datapaths, &ld->hmap_node, dp_key); + ld->datapath = dp; + + if (datapath_added_cb) { + datapath_added_cb(ld, aux); + } + + if (depth >= 100) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_WARN_RL(&rl, "datapaths nested too deep"); + return ld; + } + + struct sbrec_port_binding *target = + sbrec_port_binding_index_init_row(sbrec_port_binding_by_datapath); + sbrec_port_binding_index_set_datapath(target, dp); + + const struct sbrec_port_binding *pb; + SBREC_PORT_BINDING_FOR_EACH_EQUAL (pb, target, + sbrec_port_binding_by_datapath) { + if (!strcmp(pb->type, "patch") || !strcmp(pb->type, "l3gateway")) { + const char *peer_name = smap_get(&pb->options, "peer"); + if (peer_name) { + const struct sbrec_port_binding *peer; + + peer = lport_lookup_by_name(sbrec_port_binding_by_name, + peer_name); + + if (peer && peer->datapath) { + if (!strcmp(pb->type, "patch")) { + /* Add the datapath to local datapath only for patch + * ports. For l3gateway ports, since gateway router + * resides on one chassis, we don't need to add. + * Otherwise, all other chassis might create patch + * ports between br-int and the provider bridge. */ + local_datapath_add__(local_datapaths, peer->datapath, + sbrec_datapath_binding_by_key, + sbrec_port_binding_by_datapath, + sbrec_port_binding_by_name, + depth + 1, datapath_added_cb, + aux); + } + ld->n_peer_ports++; + if (ld->n_peer_ports > ld->n_allocated_peer_ports) { + ld->peer_ports = + x2nrealloc(ld->peer_ports, + &ld->n_allocated_peer_ports, + sizeof *ld->peer_ports); + } + ld->peer_ports[ld->n_peer_ports - 1].local = pb; + ld->peer_ports[ld->n_peer_ports - 1].remote = peer; + } + } + } + } + sbrec_port_binding_index_destroy_row(target); + return ld; +} + +static struct tracked_datapath * +tracked_datapath_create(const struct sbrec_datapath_binding *dp, + enum en_tracked_resource_type tracked_type, + struct hmap *tracked_datapaths) +{ + struct tracked_datapath *t_dp = xzalloc(sizeof *t_dp); + t_dp->dp = dp; + t_dp->tracked_type = tracked_type; + shash_init(&t_dp->lports); + hmap_insert(tracked_datapaths, &t_dp->node, uuid_hash(&dp->header_.uuid)); + return t_dp; +} diff --git a/controller/ldata.h b/controller/ldata.h new file mode 100644 index 000000000..dec5ed760 --- /dev/null +++ b/controller/ldata.h @@ -0,0 +1,118 @@ +/* Copyright (c) 2021, Red Hat, 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 LDATA_H +#define LDATA_H 1 + +/* OVS includes. */ +#include "include/openvswitch/shash.h" +#include "lib/smap.h" + +struct sbrec_datapath_binding; +struct sbrec_port_binding; +struct ovsdb_idl_index; + +/* A logical datapath that has some relevance to this hypervisor. A logical + * datapath D is relevant to hypervisor H if: + * + * - Some VIF or l2gateway or l3gateway port in D is located on H. + * + * - D is reachable over a series of hops across patch ports, starting from + * a datapath relevant to H. + * + * The 'hmap_node''s hash value is 'datapath->tunnel_key'. */ +struct local_datapath { + struct hmap_node hmap_node; + const struct sbrec_datapath_binding *datapath; + bool is_switch; + + /* The localnet port in this datapath, if any (at most one is allowed). */ + const struct sbrec_port_binding *localnet_port; + + /* True if this datapath contains an l3gateway port located on this + * hypervisor. */ + bool has_local_l3gateway; + + struct { + const struct sbrec_port_binding *local; + const struct sbrec_port_binding *remote; + } *peer_ports; + + size_t n_peer_ports; + size_t n_allocated_peer_ports; +}; + +struct local_datapath *local_datapath_alloc( + const struct sbrec_datapath_binding *); +struct local_datapath *get_local_datapath(const struct hmap *, + uint32_t tunnel_key); +void local_datapath_add(struct hmap *local_datapaths, + const struct sbrec_datapath_binding *, + struct ovsdb_idl_index *sbrec_datapath_binding_by_key, + struct ovsdb_idl_index *sbrec_port_binding_by_datapath, + struct ovsdb_idl_index *sbrec_port_binding_by_name, + void (*datapath_added)(struct local_datapath *, + void *aux), + void *aux); + +void local_datapaths_destroy(struct hmap *local_datapaths); +void local_datapath_destroy(struct local_datapath *ld); +void local_datapath_add_peer_port( + const struct sbrec_port_binding *pb, + struct ovsdb_idl_index *sbrec_datapath_binding_by_key, + struct ovsdb_idl_index *sbrec_port_binding_by_datapath, + struct ovsdb_idl_index *sbrec_port_binding_by_name, + struct local_datapath *ld, + struct hmap *local_datapaths, + void (*datapath_added_cb)( + struct local_datapath *ld, + void *aux), + void *aux); + +void local_datapath_remove_peer_port(const struct sbrec_port_binding *pb, + struct local_datapath *ld, + struct hmap *local_datapaths); + +enum en_tracked_resource_type { + TRACKED_RESOURCE_NEW, + TRACKED_RESOURCE_REMOVED, + TRACKED_RESOURCE_UPDATED +}; + +/* Represents a tracked logical port. */ +struct tracked_lport { + const struct sbrec_port_binding *pb; + enum en_tracked_resource_type tracked_type; +}; + +/* Represent a tracked datapath. */ +struct tracked_datapath { + struct hmap_node node; + const struct sbrec_datapath_binding *dp; + enum en_tracked_resource_type tracked_type; + struct shash lports; /* shash of struct tracked_binding_lport. */ +}; + +struct tracked_datapath * tracked_datapath_add( + const struct sbrec_datapath_binding *, enum en_tracked_resource_type, + struct hmap *tracked_datapaths); +struct tracked_datapath *tracked_datapath_find( + struct hmap *tracked_datapaths, const struct sbrec_datapath_binding *); +void tracked_datapath_lport_add(const struct sbrec_port_binding *, + enum en_tracked_resource_type, + struct hmap *tracked_datapaths); +void tracked_datapaths_destroy(struct hmap *tracked_datapaths); + +#endif /* controller/ldata.h */ diff --git a/controller/lflow.c b/controller/lflow.c index c58c4f25c..d1f32077b 100644 --- a/controller/lflow.c +++ b/controller/lflow.c @@ -17,6 +17,7 @@ #include "lflow.h" #include "coverage.h" #include "ha-chassis.h" +#include "ldata.h" #include "lflow-cache.h" #include "lport.h" #include "ofctrl.h" diff --git a/controller/lport.c b/controller/lport.c index 478fcfd82..25b4ef200 100644 --- a/controller/lport.c +++ b/controller/lport.c @@ -23,6 +23,10 @@ #include "lib/ovn-sb-idl.h" VLOG_DEFINE_THIS_MODULE(lport); +static const struct sbrec_port_binding *get_peer_lport( + const struct sbrec_port_binding *pb, + struct ovsdb_idl_index *sbrec_port_binding_by_name); + const struct sbrec_port_binding * lport_lookup_by_name(struct ovsdb_idl_index *sbrec_port_binding_by_name, const char *name) @@ -84,6 +88,26 @@ lport_is_chassis_resident(struct ovsdb_idl_index *sbrec_port_binding_by_name, } } +const struct sbrec_port_binding * +lport_get_peer(const struct sbrec_port_binding *pb, + struct ovsdb_idl_index *sbrec_port_binding_by_name) +{ + if (strcmp(pb->type, "patch")) { + return NULL; + } + return get_peer_lport(pb, sbrec_port_binding_by_name); +} + +const struct sbrec_port_binding * +lport_get_l3gw_peer(const struct sbrec_port_binding *pb, + struct ovsdb_idl_index *sbrec_port_binding_by_name) +{ + if (strcmp(pb->type, "l3gateway")) { + return NULL; + } + return get_peer_lport(pb, sbrec_port_binding_by_name); +} + const struct sbrec_datapath_binding * datapath_lookup_by_key(struct ovsdb_idl_index *sbrec_datapath_binding_by_key, uint64_t dp_key) @@ -120,3 +144,19 @@ mcgroup_lookup_by_dp_name( return retval; } + +static const struct sbrec_port_binding * +get_peer_lport(const struct sbrec_port_binding *pb, + struct ovsdb_idl_index *sbrec_port_binding_by_name) +{ + const char *peer_name = smap_get(&pb->options, "peer"); + + if (!peer_name) { + return NULL; + } + + const struct sbrec_port_binding *peer; + peer = lport_lookup_by_name(sbrec_port_binding_by_name, + peer_name); + return (peer && peer->datapath) ? peer : NULL; +} diff --git a/controller/lport.h b/controller/lport.h index 345efc184..43b3d714d 100644 --- a/controller/lport.h +++ b/controller/lport.h @@ -54,5 +54,10 @@ lport_is_chassis_resident(struct ovsdb_idl_index *sbrec_port_binding_by_name, const struct sbrec_chassis *chassis, const struct sset *active_tunnels, const char *port_name); - +const struct sbrec_port_binding *lport_get_peer( + const struct sbrec_port_binding *, + struct ovsdb_idl_index *sbrec_port_binding_by_name); +const struct sbrec_port_binding *lport_get_l3gw_peer( + const struct sbrec_port_binding *, + struct ovsdb_idl_index *sbrec_port_binding_by_name); #endif /* controller/lport.h */ diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 54304d788..8f620e4ad 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -39,6 +39,7 @@ #include "lflow.h" #include "lflow-cache.h" #include "lib/vswitch-idl.h" +#include "ldata.h" #include "lport.h" #include "memory.h" #include "ofctrl.h" @@ -131,15 +132,6 @@ struct pending_pkt { /* Registered ofctrl seqno type for nb_cfg propagation. */ static size_t ofctrl_seq_type_nb_cfg; -struct local_datapath * -get_local_datapath(const struct hmap *local_datapaths, uint32_t tunnel_key) -{ - struct hmap_node *node = hmap_first_with_hash(local_datapaths, tunnel_key); - return (node - ? CONTAINER_OF(node, struct local_datapath, hmap_node) - : NULL); -} - uint32_t get_tunnel_type(const char *name) { @@ -1067,8 +1059,8 @@ struct ed_type_runtime_data { * * ------------------------------------------------------------------------ * | | This is a hmap of | - * | | 'struct tracked_binding_datapath' defined in | - * | | binding.h. Runtime data handlers for OVS | + * | | 'struct tracked_datapath' defined in | + * | | ldata.h. Runtime data handlers for OVS | * | | Interface and Port Binding changes store the | * | @tracked_dp_bindings | changed datapaths (datapaths added/removed from | * | | local_datapaths) and changed port bindings | @@ -1126,7 +1118,7 @@ en_runtime_data_clear_tracked_data(void *data_) { struct ed_type_runtime_data *data = data_; - binding_tracked_dp_destroy(&data->tracked_dp_bindings); + tracked_datapaths_destroy(&data->tracked_dp_bindings); hmap_init(&data->tracked_dp_bindings); data->local_lports_changed = false; data->tracked = false; @@ -1164,14 +1156,7 @@ en_runtime_data_cleanup(void *data) sset_destroy(&rt_data->active_tunnels); sset_destroy(&rt_data->egress_ifaces); smap_destroy(&rt_data->local_iface_ids); - struct local_datapath *cur_node, *next_node; - HMAP_FOR_EACH_SAFE (cur_node, next_node, hmap_node, - &rt_data->local_datapaths) { - free(cur_node->peer_ports); - hmap_remove(&rt_data->local_datapaths, &cur_node->hmap_node); - free(cur_node); - } - hmap_destroy(&rt_data->local_datapaths); + local_datapaths_destroy(&rt_data->local_datapaths); shash_destroy_free_data(&rt_data->local_active_ports_ipv6_pd); shash_destroy_free_data(&rt_data->local_active_ports_ras); local_binding_data_destroy(&rt_data->lbinding_data); @@ -1283,13 +1268,7 @@ en_runtime_data_run(struct engine_node *node, void *data) /* don't cleanup since there is no data yet */ first_run = false; } else { - struct local_datapath *cur_node, *next_node; - HMAP_FOR_EACH_SAFE (cur_node, next_node, hmap_node, local_datapaths) { - free(cur_node->peer_ports); - hmap_remove(local_datapaths, &cur_node->hmap_node); - free(cur_node); - } - hmap_clear(local_datapaths); + local_datapaths_destroy(local_datapaths); shash_clear_free_data(local_active_ipv6_pd); shash_clear_free_data(local_active_ras); local_binding_data_destroy(&rt_data->lbinding_data); @@ -1298,6 +1277,7 @@ en_runtime_data_run(struct engine_node *node, void *data) sset_destroy(active_tunnels); sset_destroy(&rt_data->egress_ifaces); smap_destroy(&rt_data->local_iface_ids); + hmap_init(local_datapaths); sset_init(local_lports); related_lports_init(&rt_data->related_lports); sset_init(active_tunnels); @@ -1739,12 +1719,12 @@ port_groups_runtime_data_handler(struct engine_node *node, void *data) pg_sb->name); ovs_assert(pg_lports); - struct tracked_binding_datapath *tdp; + struct tracked_datapath *tdp; bool need_update = false; HMAP_FOR_EACH (tdp, node, &rt_data->tracked_dp_bindings) { struct shash_node *shash_node; SHASH_FOR_EACH (shash_node, &tdp->lports) { - struct tracked_binding_lport *lport = shash_node->data; + struct tracked_lport *lport = shash_node->data; if (sset_contains(pg_lports, lport->pb->logical_port)) { /* At least one local port-binding change is related to the * port_group, so the port_group_cs_local needs update. */ @@ -1897,9 +1877,9 @@ ct_zones_runtime_data_handler(struct engine_node *node, void *data OVS_UNUSED) } struct hmap *tracked_dp_bindings = &rt_data->tracked_dp_bindings; - struct tracked_binding_datapath *tdp; + struct tracked_datapath *tdp; HMAP_FOR_EACH (tdp, node, tracked_dp_bindings) { - if (tdp->is_new) { + if (tdp->tracked_type == TRACKED_RESOURCE_NEW) { /* A new datapath has been added. Fall back to full recompute. */ return false; } @@ -2421,9 +2401,9 @@ lflow_output_runtime_data_handler(struct engine_node *node, struct ed_type_lflow_output *fo = data; init_lflow_ctx(node, rt_data, fo, &l_ctx_in, &l_ctx_out); - struct tracked_binding_datapath *tdp; + struct tracked_datapath *tdp; HMAP_FOR_EACH (tdp, node, tracked_dp_bindings) { - if (tdp->is_new) { + if (tdp->tracked_type == TRACKED_RESOURCE_NEW) { if (!lflow_add_flows_for_datapath(tdp->dp, &l_ctx_in, &l_ctx_out)) { return false; @@ -2431,7 +2411,7 @@ lflow_output_runtime_data_handler(struct engine_node *node, } else { struct shash_node *shash_node; SHASH_FOR_EACH (shash_node, &tdp->lports) { - struct tracked_binding_lport *lport = shash_node->data; + struct tracked_lport *lport = shash_node->data; if (!lflow_handle_flows_for_lport(lport->pb, &l_ctx_in, &l_ctx_out)) { return false; diff --git a/controller/ovn-controller.h b/controller/ovn-controller.h index 417c7aacb..578588305 100644 --- a/controller/ovn-controller.h +++ b/controller/ovn-controller.h @@ -40,38 +40,6 @@ struct ct_zone_pending_entry { enum ct_zone_pending_state state; }; -/* A logical datapath that has some relevance to this hypervisor. A logical - * datapath D is relevant to hypervisor H if: - * - * - Some VIF or l2gateway or l3gateway port in D is located on H. - * - * - D is reachable over a series of hops across patch ports, starting from - * a datapath relevant to H. - * - * The 'hmap_node''s hash value is 'datapath->tunnel_key'. */ -struct local_datapath { - struct hmap_node hmap_node; - const struct sbrec_datapath_binding *datapath; - - /* The localnet port in this datapath, if any (at most one is allowed). */ - const struct sbrec_port_binding *localnet_port; - - /* True if this datapath contains an l3gateway port located on this - * hypervisor. */ - bool has_local_l3gateway; - - struct { - const struct sbrec_port_binding *local; - const struct sbrec_port_binding *remote; - } *peer_ports; - - size_t n_peer_ports; - size_t n_allocated_peer_ports; -}; - -struct local_datapath *get_local_datapath(const struct hmap *, - uint32_t tunnel_key); - const struct ovsrec_bridge *get_bridge(const struct ovsrec_bridge_table *, const char *br_name); diff --git a/controller/patch.c b/controller/patch.c index e54b56354..99a095c57 100644 --- a/controller/patch.c +++ b/controller/patch.c @@ -18,6 +18,7 @@ #include "patch.h" #include "hash.h" +#include "ldata.h" #include "lflow.h" #include "lib/vswitch-idl.h" #include "lport.h" diff --git a/controller/physical.c b/controller/physical.c index 17ca5afbb..a0f733f14 100644 --- a/controller/physical.c +++ b/controller/physical.c @@ -20,6 +20,7 @@ #include "encaps.h" #include "flow.h" #include "ha-chassis.h" +#include "ldata.h" #include "lflow.h" #include "lport.h" #include "chassis.h" diff --git a/controller/pinctrl.c b/controller/pinctrl.c index 8e4c4d18c..e2d892aab 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -25,6 +25,7 @@ #include "encaps.h" #include "flow.h" #include "ha-chassis.h" +#include "ldata.h" #include "lport.h" #include "mac-learn.h" #include "nx-match.h" From patchwork Tue Jul 13 21:56:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Numan Siddique X-Patchwork-Id: 1504894 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GPZGQ4fh9z9sX1 for ; Wed, 14 Jul 2021 07:56:30 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 1596C608E4; Tue, 13 Jul 2021 21:56:28 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 16VO3k4v5f2b; Tue, 13 Jul 2021 21:56:26 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp3.osuosl.org (Postfix) with ESMTPS id AFA5260A39; Tue, 13 Jul 2021 21:56:25 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 6F6E9C001B; Tue, 13 Jul 2021 21:56:25 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 24030C000E for ; Tue, 13 Jul 2021 21:56:24 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id A2B9F83B6B for ; Tue, 13 Jul 2021 21:56:20 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 98YIB4PsAJ9O for ; Tue, 13 Jul 2021 21:56:19 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay2-d.mail.gandi.net (relay2-d.mail.gandi.net [217.70.183.194]) by smtp1.osuosl.org (Postfix) with ESMTPS id 50B4583B50 for ; Tue, 13 Jul 2021 21:56:19 +0000 (UTC) Received: (Authenticated sender: numans@ovn.org) by relay2-d.mail.gandi.net (Postfix) with ESMTPSA id DA81C40003; Tue, 13 Jul 2021 21:56:16 +0000 (UTC) From: numans@ovn.org To: dev@openvswitch.org Date: Tue, 13 Jul 2021 17:56:02 -0400 Message-Id: <20210713215602.249161-1-numans@ovn.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210713215439.248927-1-numans@ovn.org> References: <20210713215439.248927-1-numans@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 2/5] binding: Add the localport port binding in the binding_lport information. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Numan Siddique If there is an OVS interface present with the external_ids:iface-id set to a localport port binding, we create a 'struct local_binding' for this OVS interface but we do not associate the binding_lport to this local_binding. This patch now associates the binding_lport now. Future patch will make use of this information in handling the runtime data changes in the pflow engine node. Signed-off-by: Numan Siddique --- controller/binding.c | 154 ++++++++++++++++++++++++++++++++++------ tests/ovn-controller.at | 35 ++++++++- 2 files changed, 166 insertions(+), 23 deletions(-) diff --git a/controller/binding.c b/controller/binding.c index aa38a0848..585f0271e 100644 --- a/controller/binding.c +++ b/controller/binding.c @@ -618,6 +618,11 @@ static struct binding_lport *local_binding_add_lport( enum en_lport_type); static struct binding_lport *local_binding_get_primary_lport( struct local_binding *); +static struct binding_lport *local_binding_get_first_lport( + struct local_binding *lbinding); +static struct binding_lport *local_binding_get_primary_or_localport_lport( + struct local_binding *lbinding); + static bool local_binding_handle_stale_binding_lports( struct local_binding *lbinding, struct binding_ctx_in *b_ctx_in, struct binding_ctx_out *b_ctx_out, struct hmap *qos_map); @@ -803,12 +808,15 @@ binding_dump_local_bindings(struct local_binding_data *lbinding_data, if (num_lports) { struct shash child_lports = SHASH_INITIALIZER(&child_lports); struct binding_lport *primary_lport = NULL; + struct binding_lport *localport_lport = NULL; struct binding_lport *b_lport; bool first_elem = true; LIST_FOR_EACH (b_lport, list_node, &lbinding->binding_lports) { if (first_elem && b_lport->type == LP_VIF) { primary_lport = b_lport; + } else if (first_elem && b_lport->type == LP_LOCALPORT) { + localport_lport = b_lport; } else { shash_add(&child_lports, b_lport->name, b_lport); } @@ -818,6 +826,9 @@ binding_dump_local_bindings(struct local_binding_data *lbinding_data, if (primary_lport) { ds_put_format(out_data, "primary lport : [%s]\n", primary_lport->name); + } else if (localport_lport) { + ds_put_format(out_data, "localport lport : [%s]\n", + localport_lport->name); } else { ds_put_format(out_data, "no primary lport\n"); } @@ -1007,8 +1018,7 @@ claim_lport(const struct sbrec_port_binding *pb, * Caller should make sure that this is the case. */ static bool -release_lport(const struct sbrec_port_binding *pb, bool sb_readonly, - struct hmap *tracked_datapaths, struct if_status_mgr *if_mgr) +release_lport_(const struct sbrec_port_binding *pb, bool sb_readonly) { if (pb->encap) { if (sb_readonly) { @@ -1031,9 +1041,20 @@ release_lport(const struct sbrec_port_binding *pb, bool sb_readonly, sbrec_port_binding_set_virtual_parent(pb, NULL); } + VLOG_INFO("Releasing lport %s from this chassis.", pb->logical_port); + return true; +} + +static bool +release_lport(const struct sbrec_port_binding *pb, bool sb_readonly, + struct hmap *tracked_datapaths, struct if_status_mgr *if_mgr) +{ + if (!release_lport_(pb, sb_readonly)) { + return false; + } + update_lport_tracking(pb, tracked_datapaths, false); if_status_mgr_release_iface(if_mgr, pb->logical_port); - VLOG_INFO("Releasing lport %s from this chassis.", pb->logical_port); return true; } @@ -1320,6 +1341,36 @@ consider_virtual_lport(const struct sbrec_port_binding *pb, return true; } +static bool +consider_localport(const struct sbrec_port_binding *pb, + struct binding_ctx_in *b_ctx_in, + struct binding_ctx_out *b_ctx_out) +{ + struct shash *local_bindings = &b_ctx_out->lbinding_data->bindings; + struct local_binding *lbinding = local_binding_find(local_bindings, + pb->logical_port); + + if (!lbinding) { + return true; + } + + local_binding_add_lport(&b_ctx_out->lbinding_data->lports, lbinding, pb, + LP_LOCALPORT); + + /* If the port binding is claimed, then release it as localport is claimed + * by any ovn-controller. */ + if (pb->chassis == b_ctx_in->chassis_rec) { + if (!release_lport_(pb, !b_ctx_in->ovnsb_idl_txn)) { + return false; + } + + remove_related_lport(pb, b_ctx_out); + } + + update_related_lport(pb, b_ctx_out); + return true; +} + /* Considers either claiming the lport or releasing the lport * for non VIF lports. */ @@ -1548,11 +1599,14 @@ binding_run(struct binding_ctx_in *b_ctx_in, struct binding_ctx_out *b_ctx_out) switch (lport_type) { case LP_PATCH: - case LP_LOCALPORT: case LP_VTEP: update_related_lport(pb, b_ctx_out); break; + case LP_LOCALPORT: + consider_localport(pb, b_ctx_in, b_ctx_out); + break; + case LP_VIF: consider_vif_lport(pb, b_ctx_in, b_ctx_out, NULL, qos_map_ptr); break; @@ -1766,14 +1820,18 @@ consider_iface_claim(const struct ovsrec_interface *iface_rec, lbinding->iface = iface_rec; } - struct binding_lport *b_lport = local_binding_get_primary_lport(lbinding); + struct binding_lport *b_lport = + local_binding_get_primary_or_localport_lport(lbinding); const struct sbrec_port_binding *pb = NULL; if (!b_lport) { pb = lport_lookup_by_name(b_ctx_in->sbrec_port_binding_by_name, lbinding->name); - if (pb && get_lport_type(pb) == LP_VIF) { - b_lport = local_binding_add_lport(binding_lports, lbinding, pb, - LP_VIF); + if (pb) { + enum en_lport_type lport_type = get_lport_type(pb); + if (lport_type == LP_VIF || lport_type == LP_LOCALPORT) { + b_lport = local_binding_add_lport(binding_lports, lbinding, pb, + lport_type); + } } } @@ -1782,6 +1840,10 @@ consider_iface_claim(const struct ovsrec_interface *iface_rec, return true; } + if (b_lport->type == LP_LOCALPORT) { + return consider_localport(pb, b_ctx_in, b_ctx_out); + } + if (!consider_vif_lport(b_lport->pb, b_ctx_in, b_ctx_out, lbinding, qos_map)) { return false; @@ -1826,7 +1888,8 @@ consider_iface_release(const struct ovsrec_interface *iface_rec, struct shash *binding_lports = &b_ctx_out->lbinding_data->lports; lbinding = local_binding_find(local_bindings, iface_id); - struct binding_lport *b_lport = local_binding_get_primary_lport(lbinding); + struct binding_lport *b_lport = + local_binding_get_primary_or_localport_lport(lbinding); if (is_binding_lport_this_chassis(b_lport, b_ctx_in->chassis_rec)) { struct local_datapath *ld = get_local_datapath(b_ctx_out->local_datapaths, @@ -1847,6 +1910,10 @@ consider_iface_release(const struct ovsrec_interface *iface_rec, } } + } else if (lbinding && b_lport && b_lport->type == LP_LOCALPORT) { + /* lbinding is associated with a localport. Remove it from the + * related lports. */ + remove_related_lport(b_lport->pb, b_ctx_out); } if (lbinding) { @@ -2182,6 +2249,8 @@ binding_handle_port_binding_changes(struct binding_ctx_in *b_ctx_in, SHASH_INITIALIZER(&deleted_virtual_pbs); struct shash deleted_vif_pbs = SHASH_INITIALIZER(&deleted_vif_pbs); + struct shash deleted_localport_pbs = + SHASH_INITIALIZER(&deleted_localport_pbs); struct shash deleted_other_pbs = SHASH_INITIALIZER(&deleted_other_pbs); const struct sbrec_port_binding *pb; @@ -2216,6 +2285,8 @@ binding_handle_port_binding_changes(struct binding_ctx_in *b_ctx_in, shash_add(&deleted_container_pbs, pb->logical_port, pb); } else if (lport_type == LP_VIRTUAL) { shash_add(&deleted_virtual_pbs, pb->logical_port, pb); + } else if (lport_type == LP_LOCALPORT) { + shash_add(&deleted_localport_pbs, pb->logical_port, pb); } else { shash_add(&deleted_other_pbs, pb->logical_port, pb); } @@ -2250,6 +2321,12 @@ binding_handle_port_binding_changes(struct binding_ctx_in *b_ctx_in, } } + SHASH_FOR_EACH_SAFE (node, node_next, &deleted_localport_pbs) { + handle_deleted_vif_lport(node->data, LP_LOCALPORT, b_ctx_in, + b_ctx_out); + shash_delete(&deleted_localport_pbs, node); + } + SHASH_FOR_EACH_SAFE (node, node_next, &deleted_other_pbs) { handle_deleted_lport(node->data, b_ctx_in, b_ctx_out); shash_delete(&deleted_other_pbs, node); @@ -2259,6 +2336,7 @@ delete_done: shash_destroy(&deleted_container_pbs); shash_destroy(&deleted_virtual_pbs); shash_destroy(&deleted_vif_pbs); + shash_destroy(&deleted_localport_pbs); shash_destroy(&deleted_other_pbs); if (!handled) { @@ -2318,8 +2396,11 @@ delete_done: b_ctx_out, qos_map_ptr); break; - case LP_PATCH: case LP_LOCALPORT: + handled = consider_localport(pb, b_ctx_in, b_ctx_out); + break; + + case LP_PATCH: case LP_VTEP: update_related_lport(pb, b_ctx_out); if (lport_type == LP_PATCH) { @@ -2473,6 +2554,24 @@ local_binding_delete(struct local_binding *lbinding, local_binding_destroy(lbinding, binding_lports); } +static struct binding_lport * +local_binding_get_first_lport(struct local_binding *lbinding) +{ + if (!lbinding) { + return NULL; + } + + if (!ovs_list_is_empty(&lbinding->binding_lports)) { + struct binding_lport *b_lport = NULL; + b_lport = CONTAINER_OF(ovs_list_front(&lbinding->binding_lports), + struct binding_lport, list_node); + + return b_lport; + } + + return NULL; +} + /* Returns the primary binding lport if present in lbinding's * binding lports list. A binding lport is considered primary * if binding lport's type is LP_VIF and the name matches @@ -2485,15 +2584,26 @@ local_binding_get_primary_lport(struct local_binding *lbinding) return NULL; } - if (!ovs_list_is_empty(&lbinding->binding_lports)) { - struct binding_lport *b_lport = NULL; - b_lport = CONTAINER_OF(ovs_list_front(&lbinding->binding_lports), - struct binding_lport, list_node); - - if (b_lport->type == LP_VIF && + struct binding_lport *b_lport = local_binding_get_first_lport(lbinding); + if (b_lport && b_lport->type == LP_VIF && !strcmp(lbinding->name, b_lport->name)) { - return b_lport; - } + return b_lport; + } + + return NULL; +} + +static struct binding_lport * +local_binding_get_primary_or_localport_lport(struct local_binding *lbinding) +{ + if (!lbinding) { + return NULL; + } + + struct binding_lport *b_lport = local_binding_get_first_lport(lbinding); + if (b_lport && (b_lport->type == LP_VIF || b_lport->type == LP_LOCALPORT) + && !strcmp(lbinding->name, b_lport->name)) { + return b_lport; } return NULL; @@ -2541,8 +2651,10 @@ local_binding_handle_stale_binding_lports(struct local_binding *lbinding, struct binding_ctx_out *b_ctx_out, struct hmap *qos_map) { - /* Check if this lbinding has a primary binding_lport or not. */ - struct binding_lport *p_lport = local_binding_get_primary_lport(lbinding); + /* Check if this lbinding has a primary binding_lport or + * localport binding_lport or not. */ + struct binding_lport *p_lport = + local_binding_get_primary_or_localport_lport(lbinding); if (p_lport) { /* Nothing to be done. */ return true; @@ -2709,6 +2821,7 @@ binding_lport_check_and_cleanup(struct binding_lport *b_lport, switch (b_lport->type) { case LP_VIF: + case LP_LOCALPORT: if (strcmp(b_lport->name, b_lport->lbinding->name)) { cleanup_blport = true; } @@ -2728,7 +2841,6 @@ binding_lport_check_and_cleanup(struct binding_lport *b_lport, break; case LP_PATCH: - case LP_LOCALPORT: case LP_VTEP: case LP_L2GATEWAY: case LP_L3GATEWAY: diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at index 9a2ebd7ce..11661a2fd 100644 --- a/tests/ovn-controller.at +++ b/tests/ovn-controller.at @@ -510,6 +510,18 @@ primary lport : [[lsp1]] ---------------------------------------- ]) +# Set the port type to localport +check ovn-nbctl lsp-set-type lsp1 localport +check as hv1 ovs-vsctl set open . external_ids:ovn-cms-options=localport +OVS_WAIT_UNTIL([test localport = $(ovn-sbctl get chassis . other_config:ovn-cms-options)]) + +AT_CHECK([as hv1 ovn-appctl -t ovn-controller debug/dump-local-bindings], [0], [dnl +Local bindings: +name: [[lsp1]], OVS interface name : [[vif1]], num binding lports : [[1]] +localport lport : [[lsp1]] +---------------------------------------- +]) + # pause ovn-northd check as northd ovn-appctl -t ovn-northd pause check as northd-backup ovn-appctl -t ovn-northd pause @@ -527,22 +539,41 @@ do check as hv1 ovs-vsctl set open . external_ids:ovn-cms-options=$type OVS_WAIT_UNTIL([test $type = $(ovn-sbctl get chassis . other_config:ovn-cms-options)]) - AT_CHECK([as hv1 ovn-appctl -t ovn-controller debug/dump-local-bindings], [0], [dnl + if [[ "$type" == "localport" ]]; then + AT_CHECK([as hv1 ovn-appctl -t ovn-controller debug/dump-local-bindings], [0], [dnl +Local bindings: +name: [[lsp1]], OVS interface name : [[vif1]], num binding lports : [[1]] +localport lport : [[lsp1]] +---------------------------------------- +]) + else + AT_CHECK([as hv1 ovn-appctl -t ovn-controller debug/dump-local-bindings], [0], [dnl Local bindings: name: [[lsp1]], OVS interface name : [[vif1]], num binding lports : [[0]] ---------------------------------------- ]) + fi echo "Updating to $update_type from $type" check ovn-sbctl set port_binding lsp1 type=$update_type check as hv1 ovs-vsctl set open . external_ids:ovn-cms-options=$update_type OVS_WAIT_UNTIL([test $update_type = $(ovn-sbctl get chassis . other_config:ovn-cms-options)]) - AT_CHECK([as hv1 ovn-appctl -t ovn-controller debug/dump-local-bindings], [0], [dnl + if [[ "$update_type" == "localport" ]]; then + AT_CHECK([as hv1 ovn-appctl -t ovn-controller debug/dump-local-bindings], [0], [dnl +Local bindings: +name: [[lsp1]], OVS interface name : [[vif1]], num binding lports : [[1]] +localport lport : [[lsp1]] +---------------------------------------- +]) + else + AT_CHECK([as hv1 ovn-appctl -t ovn-controller debug/dump-local-bindings], [0], [dnl Local bindings: name: [[lsp1]], OVS interface name : [[vif1]], num binding lports : [[0]] ---------------------------------------- ]) + fi + # Set the port binding type back to VIF. check ovn-sbctl set port_binding lsp1 type=\"\" check as hv1 ovs-vsctl set open . external_ids:ovn-cms-options=foo From patchwork Tue Jul 13 21:56:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Numan Siddique X-Patchwork-Id: 1504895 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GPZGg2qjkz9sX1 for ; Wed, 14 Jul 2021 07:56:43 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 2D7BC4055C; Tue, 13 Jul 2021 21:56:41 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 1RfKb-nlkYsz; Tue, 13 Jul 2021 21:56:40 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id 6E6CB4056A; Tue, 13 Jul 2021 21:56:39 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 4768EC001A; Tue, 13 Jul 2021 21:56:39 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 37B57C001B for ; Tue, 13 Jul 2021 21:56:38 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 939F840682 for ; Tue, 13 Jul 2021 21:56:31 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 218YEfbDDeBt for ; Tue, 13 Jul 2021 21:56:31 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net [217.70.183.201]) by smtp4.osuosl.org (Postfix) with ESMTPS id BA12A4067D for ; Tue, 13 Jul 2021 21:56:30 +0000 (UTC) Received: (Authenticated sender: numans@ovn.org) by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 6761F1BF205; Tue, 13 Jul 2021 21:56:28 +0000 (UTC) From: numans@ovn.org To: dev@openvswitch.org Date: Tue, 13 Jul 2021 17:56:18 -0400 Message-Id: <20210713215618.249218-1-numans@ovn.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210713215439.248927-1-numans@ovn.org> References: <20210713215439.248927-1-numans@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 3/5] binding: Track the changes of container lport when it's parent changes. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Numan Siddique When a container logical port's parent changes and if the parent logical port resides in the same chassis as the old parent, ovn-controller doesn't track that change in the 'tracked_dp_bindings'. At present this is not an issue because pflow_output engine handles this in the port_binding change handler. However, it is better to track this in the runtime_data. Signed-off-by: Numan Siddique --- controller/binding.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/controller/binding.c b/controller/binding.c index 585f0271e..395450c3e 100644 --- a/controller/binding.c +++ b/controller/binding.c @@ -1228,6 +1228,15 @@ consider_container_lport(const struct sbrec_port_binding *pb, } struct shash *binding_lports = &b_ctx_out->lbinding_data->lports; + struct binding_lport *b_lport = + binding_lport_find(binding_lports, pb->logical_port); + + if (b_lport && b_lport->lbinding != parent_lbinding) { + /* The container lport's parent has changed. So remove it from + * the related_lports so that it is tracked. */ + remove_related_lport(b_lport->pb, b_ctx_out); + } + struct binding_lport *container_b_lport = local_binding_add_lport(binding_lports, parent_lbinding, pb, LP_CONTAINER); From patchwork Tue Jul 13 21:56:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Numan Siddique X-Patchwork-Id: 1504896 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GPZHM47fBz9sX1 for ; Wed, 14 Jul 2021 07:57:19 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 88CCD83B66; Tue, 13 Jul 2021 21:57:16 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id VZu-YGqpUKp7; Tue, 13 Jul 2021 21:57:14 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id 7EECF83B54; Tue, 13 Jul 2021 21:57:13 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 4FC8AC001A; Tue, 13 Jul 2021 21:57:13 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 81F7AC000E for ; Tue, 13 Jul 2021 21:57:12 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 09B2D40548 for ; Tue, 13 Jul 2021 21:56:49 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id gutiniwcz-uw for ; Tue, 13 Jul 2021 21:56:47 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay2-d.mail.gandi.net (relay2-d.mail.gandi.net [217.70.183.194]) by smtp2.osuosl.org (Postfix) with ESMTPS id 944E640567 for ; Tue, 13 Jul 2021 21:56:46 +0000 (UTC) Received: (Authenticated sender: numans@ovn.org) by relay2-d.mail.gandi.net (Postfix) with ESMTPSA id 14CC540005; Tue, 13 Jul 2021 21:56:43 +0000 (UTC) From: numans@ovn.org To: dev@openvswitch.org Date: Tue, 13 Jul 2021 17:56:29 -0400 Message-Id: <20210713215629.249303-1-numans@ovn.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210713215439.248927-1-numans@ovn.org> References: <20210713215439.248927-1-numans@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 4/5] I-P: Handle runtime data changes for plow_output engine. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Numan Siddique physical_run() maintains a local copy of local vif to ofports in a simap along with the chassis tunnel information. This patch removes this from the physical module and now stores it in the runtime_data engine node. This makes it easier to handle runtime data changes in pflow_output engine. The newly added handler pflow_output_runtime_data_handler() returns false if a datapath is added or removed from the local_datapaths and handles the logical port claims and releases incrementally. Signed-off-by: Numan Siddique --- controller/binding.c | 39 ++-- controller/binding.h | 23 +++ controller/ldata.c | 169 +++++++++++++++++ controller/ldata.h | 44 +++++ controller/lflow.c | 5 +- controller/lflow.h | 1 + controller/ovn-controller.c | 68 ++++++- controller/ovn-controller.h | 8 - controller/physical.c | 366 +++++++----------------------------- controller/physical.h | 13 +- 10 files changed, 402 insertions(+), 334 deletions(-) diff --git a/controller/binding.c b/controller/binding.c index 395450c3e..27e778003 100644 --- a/controller/binding.c +++ b/controller/binding.c @@ -534,23 +534,6 @@ update_active_pb_ras_pd(const struct sbrec_port_binding *pb, } } -/* Corresponds to each Port_Binding.type. */ -enum en_lport_type { - LP_UNKNOWN, - LP_VIF, - LP_CONTAINER, - LP_PATCH, - LP_L3GATEWAY, - LP_LOCALNET, - LP_LOCALPORT, - LP_L2GATEWAY, - LP_VTEP, - LP_CHASSISREDIRECT, - LP_VIRTUAL, - LP_EXTERNAL, - LP_REMOTE -}; - /* Local bindings. binding.c module binds the logical port (represented by * Port_Binding rows) and sets the 'chassis' column when it sees the * OVS interface row (of type "" or "internal") with the @@ -604,7 +587,7 @@ static struct local_binding *local_binding_create( static void local_binding_add(struct shash *local_bindings, struct local_binding *); static struct local_binding *local_binding_find( - struct shash *local_bindings, const char *name); + const struct shash *local_bindings, const char *name); static void local_binding_destroy(struct local_binding *, struct shash *binding_lports); static void local_binding_delete(struct local_binding *, @@ -689,7 +672,8 @@ local_binding_data_destroy(struct local_binding_data *lbinding_data) } const struct sbrec_port_binding * -local_binding_get_primary_pb(struct shash *local_bindings, const char *pb_name) +local_binding_get_primary_pb(struct shash *local_bindings, + const char *pb_name) { struct local_binding *lbinding = local_binding_find(local_bindings, pb_name); @@ -698,6 +682,19 @@ local_binding_get_primary_pb(struct shash *local_bindings, const char *pb_name) return b_lport ? b_lport->pb : NULL; } +ofp_port_t +local_binding_get_lport_ofport(const struct shash *local_bindings, + const char *pb_name) +{ + struct local_binding *lbinding = + local_binding_find(local_bindings, pb_name); + struct binding_lport *b_lport = + local_binding_get_primary_or_localport_lport(lbinding); + + return (b_lport && lbinding->iface && lbinding->iface->n_ofport) ? + u16_to_ofp(lbinding->iface->ofport[0]) : 0; +} + bool local_binding_is_up(struct shash *local_bindings, const char *pb_name) { @@ -859,7 +856,7 @@ is_lport_vif(const struct sbrec_port_binding *pb) return !pb->type[0]; } -static enum en_lport_type +enum en_lport_type get_lport_type(const struct sbrec_port_binding *pb) { if (is_lport_vif(pb)) { @@ -2527,7 +2524,7 @@ local_binding_create(const char *name, const struct ovsrec_interface *iface) } static struct local_binding * -local_binding_find(struct shash *local_bindings, const char *name) +local_binding_find(const struct shash *local_bindings, const char *name) { return shash_find_data(local_bindings, name); } diff --git a/controller/binding.h b/controller/binding.h index b1717bd2b..f1abc4b9c 100644 --- a/controller/binding.h +++ b/controller/binding.h @@ -114,6 +114,9 @@ void local_binding_data_destroy(struct local_binding_data *); const struct sbrec_port_binding *local_binding_get_primary_pb( struct shash *local_bindings, const char *pb_name); +ofp_port_t local_binding_get_lport_ofport(const struct shash *local_bindings, + const char *pb_name); + bool local_binding_is_up(struct shash *local_bindings, const char *pb_name); bool local_binding_is_down(struct shash *local_bindings, const char *pb_name); void local_binding_set_up(struct shash *local_bindings, const char *pb_name, @@ -134,4 +137,24 @@ bool binding_handle_port_binding_changes(struct binding_ctx_in *, void binding_tracked_dp_destroy(struct hmap *tracked_datapaths); void binding_dump_local_bindings(struct local_binding_data *, struct ds *); + +/* Corresponds to each Port_Binding.type. */ +enum en_lport_type { + LP_UNKNOWN, + LP_VIF, + LP_CONTAINER, + LP_PATCH, + LP_L3GATEWAY, + LP_LOCALNET, + LP_LOCALPORT, + LP_L2GATEWAY, + LP_VTEP, + LP_CHASSISREDIRECT, + LP_VIRTUAL, + LP_EXTERNAL, + LP_REMOTE +}; + +enum en_lport_type get_lport_type(const struct sbrec_port_binding *); + #endif /* controller/binding.h */ diff --git a/controller/ldata.c b/controller/ldata.c index fe19eaf39..0b95d398b 100644 --- a/controller/ldata.c +++ b/controller/ldata.c @@ -18,10 +18,13 @@ /* OVS includes. */ #include "include/openvswitch/json.h" #include "lib/hmapx.h" +#include "lib/flow.h" #include "lib/util.h" +#include "lib/vswitch-idl.h" #include "openvswitch/vlog.h" /* OVN includes. */ +#include "encaps.h" #include "ldata.h" #include "lport.h" #include "lib/ovn-util.h" @@ -274,6 +277,172 @@ tracked_datapaths_destroy(struct hmap *tracked_datapaths) hmap_destroy(tracked_datapaths); } +/* Iterates the br_int ports and build the simap of patch to ofports + * and chassis tunnels. */ +void +ldata_run(const struct ovsrec_bridge *br_int, + const struct sbrec_chassis *chassis_rec, + struct local_nonvif_data *nonvif_data) +{ + for (int i = 0; i < br_int->n_ports; i++) { + const struct ovsrec_port *port_rec = br_int->ports[i]; + if (!strcmp(port_rec->name, br_int->name)) { + continue; + } + + const char *tunnel_id = smap_get(&port_rec->external_ids, + "ovn-chassis-id"); + if (tunnel_id && encaps_tunnel_id_match(tunnel_id, + chassis_rec->name, + NULL)) { + continue; + } + + const char *localnet = smap_get(&port_rec->external_ids, + "ovn-localnet-port"); + const char *l2gateway = smap_get(&port_rec->external_ids, + "ovn-l2gateway-port"); + + 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; + } + + bool is_patch = !strcmp(iface_rec->type, "patch"); + if (is_patch && localnet) { + simap_put(&nonvif_data->patch_ofports, localnet, ofport); + break; + } else if (is_patch && l2gateway) { + /* L2 gateway patch ports can be handled just like VIFs. */ + simap_put(&nonvif_data->patch_ofports, l2gateway, ofport); + break; + } else if (tunnel_id) { + enum chassis_tunnel_type tunnel_type; + if (!strcmp(iface_rec->type, "geneve")) { + tunnel_type = GENEVE; + } else if (!strcmp(iface_rec->type, "stt")) { + tunnel_type = STT; + } else if (!strcmp(iface_rec->type, "vxlan")) { + tunnel_type = VXLAN; + } else { + continue; + } + + /* We split the tunnel_id to get the chassis-id + * and hash the tunnel list on the chassis-id. The + * reason to use the chassis-id alone is because + * there might be cases (multicast, gateway chassis) + * where we need to tunnel to the chassis, but won't + * have the encap-ip specifically. + */ + char *hash_id = NULL; + char *ip = NULL; + + if (!encaps_tunnel_id_parse(tunnel_id, &hash_id, &ip)) { + continue; + } + struct chassis_tunnel *tun = xmalloc(sizeof *tun); + hmap_insert(&nonvif_data->chassis_tunnels, &tun->hmap_node, + hash_string(hash_id, 0)); + tun->chassis_id = xstrdup(tunnel_id); + tun->ofport = u16_to_ofp(ofport); + tun->type = tunnel_type; + + free(hash_id); + free(ip); + break; + } + } + } +} + +bool +ldata_handle_ovs_iface_changes( + const struct ovsrec_interface_table *iface_table) +{ + const struct ovsrec_interface *iface_rec; + OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, iface_table) { + if (!strcmp(iface_rec->type, "geneve") || + !strcmp(iface_rec->type, "patch") || + !strcmp(iface_rec->type, "vxlan") || + !strcmp(iface_rec->type, "stt")) { + return false; + } + } + + return true; +} + +bool +get_chassis_tunnel_ofport(const struct hmap *chassis_tunnels, + const char *chassis_name, char *encap_ip, + ofp_port_t *ofport) +{ + struct chassis_tunnel *tun = NULL; + tun = chassis_tunnel_find(chassis_tunnels, chassis_name, encap_ip); + if (!tun) { + return false; + } + + *ofport = tun->ofport; + return true; +} + +void +local_nonvif_data_init(struct local_nonvif_data *nonvif_data) +{ + simap_init(&nonvif_data->patch_ofports); + hmap_init(&nonvif_data->chassis_tunnels); +} + +void +local_nonvif_data_destroy(struct local_nonvif_data *nonvif_data) +{ + simap_destroy(&nonvif_data->patch_ofports); + struct chassis_tunnel *tun; + HMAP_FOR_EACH_POP (tun, hmap_node, &nonvif_data->chassis_tunnels) { + free(tun->chassis_id); + free(tun); + } + hmap_destroy(&nonvif_data->chassis_tunnels); +} + + +/* + * This function looks up the list of tunnel ports (provided by + * ovn-chassis-id ports) and returns the tunnel for the given chassid-id and + * encap-ip. The ovn-chassis-id is formed using the chassis-id and encap-ip. + * The list is hashed using the chassis-id. If the encap-ip is not specified, + * it means we'll just return a tunnel for that chassis-id, i.e. we just check + * for chassis-id and if there is a match, we'll return the tunnel. + * If encap-ip is also provided we use both chassis-id and encap-ip to do + * a more specific lookup. + */ +struct chassis_tunnel * +chassis_tunnel_find(const struct hmap *chassis_tunnels, const char *chassis_id, + char *encap_ip) +{ + /* + * If the specific encap_ip is given, look for the chassisid_ip entry, + * else return the 1st found entry for the chassis. + */ + struct chassis_tunnel *tun = NULL; + HMAP_FOR_EACH_WITH_HASH (tun, hmap_node, hash_string(chassis_id, 0), + chassis_tunnels) { + if (encaps_tunnel_id_match(tun->chassis_id, chassis_id, encap_ip)) { + return tun; + } + } + return NULL; +} + /* static functions. */ static struct local_datapath * local_datapath_add__(struct hmap *local_datapaths, diff --git a/controller/ldata.h b/controller/ldata.h index dec5ed760..3ef0dc87a 100644 --- a/controller/ldata.h +++ b/controller/ldata.h @@ -19,10 +19,14 @@ /* OVS includes. */ #include "include/openvswitch/shash.h" #include "lib/smap.h" +#include "lib/simap.h" struct sbrec_datapath_binding; struct sbrec_port_binding; +struct sbrec_chassis; struct ovsdb_idl_index; +struct ovsrec_bridge; +struct ovsrec_interface_table; /* A logical datapath that has some relevance to this hypervisor. A logical * datapath D is relevant to hypervisor H if: @@ -115,4 +119,44 @@ void tracked_datapath_lport_add(const struct sbrec_port_binding *, struct hmap *tracked_datapaths); void tracked_datapaths_destroy(struct hmap *tracked_datapaths); +/* Must be a bit-field ordered from most-preferred (higher number) to + * least-preferred (lower number). */ +enum chassis_tunnel_type { + GENEVE = 1 << 2, + STT = 1 << 1, + VXLAN = 1 << 0 +}; + +/* Maps from a chassis to the OpenFlow port number of the tunnel that can be + * used to reach that chassis. */ +struct chassis_tunnel { + struct hmap_node hmap_node; + char *chassis_id; + ofp_port_t ofport; + enum chassis_tunnel_type type; +}; + +struct local_nonvif_data { + struct simap patch_ofports; /* simap of patch ovs ports. */ + struct hmap chassis_tunnels; /* hmap of 'struct chassis_tunnel' from the + * tunnel OVS ports. */ +}; + +void ldata_run(const struct ovsrec_bridge *br_int, + const struct sbrec_chassis *, + struct local_nonvif_data *nonvif_data); + +bool ldata_handle_ovs_iface_changes(const struct ovsrec_interface_table *); + +struct chassis_tunnel *chassis_tunnel_find(const struct hmap *chassis_tunnels, + const char *chassis_id, + char *encap_ip); + +bool get_chassis_tunnel_ofport(const struct hmap *chassis_tunnels, + const char *chassis_name, char *encap_ip, + ofp_port_t *ofport); + +void local_nonvif_data_init(struct local_nonvif_data *nonvif_data); +void local_nonvif_data_destroy(struct local_nonvif_data *nonvif_data); + #endif /* controller/ldata.h */ diff --git a/controller/lflow.c b/controller/lflow.c index d1f32077b..4ac671e40 100644 --- a/controller/lflow.c +++ b/controller/lflow.c @@ -58,6 +58,7 @@ struct lookup_port_aux { const struct sbrec_datapath_binding *dp; const struct sbrec_logical_flow *lflow; struct lflow_resource_ref *lfrr; + const struct hmap *chassis_tunnels; }; struct condition_aux { @@ -145,7 +146,8 @@ tunnel_ofport_cb(const void *aux_, const char *port_name, ofp_port_t *ofport) return false; } - if (!get_tunnel_ofport(pb->chassis->name, NULL, ofport)) { + if (!get_chassis_tunnel_ofport(aux->chassis_tunnels, pb->chassis->name, + NULL, ofport)) { return false; } @@ -591,6 +593,7 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow, .dp = dp, .lflow = lflow, .lfrr = l_ctx_out->lfrr, + .chassis_tunnels = l_ctx_in->chassis_tunnels, }; /* Encode OVN logical actions into OpenFlow. */ diff --git a/controller/lflow.h b/controller/lflow.h index c17ff6dd4..e7dd31289 100644 --- a/controller/lflow.h +++ b/controller/lflow.h @@ -146,6 +146,7 @@ struct lflow_ctx_in { const struct shash *port_groups; const struct sset *active_tunnels; const struct sset *related_lport_ids; + const struct hmap *chassis_tunnels; }; struct lflow_ctx_out { diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 8f620e4ad..69d135046 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -1039,6 +1039,11 @@ struct ed_type_runtime_data { struct related_lports related_lports; struct sset active_tunnels; + /* Non VIF OVS interface information (mainly patch OVS interfacs + * and tunnel interfaces) that are relevant to the local + * chassis (generated by ldata_run()). */ + struct local_nonvif_data nonvif_data; + /* runtime data engine private data. */ struct sset egress_ifaces; struct smap local_iface_ids; @@ -1139,6 +1144,7 @@ en_runtime_data_init(struct engine_node *node OVS_UNUSED, local_binding_data_init(&data->lbinding_data); shash_init(&data->local_active_ports_ipv6_pd); shash_init(&data->local_active_ports_ras); + local_nonvif_data_init(&data->nonvif_data); /* Init the tracked data. */ hmap_init(&data->tracked_dp_bindings); @@ -1160,6 +1166,7 @@ en_runtime_data_cleanup(void *data) shash_destroy_free_data(&rt_data->local_active_ports_ipv6_pd); shash_destroy_free_data(&rt_data->local_active_ports_ras); local_binding_data_destroy(&rt_data->lbinding_data); + local_nonvif_data_destroy(&rt_data->nonvif_data); } static void @@ -1272,6 +1279,7 @@ en_runtime_data_run(struct engine_node *node, void *data) shash_clear_free_data(local_active_ipv6_pd); shash_clear_free_data(local_active_ras); local_binding_data_destroy(&rt_data->lbinding_data); + local_nonvif_data_destroy(&rt_data->nonvif_data); sset_destroy(local_lports); related_lports_destroy(&rt_data->related_lports); sset_destroy(active_tunnels); @@ -1284,6 +1292,7 @@ en_runtime_data_run(struct engine_node *node, void *data) sset_init(&rt_data->egress_ifaces); smap_init(&rt_data->local_iface_ids); local_binding_data_init(&rt_data->lbinding_data); + local_nonvif_data_init(&rt_data->nonvif_data); } struct binding_ctx_in b_ctx_in; @@ -1303,6 +1312,7 @@ en_runtime_data_run(struct engine_node *node, void *data) bfd_calculate_active_tunnels(b_ctx_in.br_int, active_tunnels); } + ldata_run(b_ctx_in.br_int, b_ctx_in.chassis_rec, &rt_data->nonvif_data); binding_run(&b_ctx_in, &b_ctx_out); engine_set_node_state(node, EN_UPDATED); @@ -1318,6 +1328,10 @@ runtime_data_ovs_interface_handler(struct engine_node *node, void *data) rt_data->tracked = true; b_ctx_out.tracked_dp_bindings = &rt_data->tracked_dp_bindings; + if (!ldata_handle_ovs_iface_changes(b_ctx_in.iface_table)) { + return false; + } + if (!binding_handle_ovs_interface_changes(&b_ctx_in, &b_ctx_out)) { return false; } @@ -2060,6 +2074,7 @@ init_lflow_ctx(struct engine_node *node, l_ctx_in->port_groups = port_groups; l_ctx_in->active_tunnels = &rt_data->active_tunnels; l_ctx_in->related_lport_ids = &rt_data->related_lports.lport_ids; + l_ctx_in->chassis_tunnels = &rt_data->nonvif_data.chassis_tunnels; l_ctx_out->flow_table = &fo->flow_table; l_ctx_out->group_table = &fo->group_table; @@ -2527,6 +2542,7 @@ static void init_physical_ctx(struct engine_node *node, p_ctx->ct_zones = ct_zones; p_ctx->mff_ovn_geneve = ed_mff_ovn_geneve->mff_ovn_geneve; p_ctx->local_bindings = &rt_data->lbinding_data.bindings; + p_ctx->nonvif_data = &rt_data->nonvif_data; } static void * @@ -2583,7 +2599,11 @@ pflow_output_sb_port_binding_handler(struct engine_node *node, * only. flow_output runtime data handler takes care of processing * logical flows for any port binding changes. */ - physical_handle_port_binding_changes(&p_ctx, &pfo->flow_table); + const struct sbrec_port_binding *pb; + SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (pb, p_ctx.port_binding_table) { + bool removed = sbrec_port_binding_is_deleted(pb); + physical_handle_flows_for_lport(pb, removed, &p_ctx, &pfo->flow_table); + } engine_set_node_state(node, EN_UPDATED); return true; @@ -2613,13 +2633,55 @@ pflow_output_ovs_iface_handler(struct engine_node *node OVS_UNUSED, struct ed_type_runtime_data *rt_data = engine_get_input_data("runtime_data", node); + struct physical_ctx p_ctx; + init_physical_ctx(node, rt_data, &p_ctx); + + engine_set_node_state(node, EN_UPDATED); + return physical_handle_ovs_iface_changes(&p_ctx); +} + +static bool +pflow_output_runtime_data_handler(struct engine_node *node, void *data) +{ + struct ed_type_runtime_data *rt_data = + engine_get_input_data("runtime_data", node); + + /* There is no tracked data. Fall back to full recompute of + * pflow_output. */ + if (!rt_data->tracked) { + return false; + } + + struct hmap *tracked_dp_bindings = &rt_data->tracked_dp_bindings; + if (hmap_is_empty(tracked_dp_bindings)) { + return true; + } + struct ed_type_pflow_output *pfo = data; struct physical_ctx p_ctx; init_physical_ctx(node, rt_data, &p_ctx); + struct tracked_datapath *tdp; + HMAP_FOR_EACH (tdp, node, tracked_dp_bindings) { + if (tdp->tracked_type != TRACKED_RESOURCE_UPDATED) { + /* Fall back to full recompute when a local datapath + * is added or deleted. */ + return false; + } + + struct shash_node *shash_node; + SHASH_FOR_EACH (shash_node, &tdp->lports) { + struct tracked_lport *lport = shash_node->data; + bool removed = + lport->tracked_type == TRACKED_RESOURCE_REMOVED ? true: false; + physical_handle_flows_for_lport(lport->pb, removed, &p_ctx, + &pfo->flow_table); + } + } + engine_set_node_state(node, EN_UPDATED); - return physical_handle_ovs_iface_changes(&p_ctx, &pfo->flow_table); + return true; } static void * @@ -2914,7 +2976,7 @@ main(int argc, char *argv[]) pflow_output_sb_multicast_group_handler); engine_add_input(&en_pflow_output, &en_runtime_data, - NULL); + pflow_output_runtime_data_handler); engine_add_input(&en_pflow_output, &en_sb_encap, NULL); engine_add_input(&en_pflow_output, &en_mff_ovn_geneve, NULL); engine_add_input(&en_pflow_output, &en_ovs_open_vswitch, NULL); diff --git a/controller/ovn-controller.h b/controller/ovn-controller.h index 578588305..78a53312f 100644 --- a/controller/ovn-controller.h +++ b/controller/ovn-controller.h @@ -45,14 +45,6 @@ const struct ovsrec_bridge *get_bridge(const struct ovsrec_bridge_table *, struct sbrec_encap *preferred_encap(const struct sbrec_chassis *); -/* Must be a bit-field ordered from most-preferred (higher number) to - * least-preferred (lower number). */ -enum chassis_tunnel_type { - GENEVE = 1 << 2, - STT = 1 << 1, - VXLAN = 1 << 0 -}; - uint32_t get_tunnel_type(const char *name); struct pb_ld_binding { diff --git a/controller/physical.c b/controller/physical.c index a0f733f14..5b8a9a54e 100644 --- a/controller/physical.c +++ b/controller/physical.c @@ -86,46 +86,6 @@ physical_register_ovs_idl(struct ovsdb_idl *ovs_idl) ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_external_ids); } -static struct simap localvif_to_ofport = - SIMAP_INITIALIZER(&localvif_to_ofport); -static struct hmap tunnels = HMAP_INITIALIZER(&tunnels); - -/* Maps from a chassis to the OpenFlow port number of the tunnel that can be - * used to reach that chassis. */ -struct chassis_tunnel { - struct hmap_node hmap_node; - char *chassis_id; - ofp_port_t ofport; - enum chassis_tunnel_type type; -}; - -/* - * This function looks up the list of tunnel ports (provided by - * ovn-chassis-id ports) and returns the tunnel for the given chassid-id and - * encap-ip. The ovn-chassis-id is formed using the chassis-id and encap-ip. - * The list is hashed using the chassis-id. If the encap-ip is not specified, - * it means we'll just return a tunnel for that chassis-id, i.e. we just check - * for chassis-id and if there is a match, we'll return the tunnel. - * If encap-ip is also provided we use both chassis-id and encap-ip to do - * a more specific lookup. - */ -static struct chassis_tunnel * -chassis_tunnel_find(const char *chassis_id, char *encap_ip) -{ - /* - * If the specific encap_ip is given, look for the chassisid_ip entry, - * else return the 1st found entry for the chassis. - */ - struct chassis_tunnel *tun = NULL; - HMAP_FOR_EACH_WITH_HASH (tun, hmap_node, hash_string(chassis_id, 0), - &tunnels) { - if (encaps_tunnel_id_match(tun->chassis_id, chassis_id, encap_ip)) { - return tun; - } - } - return NULL; -} - static void put_load(uint64_t value, enum mf_field_id dst, int ofs, int n_bits, struct ofpbuf *ofpacts) @@ -166,17 +126,18 @@ put_resubmit(uint8_t table_id, struct ofpbuf *ofpacts) * from the associated encap. */ static struct chassis_tunnel * -get_port_binding_tun(const struct sbrec_port_binding *binding) +get_port_binding_tun(const struct sbrec_port_binding *binding, + const struct hmap *chassis_tunnels) { struct sbrec_encap *encap = binding->encap; struct sbrec_chassis *chassis = binding->chassis; struct chassis_tunnel *tun = NULL; if (encap) { - tun = chassis_tunnel_find(chassis->name, encap->ip); + tun = chassis_tunnel_find(chassis_tunnels, chassis->name, encap->ip); } if (!tun) { - tun = chassis_tunnel_find(chassis->name, NULL); + tun = chassis_tunnel_find(chassis_tunnels, chassis->name, NULL); } return tun; } @@ -325,12 +286,13 @@ put_remote_port_redirect_overlay(const struct uint32_t port_key, struct match *match, struct ofpbuf *ofpacts_p, + const struct hmap *chassis_tunnels, struct ovn_desired_flow_table *flow_table) { if (!is_ha_remote) { /* Setup encapsulation */ const struct chassis_tunnel *rem_tun = - get_port_binding_tun(binding); + get_port_binding_tun(binding, chassis_tunnels); if (!rem_tun) { return; } @@ -348,10 +310,10 @@ put_remote_port_redirect_overlay(const struct continue; } if (!tun) { - tun = chassis_tunnel_find(ch->name, NULL); + tun = chassis_tunnel_find(chassis_tunnels, ch->name, NULL); } else { struct chassis_tunnel *chassis_tunnel = - chassis_tunnel_find(ch->name, NULL); + chassis_tunnel_find(chassis_tunnels, ch->name, NULL); if (chassis_tunnel && tun->type != chassis_tunnel->type) { static struct vlog_rate_limit rl = @@ -385,7 +347,7 @@ put_remote_port_redirect_overlay(const struct if (!ch) { continue; } - tun = chassis_tunnel_find(ch->name, NULL); + tun = chassis_tunnel_find(chassis_tunnels, ch->name, NULL); if (!tun) { continue; } @@ -925,6 +887,9 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, const struct simap *ct_zones, const struct sset *active_tunnels, const struct hmap *local_datapaths, + const struct shash *local_bindings, + const struct simap *patch_ofports, + const struct hmap *chassis_tunnels, const struct sbrec_port_binding *binding, const struct sbrec_chassis *chassis, struct ovn_desired_flow_table *flow_table, @@ -1081,17 +1046,25 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, if (!binding->tag) { goto out; } - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, - binding->parent_port)); + ofport = local_binding_get_lport_ofport(local_bindings, + binding->parent_port); if (ofport) { tag = *binding->tag; nested_container = true; parent_port = lport_lookup_by_name( sbrec_port_binding_by_name, binding->parent_port); } - } else { - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, + } else if (!strcmp(binding->type, "localnet") + || !strcmp(binding->type, "l2gateway")) { + + ofport = u16_to_ofp(simap_get(patch_ofports, binding->logical_port)); + if (ofport && binding->tag) { + tag = *binding->tag; + } + } else { + ofport = local_binding_get_lport_ofport(local_bindings, + binding->logical_port); const char *requested_chassis = smap_get(&binding->options, "requested-chassis"); if (ofport && requested_chassis && requested_chassis[0] && @@ -1102,12 +1075,6 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, */ ofport = 0; } - - if ((!strcmp(binding->type, "localnet") - || !strcmp(binding->type, "l2gateway")) - && ofport && binding->tag) { - tag = *binding->tag; - } } bool is_ha_remote = false; @@ -1118,7 +1085,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, /* It is remote port, may be reached by tunnel or localnet port */ is_remote = true; if (localnet_port) { - ofport = u16_to_ofp(simap_get(&localvif_to_ofport, + ofport = u16_to_ofp(simap_get(patch_ofports, localnet_port->logical_port)); if (!ofport) { goto out; @@ -1129,7 +1096,8 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, if (!binding->chassis) { goto out; } - tun = chassis_tunnel_find(binding->chassis->name, NULL); + tun = chassis_tunnel_find(chassis_tunnels, + binding->chassis->name, NULL); if (!tun) { goto out; } @@ -1337,7 +1305,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, put_remote_port_redirect_overlay(binding, is_ha_remote, ha_ch_ordered, mff_ovn_geneve, tun, port_key, &match, ofpacts_p, - flow_table); + chassis_tunnels, flow_table); } } out: @@ -1350,8 +1318,11 @@ static void consider_mc_group(enum mf_field_id mff_ovn_geneve, const struct simap *ct_zones, const struct hmap *local_datapaths, + struct shash *local_bindings, + struct simap *patch_ofports, const struct sbrec_chassis *chassis, const struct sbrec_multicast_group *mc, + const struct hmap *chassis_tunnels, struct ovn_desired_flow_table *flow_table) { uint32_t dp_key = mc->datapath->tunnel_key; @@ -1398,19 +1369,21 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve, put_load(zone_id, MFF_LOG_CT_ZONE, 0, 32, &ofpacts); } + const char *lport_name = (port->parent_port && *port->parent_port) ? + port->parent_port : port->logical_port; + if (!strcmp(port->type, "patch")) { put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, &remote_ofpacts); put_resubmit(OFTABLE_CHECK_LOOPBACK, &remote_ofpacts); - } else if (simap_contains(&localvif_to_ofport, - (port->parent_port && *port->parent_port) - ? port->parent_port : port->logical_port) + } else if (local_binding_get_primary_pb(local_bindings, lport_name) + || simap_contains(patch_ofports, port->logical_port) || (!strcmp(port->type, "l3gateway") && port->chassis == chassis)) { put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, &ofpacts); put_resubmit(OFTABLE_CHECK_LOOPBACK, &ofpacts); - } else if (port->chassis && !get_localnet_port(local_datapaths, - mc->datapath->tunnel_key)) { + } else if (port->chassis && !get_localnet_port( + local_datapaths, mc->datapath->tunnel_key)) { /* Add remote chassis only when localnet port not exist, * otherwise multicast will reach remote ports through localnet * port. */ @@ -1451,7 +1424,7 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve, const struct chassis_tunnel *prev = NULL; SSET_FOR_EACH (chassis_name, &remote_chassis) { const struct chassis_tunnel *tun - = chassis_tunnel_find(chassis_name, NULL); + = chassis_tunnel_find(chassis_tunnels, chassis_name, NULL); if (!tun) { continue; } @@ -1478,40 +1451,25 @@ consider_mc_group(enum mf_field_id mff_ovn_geneve, sset_destroy(&remote_chassis); } -/* Replaces 'old' by 'new' (destroying 'new'). Returns true if 'old' and 'new' - * contained different data, false if they were the same. */ -static bool -update_ofports(struct simap *old, struct simap *new) -{ - bool changed = !simap_equal(old, new); - simap_swap(old, new); - simap_destroy(new); - return changed; -} - void -physical_handle_port_binding_changes(struct physical_ctx *p_ctx, - struct ovn_desired_flow_table *flow_table) +physical_handle_flows_for_lport(const struct sbrec_port_binding *pb, + bool removed, struct physical_ctx *p_ctx, + struct ovn_desired_flow_table *flow_table) { - const struct sbrec_port_binding *binding; + ofctrl_remove_flows(flow_table, &pb->header_.uuid); + if (removed) { + return; + } + struct ofpbuf ofpacts; ofpbuf_init(&ofpacts, 0); - SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (binding, - p_ctx->port_binding_table) { - if (sbrec_port_binding_is_deleted(binding)) { - ofctrl_remove_flows(flow_table, &binding->header_.uuid); - } else { - if (!sbrec_port_binding_is_new(binding)) { - ofctrl_remove_flows(flow_table, &binding->header_.uuid); - } - consider_port_binding(p_ctx->sbrec_port_binding_by_name, - p_ctx->mff_ovn_geneve, p_ctx->ct_zones, - p_ctx->active_tunnels, - p_ctx->local_datapaths, - binding, p_ctx->chassis, - flow_table, &ofpacts); - } - } + consider_port_binding(p_ctx->sbrec_port_binding_by_name, + p_ctx->mff_ovn_geneve, p_ctx->ct_zones, + p_ctx->active_tunnels, p_ctx->local_datapaths, + p_ctx->local_bindings, + &p_ctx->nonvif_data->patch_ofports, + &p_ctx->nonvif_data->chassis_tunnels, pb, + p_ctx->chassis, flow_table, &ofpacts); ofpbuf_uninit(&ofpacts); } @@ -1528,8 +1486,11 @@ physical_handle_mc_group_changes(struct physical_ctx *p_ctx, ofctrl_remove_flows(flow_table, &mc->header_.uuid); } consider_mc_group(p_ctx->mff_ovn_geneve, p_ctx->ct_zones, - p_ctx->local_datapaths, - p_ctx->chassis, mc, flow_table); + p_ctx->local_datapaths, p_ctx->local_bindings, + &p_ctx->nonvif_data->patch_ofports, + p_ctx->chassis, mc, + &p_ctx->nonvif_data->chassis_tunnels, + flow_table); } } } @@ -1545,135 +1506,6 @@ physical_run(struct physical_ctx *p_ctx, uuid_generate(hc_uuid); } - /* This bool tracks physical mapping changes. */ - bool physical_map_changed = false; - - struct simap new_localvif_to_ofport = - SIMAP_INITIALIZER(&new_localvif_to_ofport); - struct simap new_tunnel_to_ofport = - SIMAP_INITIALIZER(&new_tunnel_to_ofport); - for (int i = 0; i < p_ctx->br_int->n_ports; i++) { - const struct ovsrec_port *port_rec = p_ctx->br_int->ports[i]; - if (!strcmp(port_rec->name, p_ctx->br_int->name)) { - continue; - } - - const char *tunnel_id = smap_get(&port_rec->external_ids, - "ovn-chassis-id"); - if (tunnel_id && encaps_tunnel_id_match(tunnel_id, - p_ctx->chassis->name, - NULL)) { - continue; - } - - const char *localnet = smap_get(&port_rec->external_ids, - "ovn-localnet-port"); - const char *l2gateway = smap_get(&port_rec->external_ids, - "ovn-l2gateway-port"); - - 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 patch to local net, logical patch port, chassis, or - * local logical port. */ - bool is_patch = !strcmp(iface_rec->type, "patch"); - if (is_patch && localnet) { - /* localnet patch ports can be handled just like VIFs. */ - simap_put(&new_localvif_to_ofport, localnet, ofport); - break; - } else if (is_patch && l2gateway) { - /* L2 gateway patch ports can be handled just like VIFs. */ - simap_put(&new_localvif_to_ofport, l2gateway, ofport); - break; - } else if (tunnel_id) { - enum chassis_tunnel_type tunnel_type; - if (!strcmp(iface_rec->type, "geneve")) { - tunnel_type = GENEVE; - if (!p_ctx->mff_ovn_geneve) { - continue; - } - } else if (!strcmp(iface_rec->type, "stt")) { - tunnel_type = STT; - } else if (!strcmp(iface_rec->type, "vxlan")) { - tunnel_type = VXLAN; - } else { - continue; - } - - simap_put(&new_tunnel_to_ofport, tunnel_id, ofport); - /* - * We split the tunnel_id to get the chassis-id - * and hash the tunnel list on the chassis-id. The - * reason to use the chassis-id alone is because - * there might be cases (multicast, gateway chassis) - * where we need to tunnel to the chassis, but won't - * have the encap-ip specifically. - */ - char *hash_id = NULL; - char *ip = NULL; - - if (!encaps_tunnel_id_parse(tunnel_id, &hash_id, &ip)) { - continue; - } - struct chassis_tunnel *tun = chassis_tunnel_find(hash_id, ip); - if (tun) { - /* If the tunnel's ofport has changed, update. */ - if (tun->ofport != u16_to_ofp(ofport) || - tun->type != tunnel_type) { - tun->ofport = u16_to_ofp(ofport); - tun->type = tunnel_type; - physical_map_changed = true; - } - } else { - tun = xmalloc(sizeof *tun); - hmap_insert(&tunnels, &tun->hmap_node, - hash_string(hash_id, 0)); - tun->chassis_id = xstrdup(tunnel_id); - tun->ofport = u16_to_ofp(ofport); - tun->type = tunnel_type; - physical_map_changed = true; - } - free(hash_id); - free(ip); - break; - } else { - const char *iface_id = smap_get(&iface_rec->external_ids, - "iface-id"); - if (iface_id) { - simap_put(&new_localvif_to_ofport, iface_id, ofport); - } - } - } - } - - /* Remove tunnels that are no longer here. */ - struct chassis_tunnel *tun, *tun_next; - HMAP_FOR_EACH_SAFE (tun, tun_next, hmap_node, &tunnels) { - if (!simap_find(&new_tunnel_to_ofport, tun->chassis_id)) { - hmap_remove(&tunnels, &tun->hmap_node); - physical_map_changed = true; - free(tun->chassis_id); - free(tun); - } - } - - /* Capture changed or removed openflow ports. */ - physical_map_changed |= update_ofports(&localvif_to_ofport, - &new_localvif_to_ofport); - if (physical_map_changed) { - /* Reprocess logical flow table immediately. */ - poll_immediate_wake(); - } - struct ofpbuf ofpacts; ofpbuf_init(&ofpacts, 0); @@ -1687,16 +1519,20 @@ physical_run(struct physical_ctx *p_ctx, consider_port_binding(p_ctx->sbrec_port_binding_by_name, p_ctx->mff_ovn_geneve, p_ctx->ct_zones, p_ctx->active_tunnels, p_ctx->local_datapaths, - binding, p_ctx->chassis, - flow_table, &ofpacts); + p_ctx->local_bindings, + &p_ctx->nonvif_data->patch_ofports, + &p_ctx->nonvif_data->chassis_tunnels, binding, + p_ctx->chassis, flow_table, &ofpacts); } /* Handle output to multicast groups, in tables 32 and 33. */ const struct sbrec_multicast_group *mc; SBREC_MULTICAST_GROUP_TABLE_FOR_EACH (mc, p_ctx->mc_group_table) { consider_mc_group(p_ctx->mff_ovn_geneve, p_ctx->ct_zones, - p_ctx->local_datapaths, p_ctx->chassis, - mc, flow_table); + p_ctx->local_datapaths, p_ctx->local_bindings, + &p_ctx->nonvif_data->patch_ofports, p_ctx->chassis, + mc, &p_ctx->nonvif_data->chassis_tunnels, + flow_table); } /* Table 0, priority 100. @@ -1711,7 +1547,8 @@ physical_run(struct physical_ctx *p_ctx, * We set MFF_LOG_DATAPATH, MFF_LOG_INPORT, and MFF_LOG_OUTPORT from the * tunnel key data where possible, then resubmit to table 33 to handle * packets to the local hypervisor. */ - HMAP_FOR_EACH (tun, hmap_node, &tunnels) { + struct chassis_tunnel *tun; + HMAP_FOR_EACH (tun, hmap_node, &p_ctx->nonvif_data->chassis_tunnels) { struct match match = MATCH_CATCHALL_INITIALIZER; match_set_in_port(&match, tun->ofport); @@ -1742,7 +1579,7 @@ physical_run(struct physical_ctx *p_ctx, } /* Handle ramp switch encapsulations. */ - HMAP_FOR_EACH (tun, hmap_node, &tunnels) { + HMAP_FOR_EACH (tun, hmap_node, &p_ctx->nonvif_data->chassis_tunnels) { if (tun->type != VXLAN) { continue; } @@ -1879,13 +1716,10 @@ physical_run(struct physical_ctx *p_ctx, &ofpacts, hc_uuid); ofpbuf_uninit(&ofpacts); - - simap_destroy(&new_tunnel_to_ofport); } bool -physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx, - struct ovn_desired_flow_table *flow_table) +physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx) { const struct ovsrec_interface *iface_rec; OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, p_ctx->iface_table) { @@ -1897,64 +1731,6 @@ physical_handle_ovs_iface_changes(struct physical_ctx *p_ctx, } } - struct ofpbuf ofpacts; - ofpbuf_init(&ofpacts, 0); - - OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, p_ctx->iface_table) { - const char *iface_id = smap_get(&iface_rec->external_ids, "iface-id"); - if (!iface_id) { - continue; - } - - const struct sbrec_port_binding *lb_pb = - local_binding_get_primary_pb(p_ctx->local_bindings, iface_id); - if (!lb_pb) { - /* For regular VIFs (e.g. lsp) the upcoming port-binding update - * will remove lfows related to the unclaimed ovs port. - * Localport is a special case and it needs to be managed here - * since the port is not binded and otherwise the related lfows - * will not be cleared removing the ovs port. - */ - lb_pb = lport_lookup_by_name(p_ctx->sbrec_port_binding_by_name, - iface_id); - if (!lb_pb || strcmp(lb_pb->type, "localport")) { - continue; - } - } - - int64_t ofport = iface_rec->n_ofport ? *iface_rec->ofport : 0; - if (ovsrec_interface_is_deleted(iface_rec)) { - ofctrl_remove_flows(flow_table, &lb_pb->header_.uuid); - simap_find_and_delete(&localvif_to_ofport, iface_id); - } else { - if (!ovsrec_interface_is_new(iface_rec)) { - ofctrl_remove_flows(flow_table, &lb_pb->header_.uuid); - } - - simap_put(&localvif_to_ofport, iface_id, ofport); - consider_port_binding(p_ctx->sbrec_port_binding_by_name, - p_ctx->mff_ovn_geneve, p_ctx->ct_zones, - p_ctx->active_tunnels, - p_ctx->local_datapaths, - lb_pb, p_ctx->chassis, - flow_table, &ofpacts); - } - } - - ofpbuf_uninit(&ofpacts); - return true; -} - -bool -get_tunnel_ofport(const char *chassis_name, char *encap_ip, ofp_port_t *ofport) -{ - struct chassis_tunnel *tun = NULL; - tun = chassis_tunnel_find(chassis_name, encap_ip); - if (!tun) { - return false; - } - - *ofport = tun->ofport; return true; } diff --git a/controller/physical.h b/controller/physical.h index feab41df4..3fdc20005 100644 --- a/controller/physical.h +++ b/controller/physical.h @@ -34,6 +34,7 @@ struct simap; struct sbrec_multicast_group_table; struct sbrec_port_binding_table; struct sset; +struct local_nonvif_data; /* OVN Geneve option information. * @@ -56,18 +57,18 @@ struct physical_ctx { const struct simap *ct_zones; enum mf_field_id mff_ovn_geneve; struct shash *local_bindings; + struct local_nonvif_data *nonvif_data; }; void physical_register_ovs_idl(struct ovsdb_idl *); void physical_run(struct physical_ctx *, struct ovn_desired_flow_table *); void physical_clear_unassoc_flows_with_db(struct ovn_desired_flow_table *); -void physical_handle_port_binding_changes(struct physical_ctx *, - struct ovn_desired_flow_table *); void physical_handle_mc_group_changes(struct physical_ctx *, struct ovn_desired_flow_table *); -bool physical_handle_ovs_iface_changes(struct physical_ctx *, - struct ovn_desired_flow_table *); -bool get_tunnel_ofport(const char *chassis_name, char *encap_ip, - ofp_port_t *ofport); +bool physical_handle_ovs_iface_changes(struct physical_ctx *); +void physical_handle_flows_for_lport(const struct sbrec_port_binding *, + bool removed, + struct physical_ctx *, + struct ovn_desired_flow_table *); #endif /* controller/physical.h */ From patchwork Tue Jul 13 21:56:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Numan Siddique X-Patchwork-Id: 1504897 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GPZHR3bqBz9sX1 for ; Wed, 14 Jul 2021 07:57:23 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id C4E8683B84; Tue, 13 Jul 2021 21:57:21 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id YboWW40ca3VX; Tue, 13 Jul 2021 21:57:20 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id ABB4283B65; Tue, 13 Jul 2021 21:57:19 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 92AC6C001A; Tue, 13 Jul 2021 21:57:19 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0CEAAC001A for ; Tue, 13 Jul 2021 21:57:18 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id CB0B44066A for ; Tue, 13 Jul 2021 21:57:05 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id UVLKE3Zz0vuA for ; Tue, 13 Jul 2021 21:57:04 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by smtp4.osuosl.org (Postfix) with ESMTPS id 1762940665 for ; Tue, 13 Jul 2021 21:57:03 +0000 (UTC) Received: (Authenticated sender: numans@ovn.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id 545C51C0004; Tue, 13 Jul 2021 21:56:59 +0000 (UTC) From: numans@ovn.org To: dev@openvswitch.org Date: Tue, 13 Jul 2021 17:56:45 -0400 Message-Id: <20210713215645.249381-1-numans@ovn.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210713215439.248927-1-numans@ovn.org> References: <20210713215439.248927-1-numans@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn 5/5] controller: Improve ct zone handling. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Numan Siddique Prior to this patch, ovn-controller generates a zone id for each OVS interface which has external_ids:iface-id set even if there is no corresponding logical port for it. This patch now changes the way we allocate the zone id. A zone id is allocated only if there is an OVS interface with external_ids:iface-id and the corresponding logical port is claimed. We use the runtime data (rt_data->lbinding_data.lports) for this. This patch also improves the ct_zones_runtime_data_handler() by using the tracked datapath data to allocate the zone ids for newly claimed lports or to free up the zone id for the released lports instead of triggering a full recompute. And finally this patch also adds a ct zone handler for pflow_output engine. This handler falls back to recompute if the ct zone engine was recomputed. Otherwise it returns true. Signed-off-by: Numan Siddique --- controller/ovn-controller.c | 133 +++++++++++++++++++++++++++--------- lib/inc-proc-eng.h | 4 ++ tests/ovn.at | 2 +- 3 files changed, 106 insertions(+), 33 deletions(-) diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 69d135046..db247edb1 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -617,8 +617,32 @@ add_pending_ct_zone_entry(struct shash *pending_ct_zones, } } +static bool +alloc_id_to_ct_zone(const char *zone_name, struct simap *ct_zones, + unsigned long *ct_zone_bitmap, int *scan_start, + struct shash *pending_ct_zones) +{ + /* We assume that there are 64K zones and that we own them all. */ + int zone = bitmap_scan(ct_zone_bitmap, 0, *scan_start, MAX_CT_ZONES + 1); + if (zone == MAX_CT_ZONES + 1) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_WARN_RL(&rl, "exhausted all ct zones"); + return false; + } + + *scan_start = zone + 1; + + add_pending_ct_zone_entry(pending_ct_zones, CT_ZONE_OF_QUEUED, + zone, true, zone_name); + + bitmap_set1(ct_zone_bitmap, zone); + simap_put(ct_zones, zone_name, zone); + return true; +} + static void -update_ct_zones(const struct sset *lports, const struct hmap *local_datapaths, +update_ct_zones(const struct shash *binding_lports, + const struct hmap *local_datapaths, struct simap *ct_zones, unsigned long *ct_zone_bitmap, struct shash *pending_ct_zones) { @@ -629,8 +653,9 @@ update_ct_zones(const struct sset *lports, const struct hmap *local_datapaths, struct simap req_snat_zones = SIMAP_INITIALIZER(&req_snat_zones); unsigned long unreq_snat_zones[BITMAP_N_LONGS(MAX_CT_ZONES)]; - SSET_FOR_EACH(user, lports) { - sset_add(&all_users, user); + struct shash_node *shash_node; + SHASH_FOR_EACH (shash_node, binding_lports) { + sset_add(&all_users, shash_node->name); } /* Local patched datapath (gateway routers) need zones assigned. */ @@ -718,26 +743,12 @@ update_ct_zones(const struct sset *lports, const struct hmap *local_datapaths, /* Assign a unique zone id for each logical port and two zones * to a gateway router. */ SSET_FOR_EACH(user, &all_users) { - int zone; - if (simap_contains(ct_zones, user)) { continue; } - /* We assume that there are 64K zones and that we own them all. */ - zone = bitmap_scan(ct_zone_bitmap, 0, scan_start, MAX_CT_ZONES + 1); - if (zone == MAX_CT_ZONES + 1) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); - VLOG_WARN_RL(&rl, "exhausted all ct zones"); - break; - } - scan_start = zone + 1; - - add_pending_ct_zone_entry(pending_ct_zones, CT_ZONE_OF_QUEUED, - zone, true, user); - - bitmap_set1(ct_zone_bitmap, zone); - simap_put(ct_zones, user, zone); + alloc_id_to_ct_zone(user, ct_zones, ct_zone_bitmap, &scan_start, + pending_ct_zones); } simap_destroy(&req_snat_zones); @@ -1775,6 +1786,9 @@ struct ed_type_ct_zones { unsigned long bitmap[BITMAP_N_LONGS(MAX_CT_ZONES)]; struct shash pending; struct simap current; + + /* Tracked data. */ + bool recomputed; }; static void * @@ -1797,6 +1811,13 @@ en_ct_zones_init(struct engine_node *node, struct engine_arg *arg OVS_UNUSED) return data; } +static void +en_ct_zones_clear_tracked_data(void *data_) +{ + struct ed_type_ct_zones *data = data_; + data->recomputed = false; +} + static void en_ct_zones_cleanup(void *data) { @@ -1813,11 +1834,12 @@ en_ct_zones_run(struct engine_node *node, void *data) struct ed_type_runtime_data *rt_data = engine_get_input_data("runtime_data", node); - update_ct_zones(&rt_data->local_lports, &rt_data->local_datapaths, + update_ct_zones(&rt_data->lbinding_data.lports, &rt_data->local_datapaths, &ct_zones_data->current, ct_zones_data->bitmap, &ct_zones_data->pending); + ct_zones_data->recomputed = true; engine_set_node_state(node, EN_UPDATED); } @@ -1875,7 +1897,7 @@ ct_zones_datapath_binding_handler(struct engine_node *node, void *data) } static bool -ct_zones_runtime_data_handler(struct engine_node *node, void *data OVS_UNUSED) +ct_zones_runtime_data_handler(struct engine_node *node, void *data) { struct ed_type_runtime_data *rt_data = engine_get_input_data("runtime_data", node); @@ -1885,24 +1907,51 @@ ct_zones_runtime_data_handler(struct engine_node *node, void *data OVS_UNUSED) return false; } - /* If local_lports have changed then fall back to full recompute. */ - if (rt_data->local_lports_changed) { - return false; - } + struct ed_type_ct_zones *ct_zones_data = data; struct hmap *tracked_dp_bindings = &rt_data->tracked_dp_bindings; struct tracked_datapath *tdp; + int scan_start = 0; + + bool updated = false; + HMAP_FOR_EACH (tdp, node, tracked_dp_bindings) { if (tdp->tracked_type == TRACKED_RESOURCE_NEW) { /* A new datapath has been added. Fall back to full recompute. */ return false; } - /* When an lport is claimed or released because of port binding, - * changes we don't have to compute the ct zone entries for these. - * That is because we generate the ct zone entries for each local - * OVS interface which has external_ids:iface-id set. For the local - * OVS interface changes, rt_data->local_ports_changed will be true. */ + struct shash_node *shash_node; + SHASH_FOR_EACH (shash_node, &tdp->lports) { + struct tracked_lport *t_lport = shash_node->data; + if (t_lport->tracked_type == TRACKED_RESOURCE_NEW) { + if (!simap_contains(&ct_zones_data->current, + t_lport->pb->logical_port)) { + alloc_id_to_ct_zone(t_lport->pb->logical_port, + &ct_zones_data->current, + ct_zones_data->bitmap, &scan_start, + &ct_zones_data->pending); + updated = true; + } + } else if (t_lport->tracked_type == TRACKED_RESOURCE_REMOVED) { + struct simap_node *ct_zone = + simap_find(&ct_zones_data->current, + t_lport->pb->logical_port); + if (ct_zone) { + add_pending_ct_zone_entry( + &ct_zones_data->pending, CT_ZONE_DB_QUEUED, + ct_zone->data, false, ct_zone->name); + + bitmap_set0(ct_zones_data->bitmap, ct_zone->data); + simap_delete(&ct_zones_data->current, ct_zone); + updated = true; + } + } + } + } + + if (updated) { + engine_set_node_state(node, EN_UPDATED); } return true; @@ -2684,6 +2733,25 @@ pflow_output_runtime_data_handler(struct engine_node *node, void *data) return true; } +static bool +pflow_output_ct_zones_handler(struct engine_node *node OVS_UNUSED, + void *data OVS_UNUSED) +{ + struct ed_type_ct_zones *ct_zones_data = + engine_get_input_data("ct_zones", node); + + /* If ct_zones engine node was recomputed, then fall back to full + * recompute of pflow_output. Otherwise there is no need to do + * anything for the following reasons: + * - When an lport is claimed, ct zone handler for the + * runtime_data handler allocates the zone id for the lport (and it is + * saved in the br-int external_ids). + * - pflow_output handler for the runtime data changes adds + * the physical flows for the claimed lport. + * */ + return !ct_zones_data->recomputed; +} + static void * en_flow_output_init(struct engine_node *node OVS_UNUSED, struct engine_arg *arg OVS_UNUSED) @@ -2932,7 +3000,7 @@ main(int argc, char *argv[]) stopwatch_create(OFCTRL_PUT_STOPWATCH_NAME, SW_MS); /* Define inc-proc-engine nodes. */ - ENGINE_NODE_CUSTOM_DATA(ct_zones, "ct_zones"); + ENGINE_NODE_CUSTOM_WITH_CLEAR_TRACK_DATA(ct_zones, "ct_zones"); ENGINE_NODE_WITH_CLEAR_TRACK_DATA(runtime_data, "runtime_data"); ENGINE_NODE(mff_ovn_geneve, "mff_ovn_geneve"); ENGINE_NODE(ofctrl_is_connected, "ofctrl_is_connected"); @@ -2966,7 +3034,8 @@ main(int argc, char *argv[]) */ engine_add_input(&en_pflow_output, &en_ovs_interface, pflow_output_ovs_iface_handler); - engine_add_input(&en_pflow_output, &en_ct_zones, NULL); + engine_add_input(&en_pflow_output, &en_ct_zones, + pflow_output_ct_zones_handler); engine_add_input(&en_pflow_output, &en_sb_chassis, pflow_lflow_output_sb_chassis_handler); diff --git a/lib/inc-proc-eng.h b/lib/inc-proc-eng.h index 7e9f5bb70..859b30a71 100644 --- a/lib/inc-proc-eng.h +++ b/lib/inc-proc-eng.h @@ -302,6 +302,10 @@ void engine_ovsdb_node_add_index(struct engine_node *, const char *name, #define ENGINE_NODE_CUSTOM_DATA(NAME, NAME_STR) \ ENGINE_NODE_DEF(NAME, NAME_STR) +#define ENGINE_NODE_CUSTOM_WITH_CLEAR_TRACK_DATA(NAME, NAME_STR) \ + ENGINE_NODE_CUSTOM_DATA(NAME, NAME_STR) \ + en_##NAME.clear_tracked_data = en_##NAME##_clear_tracked_data; + #define ENGINE_NODE(NAME, NAME_STR) \ static bool (*en_##NAME##_is_valid)(struct engine_node *node) = NULL; \ ENGINE_NODE_DEF(NAME, NAME_STR) diff --git a/tests/ovn.at b/tests/ovn.at index e5d8869a8..ce3d64c82 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -23122,7 +23122,7 @@ OVS_WAIT_UNTIL([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw0_dpkey reg15=0x${p1_dpkey} | grep REG13 | wc -l) -eq 0]) p1_zoneid=$(as hv1 ovs-vsctl get bridge br-int external_ids:ct-zone-sw0-p1 | sed 's/"//g') -AT_CHECK([test ! -z $p1_zoneid]) +AT_CHECK([test -z $p1_zoneid]) OVN_CLEANUP([hv1]) AT_CLEANUP