From patchwork Fri Jun 2 12:31:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miguel Angel Ajo X-Patchwork-Id: 770313 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3wfNsm55JPz9s71 for ; Fri, 2 Jun 2017 22:33:16 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 5DF72B30; Fri, 2 Jun 2017 12:31:59 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 31687905 for ; Fri, 2 Jun 2017 12:31:58 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-wm0-f48.google.com (mail-wm0-f48.google.com [74.125.82.48]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id E4CDD106 for ; Fri, 2 Jun 2017 12:31:56 +0000 (UTC) Received: by mail-wm0-f48.google.com with SMTP id 7so24241967wmo.1 for ; Fri, 02 Jun 2017 05:31:56 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=dkGbd08ydAPZVph/yIgvazbUZqKCNit/j1tdZ52Cb3A=; b=fGTBGuZcrIUdw3XqBLEzefif1IfWu2wCAyk/7vl2OvPCNjnxGcKmgl19zyUM53lrxT DReEemXBoihm/imOo28BjMs8stC57Eu0nJlclK+2SHYoNxpwm/8ymLt/8OlmyTLZ8E8U pNudkO86LJKz/UmLLU4Ev8/+sTkLC93ErwNGjjIRlLLQQxHUAilNROV867QOQ4MvpM/n 3exOGPh9Mc5lnDZHShRMTF6C4lbc0VWQXKVcX7hoaMoqsBLEiwLwWuuLDGrv4OV2H1+p oNRGLhM0oqZF6h2Z8eeH2LKn4VqBOb8lwAi+gZ1jexuWDhmcoi+p5iFDeHrJs2UG+2TB foag== X-Gm-Message-State: AODbwcCFhduiVn6bFmExkXO5kZ3pmuY/Psd/jYI/FgOJhYL/cAXBpPg5 g+oggoybUKU04bW1oFmJTw== X-Received: by 10.223.182.152 with SMTP id j24mr1866653wre.122.1496406715183; Fri, 02 Jun 2017 05:31:55 -0700 (PDT) Received: from gw1.localdomain (111.148.134.37.dynamic.jazztel.es. [37.134.148.111]) by smtp.gmail.com with ESMTPSA id e19sm2404375wma.25.2017.06.02.05.31.53 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 02 Jun 2017 05:31:53 -0700 (PDT) From: majopela@redhat.com To: dev@openvswitch.org Date: Fri, 2 Jun 2017 12:31:42 +0000 Message-Id: <1496406704-15393-3-git-send-email-majopela@redhat.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1496406704-15393-1-git-send-email-majopela@redhat.com> References: <1496406704-15393-1-git-send-email-majopela@redhat.com> X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: venkata anil Subject: [ovs-dev] [PATCH v1 2/4] ovn: l3ha, enable bfd between tunnel endpoints X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org From: venkata anil This patch enables bfd protocol between gateways and transport nodes, all gateway nodes with any HA chassisredirect port will enable BFD to all tunnel endpoints, while transport nodes will enable BFD to all tunnel endpoints hosting an HA gateway chassisredirect port. Signed-off-by: Venkata Anil --- ovn/controller/binding.c | 202 ++++++++++++++++++++++++++++++++++++---- ovn/controller/binding.h | 3 + ovn/controller/ovn-controller.c | 4 + ovn/controller/ovn-controller.h | 3 + 4 files changed, 194 insertions(+), 18 deletions(-) diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c index d45c5df..431b61e 100644 --- a/ovn/controller/binding.c +++ b/ovn/controller/binding.c @@ -58,6 +58,8 @@ binding_register_ovs_idl(struct ovsdb_idl *ovs_idl) ovsdb_idl_add_table(ovs_idl, &ovsrec_table_interface); ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_name); ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_external_ids); + ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_bfd); + ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_bfd_status); ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_status); ovsdb_idl_add_table(ovs_idl, &ovsrec_table_qos); @@ -68,7 +70,8 @@ static void get_local_iface_ids(const struct ovsrec_bridge *br_int, struct shash *lport_to_iface, struct sset *local_lports, - struct sset *egress_ifaces) + struct sset *egress_ifaces, + struct sset *active_tunnels) { int i; @@ -100,6 +103,20 @@ get_local_iface_ids(const struct ovsrec_bridge *br_int, if (tunnel_iface) { sset_add(egress_ifaces, tunnel_iface); } + /* Add ovn-chassis-id if the bfd_status of the tunnel + * is active */ + const char *bfd = smap_get(&iface_rec->bfd, "enable"); + if (bfd && !strcmp(bfd, "true")) { + const char *status = smap_get(&iface_rec->bfd_status, + "state"); + if (status && !strcmp(status, "up")) { + const char *id = smap_get(&port_rec->external_ids, + "ovn-chassis-id"); + if (id) { + sset_add(active_tunnels, id); + } + } + } } } } @@ -110,7 +127,8 @@ add_local_datapath__(const struct ldatapath_index *ldatapaths, const struct lport_index *lports, const struct sbrec_datapath_binding *datapath, bool has_local_l3gateway, int depth, - struct hmap *local_datapaths) + struct hmap *local_datapaths, + bool has_local_redirectchassis) { uint32_t dp_key = datapath->tunnel_key; @@ -119,6 +137,9 @@ add_local_datapath__(const struct ldatapath_index *ldatapaths, if (has_local_l3gateway) { ld->has_local_l3gateway = true; } + if (has_local_redirectchassis) { + ld->has_local_redirectchassis = true; + } return; } @@ -129,6 +150,7 @@ add_local_datapath__(const struct ldatapath_index *ldatapaths, ovs_assert(ld->ldatapath); ld->localnet_port = NULL; ld->has_local_l3gateway = has_local_l3gateway; + ld->has_local_redirectchassis = has_local_redirectchassis; if (depth >= 100) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); @@ -146,7 +168,14 @@ add_local_datapath__(const struct ldatapath_index *ldatapaths, lports, peer_name); if (peer && peer->datapath) { add_local_datapath__(ldatapaths, lports, peer->datapath, - false, depth + 1, local_datapaths); + false, depth + 1, local_datapaths, + false); + ld->n_peer_dps++; + ld->peer_dps = xrealloc( + ld->peer_dps, + ld->n_peer_dps * sizeof *ld->peer_dps); + ld->peer_dps[ld->n_peer_dps - 1] = ldatapath_lookup_by_key( + ldatapaths, peer->datapath->tunnel_key); } } } @@ -157,10 +186,11 @@ static void add_local_datapath(const struct ldatapath_index *ldatapaths, const struct lport_index *lports, const struct sbrec_datapath_binding *datapath, - bool has_local_l3gateway, struct hmap *local_datapaths) + bool has_local_l3gateway, struct hmap *local_datapaths, + bool has_local_redirectchassis) { add_local_datapath__(ldatapaths, lports, datapath, has_local_l3gateway, 0, - local_datapaths); + local_datapaths, has_local_redirectchassis); } static void @@ -362,10 +392,12 @@ consider_local_datapath(struct controller_ctx *ctx, struct hmap *qos_map, struct hmap *local_datapaths, struct shash *lport_to_iface, - struct sset *local_lports) + struct sset *local_lports, + struct sset *active_tunnels) { const struct ovsrec_interface *iface_rec = shash_find_data(lport_to_iface, binding_rec->logical_port); + struct ovs_list *redirect_chassis = NULL; bool our_chassis = false; if (iface_rec @@ -376,7 +408,7 @@ consider_local_datapath(struct controller_ctx *ctx, sset_add(local_lports, binding_rec->logical_port); } add_local_datapath(ldatapaths, lports, binding_rec->datapath, - false, local_datapaths); + false, local_datapaths, false); if (iface_rec && qos_map && ctx->ovs_idl_txn) { get_qos_params(binding_rec, qos_map); } @@ -391,24 +423,35 @@ consider_local_datapath(struct controller_ctx *ctx, if (our_chassis) { sset_add(local_lports, binding_rec->logical_port); add_local_datapath(ldatapaths, lports, binding_rec->datapath, - false, local_datapaths); + false, local_datapaths, false); } } else if (!strcmp(binding_rec->type, "chassisredirect")) { - if (pb_redirect_chassis_contains(binding_rec, chassis_rec)) { + redirect_chassis = parse_redirect_chassis(binding_rec); + + if (redirect_chassis && + redirect_chassis_contains(redirect_chassis, chassis_rec)) { + struct redirect_chassis *rc; + LIST_FOR_EACH (rc, node, redirect_chassis) { + if (!strcmp(rc->chassis_id, chassis_rec->name)) { + /* sb_rec_port_binding->chassis should reflect master */ + our_chassis = true; + break; + } + if (sset_contains(active_tunnels, rc->chassis_id)) { + break; + } + } add_local_datapath(ldatapaths, lports, binding_rec->datapath, - false, local_datapaths); - // XXX this should only be set to true if our chassis - // (chassis_rec) is the master for this chassisredirect port - // but for now we'll bind it only when not bound - our_chassis = !binding_rec->chassis; + false, local_datapaths, our_chassis); } + redirect_chassis_destroy(redirect_chassis); } else if (!strcmp(binding_rec->type, "l3gateway")) { const char *chassis_id = smap_get(&binding_rec->options, "l3gateway-chassis"); our_chassis = chassis_id && !strcmp(chassis_id, chassis_rec->name); if (our_chassis) { add_local_datapath(ldatapaths, lports, binding_rec->datapath, - true, local_datapaths); + true, local_datapaths, false); } } else if (!strcmp(binding_rec->type, "localnet")) { /* Add all localnet ports to local_lports so that we allocate ct zones @@ -457,12 +500,13 @@ binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int, const struct sbrec_port_binding *binding_rec; struct shash lport_to_iface = SHASH_INITIALIZER(&lport_to_iface); struct sset egress_ifaces = SSET_INITIALIZER(&egress_ifaces); + struct sset active_tunnels = SSET_INITIALIZER(&active_tunnels); struct hmap qos_map; hmap_init(&qos_map); if (br_int) { get_local_iface_ids(br_int, &lport_to_iface, local_lports, - &egress_ifaces); + &egress_ifaces, &active_tunnels); } /* Run through each binding record to see if it is resident on this @@ -473,10 +517,9 @@ binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int, chassis_rec, binding_rec, sset_is_empty(&egress_ifaces) ? NULL : &qos_map, local_datapaths, &lport_to_iface, - local_lports); + local_lports, &active_tunnels); } - if (!sset_is_empty(&egress_ifaces) && set_noop_qos(ctx, &egress_ifaces)) { const char *entry; @@ -487,9 +530,132 @@ binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int, shash_destroy(&lport_to_iface); sset_destroy(&egress_ifaces); + sset_destroy(&active_tunnels); hmap_destroy(&qos_map); } + +static void +calculate_bfd_chassis(struct sset *bfd_chassis, + const struct sbrec_chassis *our_chassis, + struct hmap *local_datapaths) +{ + /* Identify all chassis nodes to which we need to enable bfd. + * 1) Any chassis hosting the chassisredirect ports for known + * router datapaths. + * 2) Chassis hosting peer datapaths (with ports) connected + * to a router datapath when our chassis is hosting a router + * with a chassis redirect port. */ + struct local_datapath *dp; + HMAP_FOR_EACH (dp, hmap_node, local_datapaths) { + const char *is_router = smap_get(&dp->datapath->external_ids, + "logical-router"); + bool our_chassis_is_gw_for_dp = false; + if (is_router) { + for (size_t j = 0; j < dp->ldatapath->n_lports; j++) { + const struct sbrec_port_binding *pb = dp->ldatapath->lports[j]; + if (!strcmp(pb->type, "chassisredirect")) { + struct ovs_list *redirect_chassis = NULL; + redirect_chassis = parse_redirect_chassis(pb); + /* we don't need BFD for non-HA chassisredirect */ + if (!redirect_chassis || + ovs_list_is_short(redirect_chassis)) { + continue; + } + our_chassis_is_gw_for_dp = redirect_chassis_contains( + redirect_chassis, our_chassis); + struct redirect_chassis *chassis; + LIST_FOR_EACH (chassis, node, redirect_chassis) { + sset_add(bfd_chassis, chassis->chassis_id); + } + redirect_chassis_destroy(redirect_chassis); + break; + } + } + } + if (our_chassis_is_gw_for_dp) { + for (size_t i = 0; i < dp->n_peer_dps; i++) { + const struct ldatapath *pdp = dp->peer_dps[i]; + if (!pdp) { + continue; + } + for (size_t j = 0; j < pdp->n_lports; j++) { + const struct sbrec_port_binding *pb = pdp->lports[j]; + const char *chassis_name = NULL; + if (!pb->chassis) { + continue; + } + /* Gateway node has to enable bfd to all nodes hosting + * connected network ports */ + chassis_name = pb->chassis->name; + if (chassis_name) { + sset_add(bfd_chassis, chassis_name); + } + } + } + } + } +} + +void +bfd_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int, + const struct sbrec_chassis *chassis_rec, + struct hmap *local_datapaths) +{ + if (!chassis_rec) { + return; + } + struct sset bfd_chassis = SSET_INITIALIZER(&bfd_chassis); + /* Identify all chassis nodes to which we need to enable bfd */ + calculate_bfd_chassis(&bfd_chassis, chassis_rec, local_datapaths); + + /* Identify tunnels ports(connected to remote chassis id) to enable bfd */ + struct sset tunnels = SSET_INITIALIZER(&tunnels); + struct sset bfd_ifaces = SSET_INITIALIZER(&bfd_ifaces); + for (size_t k = 0; k < br_int->n_ports; k++) { + const char *chassis_id = smap_get(&br_int->ports[k]->external_ids, + "ovn-chassis-id"); + if (chassis_id) { + char *port_name = br_int->ports[k]->name; + sset_add(&tunnels, port_name); + if (sset_contains(&bfd_chassis, chassis_id)) { + sset_add(&bfd_ifaces, port_name); + } + } + } + + /* Enable or disable bfd */ + const struct ovsrec_interface *iface; + struct smap bfd = SMAP_INITIALIZER(&bfd); + OVSREC_INTERFACE_FOR_EACH (iface, ctx->ovs_idl) { + if (sset_contains(&tunnels, iface->name)) { + const char *bfd_enabled = smap_get(&iface->bfd, "enable"); + if (sset_contains(&bfd_ifaces, iface->name)) { + smap_add(&bfd, "enable", "true"); + if (bfd_enabled && !strcmp(bfd_enabled, "true")) { + /* If already set to true we skip setting it again + * to avoid flapping to bfd initialization state */ + continue; + } + ovsrec_interface_verify_bfd(iface); + ovsrec_interface_set_bfd(iface, &bfd); + } else { + smap_add(&bfd, "enable", "false"); + if (bfd_enabled && !strcmp(bfd_enabled, "false")) { + /* If already set to false we skip setting it again */ + continue; + } + ovsrec_interface_verify_bfd(iface); + ovsrec_interface_set_bfd(iface, &bfd); + } + } + } + sset_destroy(&bfd_chassis); + sset_destroy(&tunnels); + sset_destroy(&bfd_ifaces); + smap_destroy(&bfd); +} + /* Returns true if the database is all cleaned up, false if more work is * required. */ bool diff --git a/ovn/controller/binding.h b/ovn/controller/binding.h index 3bfa7d1..2b88ec5 100644 --- a/ovn/controller/binding.h +++ b/ovn/controller/binding.h @@ -33,6 +33,9 @@ void binding_run(struct controller_ctx *, const struct ovsrec_bridge *br_int, const struct sbrec_chassis *, const struct ldatapath_index *, const struct lport_index *, struct hmap *local_datapaths, struct sset *all_lports); +void bfd_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int, + const struct sbrec_chassis *chassis_rec, + struct hmap *local_datapaths); bool binding_cleanup(struct controller_ctx *, const struct sbrec_chassis *); #endif /* ovn/binding.h */ diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c index 21893bc..7930b6e 100644 --- a/ovn/controller/ovn-controller.c +++ b/ovn/controller/ovn-controller.c @@ -532,6 +532,8 @@ main(int argc, char *argv[]) ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_open_vswitch_col_bridges); ovsdb_idl_add_table(ovs_idl_loop.idl, &ovsrec_table_interface); ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_interface_col_name); + ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_interface_col_bfd); + ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_interface_col_bfd_status); ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_interface_col_type); ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_interface_col_options); ovsdb_idl_add_column(ovs_idl_loop.idl, &ovsrec_interface_col_ofport); @@ -651,6 +653,7 @@ main(int argc, char *argv[]) &local_datapaths, &group_table, &addr_sets, &flow_table); + bfd_run(&ctx, br_int, chassis, &local_datapaths); physical_run(&ctx, mff_ovn_geneve, br_int, chassis, &ct_zones, &lports, &flow_table, &local_datapaths, &local_lports); @@ -705,6 +708,7 @@ main(int argc, char *argv[]) struct local_datapath *cur_node, *next_node; HMAP_FOR_EACH_SAFE (cur_node, next_node, hmap_node, &local_datapaths) { + free(cur_node->peer_dps); hmap_remove(&local_datapaths, &cur_node->hmap_node); free(cur_node); } diff --git a/ovn/controller/ovn-controller.h b/ovn/controller/ovn-controller.h index 4bc0467..72dfce5 100644 --- a/ovn/controller/ovn-controller.h +++ b/ovn/controller/ovn-controller.h @@ -66,6 +66,9 @@ struct local_datapath { /* True if this datapath contains an l3gateway port located on this * hypervisor. */ bool has_local_l3gateway; + bool has_local_redirectchassis; + const struct ldatapath **peer_dps; + size_t n_peer_dps; }; struct local_datapath *get_local_datapath(const struct hmap *,