From patchwork Wed Jul 28 02:47:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Numan Siddique X-Patchwork-Id: 1510695 X-Patchwork-Delegate: zhouhan@gmail.com 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 4GZJ52197Zz9sWX for ; Wed, 28 Jul 2021 12:48:37 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 85F5560804; Wed, 28 Jul 2021 02:48:35 +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 NiGzqOxyPsY1; Wed, 28 Jul 2021 02:48:33 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp3.osuosl.org (Postfix) with ESMTPS id 680FF6080F; Wed, 28 Jul 2021 02:48:32 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 33286C001C; Wed, 28 Jul 2021 02:48:32 +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 10BE9C001A for ; Wed, 28 Jul 2021 02:48:30 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id E555A60816 for ; Wed, 28 Jul 2021 02:48:11 +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 7LQr3B0E0BMD for ; Wed, 28 Jul 2021 02:48:09 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [217.70.178.231]) by smtp3.osuosl.org (Postfix) with ESMTPS id 274F36081C for ; Wed, 28 Jul 2021 02:48:08 +0000 (UTC) Received: (Authenticated sender: numans@ovn.org) by relay11.mail.gandi.net (Postfix) with ESMTPSA id 3AF3D100002; Wed, 28 Jul 2021 02:48:05 +0000 (UTC) From: numans@ovn.org To: dev@openvswitch.org Date: Tue, 27 Jul 2021 22:47:55 -0400 Message-Id: <20210728024755.2945713-1-numans@ovn.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210728024512.2944939-1-numans@ovn.org> References: <20210728024512.2944939-1-numans@ovn.org> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH ovn v3 4/5] I-P: Handle runtime data changes for pflow_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 a separate engine node - non_vif_data. 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 Acked-by: Han Zhou --- controller/binding.c | 39 ++-- controller/binding.h | 23 ++ controller/lflow.c | 5 +- controller/lflow.h | 1 + controller/local_data.c | 164 +++++++++++++++ controller/local_data.h | 39 ++++ controller/ovn-controller.c | 185 ++++++++++++++--- controller/ovn-controller.h | 8 - controller/physical.c | 404 ++++++++---------------------------- controller/physical.h | 15 +- 10 files changed, 507 insertions(+), 376 deletions(-) diff --git a/controller/binding.c b/controller/binding.c index 61cb8ccf4..a91832921 100644 --- a/controller/binding.c +++ b/controller/binding.c @@ -548,23 +548,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 @@ -618,7 +601,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 *, @@ -703,7 +686,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); @@ -712,6 +696,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) { @@ -873,7 +870,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)) { @@ -2555,7 +2552,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/lflow.c b/controller/lflow.c index 2e4582009..e13a6cc51 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; } @@ -612,6 +614,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, }; /* Parse any meter to be used if this flow should punt packets to 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/local_data.c b/controller/local_data.c index 1dc8c45a1..f4944adfd 100644 --- a/controller/local_data.c +++ b/controller/local_data.c @@ -18,10 +18,14 @@ /* 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 "lport.h" #include "lib/ovn-util.h" #include "lib/ovn-sb-idl.h" #include "local_data.h" @@ -276,6 +280,166 @@ 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 +local_nonvif_data_run(const struct ovsrec_bridge *br_int, + const struct sbrec_chassis *chassis_rec, + struct simap *patch_ofports, + struct hmap *chassis_tunnels) +{ + 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(patch_ofports, localnet, ofport); + break; + } else if (is_patch && l2gateway) { + /* L2 gateway patch ports can be handled just like VIFs. */ + simap_put(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(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 +local_nonvif_data_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 +chassis_tunnels_destroy(struct hmap *chassis_tunnels) +{ + struct chassis_tunnel *tun; + HMAP_FOR_EACH_POP (tun, hmap_node, chassis_tunnels) { + free(tun->chassis_id); + free(tun); + } + hmap_destroy(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/local_data.h b/controller/local_data.h index e29fe928c..6370167bc 100644 --- a/controller/local_data.h +++ b/controller/local_data.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: @@ -116,4 +120,39 @@ 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; +}; + +void local_nonvif_data_run(const struct ovsrec_bridge *br_int, + const struct sbrec_chassis *, + struct simap *patch_ofports, + struct hmap *chassis_tunnels); + +bool local_nonvif_data_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 chassis_tunnels_destroy(struct hmap *chassis_tunnels); + #endif /* controller/local_data.h */ diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 317e9f967..a5169ec0e 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -1939,6 +1939,78 @@ en_mff_ovn_geneve_run(struct engine_node *node, void *data) engine_set_node_state(node, EN_UNCHANGED); } +/* Engine node which is used to handle the Non VIF data like + * - OVS patch ports + * - Tunnel ports and the related chassis information. + */ +struct ed_type_non_vif_data { + struct simap patch_ofports; /* simap of patch ovs ports. */ + struct hmap chassis_tunnels; /* hmap of 'struct chassis_tunnel' from the + * tunnel OVS ports. */ +}; + +static void * +en_non_vif_data_init(struct engine_node *node OVS_UNUSED, + struct engine_arg *arg OVS_UNUSED) +{ + struct ed_type_non_vif_data *data = xzalloc(sizeof *data); + simap_init(&data->patch_ofports); + hmap_init(&data->chassis_tunnels); + return data; +} + +static void +en_non_vif_data_cleanup(void *data OVS_UNUSED) +{ + struct ed_type_non_vif_data *ed_non_vif_data = data; + simap_destroy(&ed_non_vif_data->patch_ofports); + chassis_tunnels_destroy(&ed_non_vif_data->chassis_tunnels); +} + +static void +en_non_vif_data_run(struct engine_node *node, void *data) +{ + struct ed_type_non_vif_data *ed_non_vif_data = data; + simap_destroy(&ed_non_vif_data->patch_ofports); + chassis_tunnels_destroy(&ed_non_vif_data->chassis_tunnels); + simap_init(&ed_non_vif_data->patch_ofports); + hmap_init(&ed_non_vif_data->chassis_tunnels); + + struct ovsrec_open_vswitch_table *ovs_table = + (struct ovsrec_open_vswitch_table *)EN_OVSDB_GET( + engine_get_input("OVS_open_vswitch", node)); + struct ovsrec_bridge_table *bridge_table = + (struct ovsrec_bridge_table *)EN_OVSDB_GET( + engine_get_input("OVS_bridge", node)); + + const struct ovsrec_bridge *br_int = get_br_int(bridge_table, ovs_table); + const char *chassis_id = get_ovs_chassis_id(ovs_table); + ovs_assert(br_int && chassis_id); + + struct ovsdb_idl_index *sbrec_chassis_by_name = + engine_ovsdb_node_get_index( + engine_get_input("SB_chassis", node), + "name"); + + const struct sbrec_chassis *chassis + = chassis_lookup_by_name(sbrec_chassis_by_name, chassis_id); + ovs_assert(chassis); + + local_nonvif_data_run(br_int, chassis, &ed_non_vif_data->patch_ofports, + &ed_non_vif_data->chassis_tunnels); + engine_set_node_state(node, EN_UPDATED); +} + +static bool +non_vif_data_ovs_iface_handler(struct engine_node *node, void *data OVS_UNUSED) +{ + struct ovsrec_interface_table *iface_table = + (struct ovsrec_interface_table *)EN_OVSDB_GET( + engine_get_input("OVS_interface", node)); + + return local_nonvif_data_handle_ovs_iface_changes(iface_table); +} + struct lflow_output_persistent_data { uint32_t conj_id_ofs; struct lflow_cache *lflow_cache; @@ -1962,6 +2034,7 @@ struct ed_type_lflow_output { static void init_lflow_ctx(struct engine_node *node, struct ed_type_runtime_data *rt_data, + struct ed_type_non_vif_data *non_vif_data, struct ed_type_lflow_output *fo, struct lflow_ctx_in *l_ctx_in, struct lflow_ctx_out *l_ctx_out) @@ -2068,6 +2141,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 = &non_vif_data->chassis_tunnels; l_ctx_out->flow_table = &fo->flow_table; l_ctx_out->group_table = &fo->group_table; @@ -2107,6 +2181,8 @@ en_lflow_output_run(struct engine_node *node, void *data) { struct ed_type_runtime_data *rt_data = engine_get_input_data("runtime_data", node); + struct ed_type_non_vif_data *non_vif_data = + engine_get_input_data("non_vif_data", node); struct ovsrec_open_vswitch_table *ovs_table = (struct ovsrec_open_vswitch_table *)EN_OVSDB_GET( @@ -2155,7 +2231,7 @@ en_lflow_output_run(struct engine_node *node, void *data) struct lflow_ctx_in l_ctx_in; struct lflow_ctx_out l_ctx_out; - init_lflow_ctx(node, rt_data, fo, &l_ctx_in, &l_ctx_out); + init_lflow_ctx(node, rt_data, non_vif_data, fo, &l_ctx_in, &l_ctx_out); lflow_run(&l_ctx_in, &l_ctx_out); if (l_ctx_out.conj_id_overflow) { @@ -2182,6 +2258,8 @@ lflow_output_sb_logical_flow_handler(struct engine_node *node, void *data) { struct ed_type_runtime_data *rt_data = engine_get_input_data("runtime_data", node); + struct ed_type_non_vif_data *non_vif_data = + engine_get_input_data("non_vif_data", node); struct ovsrec_open_vswitch_table *ovs_table = (struct ovsrec_open_vswitch_table *)EN_OVSDB_GET( engine_get_input("OVS_open_vswitch", node)); @@ -2194,7 +2272,7 @@ lflow_output_sb_logical_flow_handler(struct engine_node *node, void *data) struct ed_type_lflow_output *fo = data; struct lflow_ctx_in l_ctx_in; struct lflow_ctx_out l_ctx_out; - init_lflow_ctx(node, rt_data, fo, &l_ctx_in, &l_ctx_out); + init_lflow_ctx(node, rt_data, non_vif_data, fo, &l_ctx_in, &l_ctx_out); bool handled = lflow_handle_changed_flows(&l_ctx_in, &l_ctx_out); @@ -2232,12 +2310,14 @@ lflow_output_sb_multicast_group_handler(struct engine_node *node, void *data) { struct ed_type_runtime_data *rt_data = engine_get_input_data("runtime_data", node); + struct ed_type_non_vif_data *non_vif_data = + engine_get_input_data("non_vif_data", node); struct ed_type_lflow_output *lfo = data; struct lflow_ctx_in l_ctx_in; struct lflow_ctx_out l_ctx_out; - init_lflow_ctx(node, rt_data, lfo, &l_ctx_in, &l_ctx_out); + init_lflow_ctx(node, rt_data, non_vif_data, lfo, &l_ctx_in, &l_ctx_out); if (!lflow_handle_changed_mc_groups(&l_ctx_in, &l_ctx_out)) { return false; } @@ -2251,12 +2331,14 @@ lflow_output_sb_port_binding_handler(struct engine_node *node, void *data) { struct ed_type_runtime_data *rt_data = engine_get_input_data("runtime_data", node); + struct ed_type_non_vif_data *non_vif_data = + engine_get_input_data("non_vif_data", node); struct ed_type_lflow_output *lfo = data; struct lflow_ctx_in l_ctx_in; struct lflow_ctx_out l_ctx_out; - init_lflow_ctx(node, rt_data, lfo, &l_ctx_in, &l_ctx_out); + init_lflow_ctx(node, rt_data, non_vif_data, lfo, &l_ctx_in, &l_ctx_out); if (!lflow_handle_changed_port_bindings(&l_ctx_in, &l_ctx_out)) { return false; } @@ -2271,6 +2353,8 @@ _lflow_output_resource_ref_handler(struct engine_node *node, void *data, { struct ed_type_runtime_data *rt_data = engine_get_input_data("runtime_data", node); + struct ed_type_non_vif_data *non_vif_data = + engine_get_input_data("non_vif_data", node); struct ed_type_addr_sets *as_data = engine_get_input_data("addr_sets", node); @@ -2302,7 +2386,7 @@ _lflow_output_resource_ref_handler(struct engine_node *node, void *data, struct lflow_ctx_in l_ctx_in; struct lflow_ctx_out l_ctx_out; - init_lflow_ctx(node, rt_data, fo, &l_ctx_in, &l_ctx_out); + init_lflow_ctx(node, rt_data, non_vif_data, fo, &l_ctx_in, &l_ctx_out); bool changed; const char *ref_name; @@ -2389,6 +2473,8 @@ lflow_output_runtime_data_handler(struct engine_node *node, { struct ed_type_runtime_data *rt_data = engine_get_input_data("runtime_data", node); + struct ed_type_non_vif_data *non_vif_data = + engine_get_input_data("non_vif_data", node); /* There is no tracked data. Fall back to full recompute of * flow_output. */ @@ -2407,7 +2493,7 @@ lflow_output_runtime_data_handler(struct engine_node *node, struct lflow_ctx_in l_ctx_in; struct lflow_ctx_out l_ctx_out; struct ed_type_lflow_output *fo = data; - init_lflow_ctx(node, rt_data, fo, &l_ctx_in, &l_ctx_out); + init_lflow_ctx(node, rt_data, non_vif_data, fo, &l_ctx_in, &l_ctx_out); struct tracked_datapath *tdp; HMAP_FOR_EACH (tdp, node, tracked_dp_bindings) { @@ -2437,11 +2523,13 @@ lflow_output_sb_load_balancer_handler(struct engine_node *node, void *data) { struct ed_type_runtime_data *rt_data = engine_get_input_data("runtime_data", node); + struct ed_type_non_vif_data *non_vif_data = + engine_get_input_data("non_vif_data", node); struct ed_type_lflow_output *fo = data; struct lflow_ctx_in l_ctx_in; struct lflow_ctx_out l_ctx_out; - init_lflow_ctx(node, rt_data, fo, &l_ctx_in, &l_ctx_out); + init_lflow_ctx(node, rt_data, non_vif_data, fo, &l_ctx_in, &l_ctx_out); bool handled = lflow_handle_changed_lbs(&l_ctx_in, &l_ctx_out); @@ -2454,11 +2542,13 @@ lflow_output_sb_fdb_handler(struct engine_node *node, void *data) { struct ed_type_runtime_data *rt_data = engine_get_input_data("runtime_data", node); + struct ed_type_non_vif_data *non_vif_data = + engine_get_input_data("non_vif_data", node); struct ed_type_lflow_output *fo = data; struct lflow_ctx_in l_ctx_in; struct lflow_ctx_out l_ctx_out; - init_lflow_ctx(node, rt_data, fo, &l_ctx_in, &l_ctx_out); + init_lflow_ctx(node, rt_data, non_vif_data, fo, &l_ctx_in, &l_ctx_out); bool handled = lflow_handle_changed_fdbs(&l_ctx_in, &l_ctx_out); @@ -2473,6 +2563,7 @@ struct ed_type_pflow_output { static void init_physical_ctx(struct engine_node *node, struct ed_type_runtime_data *rt_data, + struct ed_type_non_vif_data *non_vif_data, struct physical_ctx *p_ctx) { struct ovsdb_idl_index *sbrec_port_binding_by_name = @@ -2514,10 +2605,6 @@ static void init_physical_ctx(struct engine_node *node, ovs_assert(br_int && chassis); - struct ovsrec_interface_table *iface_table = - (struct ovsrec_interface_table *)EN_OVSDB_GET( - engine_get_input("OVS_interface", node)); - struct ed_type_ct_zones *ct_zones_data = engine_get_input_data("ct_zones", node); struct simap *ct_zones = &ct_zones_data->current; @@ -2527,7 +2614,6 @@ static void init_physical_ctx(struct engine_node *node, p_ctx->mc_group_table = multicast_group_table; p_ctx->br_int = br_int; p_ctx->chassis_table = chassis_table; - p_ctx->iface_table = iface_table; p_ctx->chassis = chassis; p_ctx->active_tunnels = &rt_data->active_tunnels; p_ctx->local_datapaths = &rt_data->local_datapaths; @@ -2535,6 +2621,8 @@ 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->patch_ofports = &non_vif_data->patch_ofports; + p_ctx->chassis_tunnels = &non_vif_data->chassis_tunnels; } static void * @@ -2567,9 +2655,11 @@ en_pflow_output_run(struct engine_node *node, void *data) struct ed_type_runtime_data *rt_data = engine_get_input_data("runtime_data", node); + struct ed_type_non_vif_data *non_vif_data = + engine_get_input_data("non_vif_data", node); struct physical_ctx p_ctx; - init_physical_ctx(node, rt_data, &p_ctx); + init_physical_ctx(node, rt_data, non_vif_data, &p_ctx); physical_run(&p_ctx, pflow_table); engine_set_node_state(node, EN_UPDATED); @@ -2581,17 +2671,23 @@ pflow_output_sb_port_binding_handler(struct engine_node *node, { struct ed_type_runtime_data *rt_data = engine_get_input_data("runtime_data", node); + struct ed_type_non_vif_data *non_vif_data = + engine_get_input_data("non_vif_data", node); struct ed_type_pflow_output *pfo = data; struct physical_ctx p_ctx; - init_physical_ctx(node, rt_data, &p_ctx); + init_physical_ctx(node, rt_data, non_vif_data, &p_ctx); /* We handle port-binding changes for physical flow processing * 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; @@ -2602,11 +2698,13 @@ pflow_output_sb_multicast_group_handler(struct engine_node *node, void *data) { struct ed_type_runtime_data *rt_data = engine_get_input_data("runtime_data", node); + struct ed_type_non_vif_data *non_vif_data = + engine_get_input_data("non_vif_data", node); struct ed_type_pflow_output *pfo = data; struct physical_ctx p_ctx; - init_physical_ctx(node, rt_data, &p_ctx); + init_physical_ctx(node, rt_data, non_vif_data, &p_ctx); physical_handle_mc_group_changes(&p_ctx, &pfo->flow_table); @@ -2615,19 +2713,49 @@ pflow_output_sb_multicast_group_handler(struct engine_node *node, void *data) } static bool -pflow_output_ovs_iface_handler(struct engine_node *node OVS_UNUSED, - void *data OVS_UNUSED) +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); + struct ed_type_non_vif_data *non_vif_data = + engine_get_input_data("non_vif_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); + init_physical_ctx(node, rt_data, non_vif_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 * @@ -2887,6 +3015,7 @@ main(int argc, char *argv[]) /* Define inc-proc-engine nodes. */ ENGINE_NODE_CUSTOM_DATA(ct_zones, "ct_zones"); ENGINE_NODE_WITH_CLEAR_TRACK_DATA(runtime_data, "runtime_data"); + ENGINE_NODE(non_vif_data, "non_vif_data"); ENGINE_NODE(mff_ovn_geneve, "mff_ovn_geneve"); ENGINE_NODE(ofctrl_is_connected, "ofctrl_is_connected"); ENGINE_NODE(pflow_output, "physical_flow_output"); @@ -2914,11 +3043,17 @@ main(int argc, char *argv[]) engine_add_input(&en_port_groups, &en_runtime_data, port_groups_runtime_data_handler); + engine_add_input(&en_non_vif_data, &en_ovs_open_vswitch, NULL); + engine_add_input(&en_non_vif_data, &en_ovs_bridge, NULL); + engine_add_input(&en_non_vif_data, &en_sb_chassis, NULL); + engine_add_input(&en_non_vif_data, &en_ovs_interface, + non_vif_data_ovs_iface_handler); + /* Note: The order of inputs is important, all OVS interface changes must * be handled before any ct_zone changes. */ - engine_add_input(&en_pflow_output, &en_ovs_interface, - pflow_output_ovs_iface_handler); + engine_add_input(&en_pflow_output, &en_non_vif_data, + NULL); engine_add_input(&en_pflow_output, &en_ct_zones, NULL); engine_add_input(&en_pflow_output, &en_sb_chassis, pflow_lflow_output_sb_chassis_handler); @@ -2929,7 +3064,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); @@ -2941,6 +3076,8 @@ main(int argc, char *argv[]) lflow_output_port_groups_handler); engine_add_input(&en_lflow_output, &en_runtime_data, lflow_output_runtime_data_handler); + engine_add_input(&en_lflow_output, &en_non_vif_data, + NULL); engine_add_input(&en_lflow_output, &en_sb_multicast_group, lflow_output_sb_multicast_group_handler); 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 188606927..2b8189246 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; } @@ -926,6 +888,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, @@ -1082,17 +1047,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] && @@ -1103,12 +1076,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; @@ -1119,7 +1086,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; @@ -1130,7 +1097,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; } @@ -1384,7 +1352,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: @@ -1397,8 +1365,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; @@ -1445,19 +1416,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. */ @@ -1498,7 +1471,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; } @@ -1525,41 +1498,50 @@ 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; - 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); - } + ofctrl_remove_flows(flow_table, &pb->header_.uuid); + + if (!strcmp(pb->type, "external")) { + /* External lports have a dependency on the localnet port. + * We need to remove the flows of the localnet port as well + * and re-consider adding the flows for it. + */ + struct local_datapath *ldp = + get_local_datapath(p_ctx->local_datapaths, + pb->datapath->tunnel_key); + if (ldp && ldp->localnet_port) { + struct ofpbuf ofpacts; + ofctrl_remove_flows(flow_table, &ldp->localnet_port->header_.uuid); + ofpbuf_init(&ofpacts, 0); 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, + p_ctx->local_bindings, + p_ctx->patch_ofports, + p_ctx->chassis_tunnels, + ldp->localnet_port, p_ctx->chassis, flow_table, &ofpacts); + ofpbuf_uninit(&ofpacts); } } - ofpbuf_uninit(&ofpacts); + + if (!removed) { + struct ofpbuf ofpacts; + ofpbuf_init(&ofpacts, 0); + 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->patch_ofports, + p_ctx->chassis_tunnels, pb, + p_ctx->chassis, flow_table, &ofpacts); + ofpbuf_uninit(&ofpacts); + } } void @@ -1575,8 +1557,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->patch_ofports, + p_ctx->chassis, mc, + p_ctx->chassis_tunnels, + flow_table); } } } @@ -1592,135 +1577,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); @@ -1734,16 +1590,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->patch_ofports, + p_ctx->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->patch_ofports, p_ctx->chassis, + mc, p_ctx->chassis_tunnels, + flow_table); } /* Table 0, priority 100. @@ -1758,7 +1618,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->chassis_tunnels) { struct match match = MATCH_CATCHALL_INITIALIZER; match_set_in_port(&match, tun->ofport); @@ -1789,7 +1650,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->chassis_tunnels) { if (tun->type != VXLAN) { continue; } @@ -1926,89 +1787,4 @@ 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) -{ - const struct ovsrec_interface *iface_rec; - OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface_rec, p_ctx->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; - } - } - - 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; -} - -void -physical_clear_unassoc_flows_with_db(struct ovn_desired_flow_table *flow_table) -{ - if (hc_uuid) { - ofctrl_remove_flows(flow_table, hc_uuid); - } } diff --git a/controller/physical.h b/controller/physical.h index feab41df4..c4540ad7f 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. * @@ -49,25 +50,23 @@ struct physical_ctx { const struct ovsrec_bridge *br_int; const struct sbrec_chassis_table *chassis_table; const struct sbrec_chassis *chassis; - const struct ovsrec_interface_table *iface_table; const struct sset *active_tunnels; struct hmap *local_datapaths; struct sset *local_lports; const struct simap *ct_zones; enum mf_field_id mff_ovn_geneve; struct shash *local_bindings; + struct simap *patch_ofports; + struct hmap *chassis_tunnels; }; 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); +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 */