Skip to content

Commit

Permalink
ovn: l3ha, enable bfd between tunnel endpoints
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Miguel Angel Ajo <[email protected]>
Co-Authored-by: Miguel Angel Ajo <[email protected]>
Signed-off-by: Russell Bryant <[email protected]>
  • Loading branch information
2 people authored and russellb committed Jul 16, 2017
1 parent 1da17a0 commit 3475695
Show file tree
Hide file tree
Showing 8 changed files with 353 additions and 13 deletions.
2 changes: 2 additions & 0 deletions ovn/controller/automake.mk
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
bin_PROGRAMS += ovn/controller/ovn-controller
ovn_controller_ovn_controller_SOURCES = \
ovn/controller/bfd.c \
ovn/controller/bfd.h \
ovn/controller/binding.c \
ovn/controller/binding.h \
ovn/controller/chassis.c \
Expand Down
201 changes: 201 additions & 0 deletions ovn/controller/bfd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
/* Copyright (c) 2017 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 <config.h>
#include "bfd.h"
#include "gchassis.h"
#include "lport.h"
#include "ovn-controller.h"

#include "lib/hash.h"
#include "lib/sset.h"
#include "lib/util.h"
#include "lib/vswitch-idl.h"
#include "openvswitch/vlog.h"
#include "ovn/lib/ovn-sb-idl.h"
#include "ovn-controller.h"

VLOG_DEFINE_THIS_MODULE(ovn_bfd);

void
bfd_register_ovs_idl(struct ovsdb_idl *ovs_idl)
{
/* NOTE: this assumes that binding.c has added the
* ovsrec_interface table */
ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_bfd);
ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_bfd_status);
}


static void
interface_set_bfd(const struct ovsrec_interface *iface, bool bfd_setting)
{
const char *new_setting = bfd_setting ? "true":"false";
const char *current_setting = smap_get(&iface->bfd, "enable");
if (current_setting && !strcmp(current_setting, new_setting)) {
/* If already set to the desired setting we skip setting it again
* to avoid flapping to bfd initialization state */
return;
}
const struct smap bfd = SMAP_CONST1(&bfd, "enable", new_setting);
ovsrec_interface_verify_bfd(iface);
ovsrec_interface_set_bfd(iface, &bfd);
VLOG_INFO("%s BFD on interface %s", bfd_setting ? "Enabled" : "Disabled",
iface->name);
}

void
bfd_calculate_active_tunnels(const struct ovsrec_bridge *br_int,
struct sset *active_tunnels)
{
int i;

for (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;
}

int j;
for (j = 0; j < port_rec->n_interfaces; j++) {
const struct ovsrec_interface *iface_rec;
iface_rec = port_rec->interfaces[j];

/* Check if this is a tunnel interface. */
if (smap_get(&iface_rec->options, "remote_ip")) {
/* 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);
}
}
}
}
}
}
}

static void
bfd_calculate_chassis(const struct sbrec_chassis *our_chassis,
struct hmap *local_datapaths,
const struct chassis_index *chassis_index,
struct sset *bfd_chassis)
{
/* 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 *gateway_chassis = NULL;
gateway_chassis =
gateway_chassis_get_ordered(pb, chassis_index);
/* we don't need BFD for non-HA chassisredirect */
if (!gateway_chassis ||
ovs_list_is_short(gateway_chassis)) {
continue;
}
our_chassis_is_gw_for_dp = gateway_chassis_contains(
gateway_chassis, our_chassis);
struct gateway_chassis *gwc;
LIST_FOR_EACH (gwc, node, gateway_chassis) {
if (gwc->db->chassis) {
sset_add(bfd_chassis, gwc->db->chassis->name);
}
}
gateway_chassis_destroy(gateway_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];
if (pb->chassis) {
/* Gateway node has to enable bfd to all nodes hosting
* connected network ports */
const char *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,
const struct chassis_index *chassis_index)
{

if (!chassis_rec) {
return;
}
struct sset bfd_chassis = SSET_INITIALIZER(&bfd_chassis);
bfd_calculate_chassis(chassis_rec, local_datapaths, chassis_index,
&bfd_chassis);
/* 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;
OVSREC_INTERFACE_FOR_EACH (iface, ctx->ovs_idl) {
if (sset_contains(&tunnels, iface->name)) {
interface_set_bfd(
iface, sset_contains(&bfd_ifaces, iface->name));
}
}

sset_destroy(&tunnels);
sset_destroy(&bfd_ifaces);
sset_destroy(&bfd_chassis);
}
34 changes: 34 additions & 0 deletions ovn/controller/bfd.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/* Copyright (c) 2017 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 OVN_BFD_H
#define OVN_BFD_H 1

struct chassis_index;
struct controller_ctx;
struct hmap;
struct ovsdb_idl;
struct ovsrec_bridge;
struct sbrec_chassis;
struct sset;

void bfd_register_ovs_idl(struct ovsdb_idl *);
void bfd_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,
const struct sbrec_chassis *chassis_rec,
struct hmap *local_datapaths, const struct chassis_index *);
void bfd_calculate_active_tunnels(const struct ovsrec_bridge *br_int,
struct sset *active_tunnels);

#endif
47 changes: 36 additions & 11 deletions ovn/controller/binding.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,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);
Expand Down Expand Up @@ -149,6 +151,12 @@ add_local_datapath__(const struct ldatapath_index *ldatapaths,
if (peer && peer->datapath) {
add_local_datapath__(ldatapaths, lports, peer->datapath,
false, depth + 1, local_datapaths);
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);
}
}
}
Expand Down Expand Up @@ -359,6 +367,8 @@ static void
consider_local_datapath(struct controller_ctx *ctx,
const struct ldatapath_index *ldatapaths,
const struct lport_index *lports,
const struct chassis_index *chassis_index,
struct sset *active_tunnels,
const struct sbrec_chassis *chassis_rec,
const struct sbrec_port_binding *binding_rec,
struct hmap *qos_map,
Expand All @@ -368,6 +378,7 @@ consider_local_datapath(struct controller_ctx *ctx,
{
const struct ovsrec_interface *iface_rec
= shash_find_data(lport_to_iface, binding_rec->logical_port);
struct ovs_list *gateway_chassis = NULL;

bool our_chassis = false;
if (iface_rec
Expand Down Expand Up @@ -396,16 +407,28 @@ consider_local_datapath(struct controller_ctx *ctx,
false, local_datapaths);
}
} else if (!strcmp(binding_rec->type, "chassisredirect")) {
if (gateway_chassis_in_pb_contains(binding_rec, chassis_rec)) {
gateway_chassis = gateway_chassis_get_ordered(binding_rec,
chassis_index);
if (gateway_chassis &&
gateway_chassis_contains(gateway_chassis, chassis_rec)) {
struct gateway_chassis *gwc;
LIST_FOR_EACH (gwc, node, gateway_chassis) {
if (!gwc->db->chassis) {
continue;
}
if (!strcmp(gwc->db->chassis->name, chassis_rec->name)) {
/* sb_rec_port_binding->chassis should reflect master */
our_chassis = true;
break;
}
if (sset_contains(active_tunnels, gwc->db->chassis->name)) {
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, this is
* handled in subsequent patches */
our_chassis = !binding_rec->chassis ||
chassis_rec == binding_rec->chassis;
}
gateway_chassis_destroy(gateway_chassis);
} else if (!strcmp(binding_rec->type, "l3gateway")) {
const char *chassis_id = smap_get(&binding_rec->options,
"l3gateway-chassis");
Expand Down Expand Up @@ -475,8 +498,10 @@ void
binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,
const struct sbrec_chassis *chassis_rec,
const struct ldatapath_index *ldatapaths,
const struct lport_index *lports, struct hmap *local_datapaths,
struct sset *local_lports)
const struct lport_index *lports,
const struct chassis_index *chassis_index,
struct sset *active_tunnels,
struct hmap *local_datapaths, struct sset *local_lports)
{
if (!chassis_rec) {
return;
Expand All @@ -497,8 +522,8 @@ binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,
* chassis and update the binding accordingly. This includes both
* directly connected logical ports and children of those ports. */
SBREC_PORT_BINDING_FOR_EACH(binding_rec, ctx->ovnsb_idl) {
consider_local_datapath(ctx, ldatapaths, lports,
chassis_rec, binding_rec,
consider_local_datapath(ctx, ldatapaths, lports, chassis_index,
active_tunnels, chassis_rec, binding_rec,
sset_is_empty(&egress_ifaces) ? NULL :
&qos_map, local_datapaths, &lport_to_iface,
local_lports);
Expand Down
3 changes: 2 additions & 1 deletion ovn/controller/binding.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ struct sset;
void binding_register_ovs_idl(struct ovsdb_idl *);
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,
const struct lport_index *, const struct chassis_index *,
struct sset *active_tunnels, struct hmap *local_datapaths,
struct sset *all_lports);
bool binding_cleanup(struct controller_ctx *, const struct sbrec_chassis *);

Expand Down
Loading

0 comments on commit 3475695

Please sign in to comment.