@@ -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
@@ -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 */
@@ -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);
}
@@ -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 *,