@@ -606,13 +606,13 @@ ovn_lb_get_health_check(const struct nbrec_load_balancer *nbrec_lb,
return NULL;
}
-struct ovn_northd_lb *
-ovn_northd_lb_create(const struct nbrec_load_balancer *nbrec_lb)
+static void
+ovn_northd_lb_init(struct ovn_northd_lb *lb,
+ const struct nbrec_load_balancer *nbrec_lb)
{
bool template = smap_get_bool(&nbrec_lb->options, "template", false);
bool is_udp = nullable_string_is_equal(nbrec_lb->protocol, "udp");
bool is_sctp = nullable_string_is_equal(nbrec_lb->protocol, "sctp");
- struct ovn_northd_lb *lb = xzalloc(sizeof *lb);
int address_family = !strcmp(smap_get_def(&nbrec_lb->options,
"address-family", "ipv4"),
"ipv4")
@@ -668,6 +668,10 @@ ovn_northd_lb_create(const struct nbrec_load_balancer *nbrec_lb)
"reject", false);
ovn_northd_lb_vip_init(lb_vip_nb, lb_vip, nbrec_lb,
node->key, node->value, template);
+ if (lb_vip_nb->lb_health_check) {
+ lb->health_checks = true;
+ }
+
if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) {
sset_add(&lb->ips_v4, lb_vip->vip_str);
} else {
@@ -711,6 +715,13 @@ ovn_northd_lb_create(const struct nbrec_load_balancer *nbrec_lb)
ds_chomp(&sel_fields, ',');
lb->selection_fields = ds_steal_cstr(&sel_fields);
}
+}
+
+struct ovn_northd_lb *
+ovn_northd_lb_create(const struct nbrec_load_balancer *nbrec_lb)
+{
+ struct ovn_northd_lb *lb = xzalloc(sizeof *lb);
+ ovn_northd_lb_init(lb, nbrec_lb);
return lb;
}
@@ -736,8 +747,8 @@ ovn_northd_lb_get_vips(const struct ovn_northd_lb *lb)
return &lb->nlb->vips;
}
-void
-ovn_northd_lb_destroy(struct ovn_northd_lb *lb)
+static void
+ovn_northd_lb_cleanup(struct ovn_northd_lb *lb)
{
for (size_t i = 0; i < lb->n_vips; i++) {
ovn_lb_vip_destroy(&lb->vips[i]);
@@ -745,24 +756,36 @@ ovn_northd_lb_destroy(struct ovn_northd_lb *lb)
}
free(lb->vips);
free(lb->vips_nb);
+ lb->vips = NULL;
+ lb->vips_nb = NULL;
smap_destroy(&lb->template_vips);
sset_destroy(&lb->ips_v4);
sset_destroy(&lb->ips_v6);
free(lb->selection_fields);
+ lb->selection_fields = NULL;
+ lb->health_checks = false;
+}
+
+void
+ovn_northd_lb_destroy(struct ovn_northd_lb *lb)
+{
+ ovn_northd_lb_cleanup(lb);
free(lb);
}
-/* Constructs a new 'struct ovn_lb_group' object from the Nb LB Group record
- * and an array of 'struct ovn_northd_lb' objects for its associated
- * load balancers. */
-struct ovn_lb_group *
-ovn_lb_group_create(const struct nbrec_load_balancer_group *nbrec_lb_group,
- const struct hmap *lbs)
+void
+ovn_northd_lb_reinit(struct ovn_northd_lb *lb,
+ const struct nbrec_load_balancer *nbrec_lb)
{
- struct ovn_lb_group *lb_group;
+ ovn_northd_lb_cleanup(lb);
+ ovn_northd_lb_init(lb, nbrec_lb);
+}
- lb_group = xzalloc(sizeof *lb_group);
- lb_group->uuid = nbrec_lb_group->header_.uuid;
+static void
+ovn_lb_group_init(struct ovn_lb_group *lb_group,
+ const struct nbrec_load_balancer_group *nbrec_lb_group,
+ const struct hmap *lbs)
+{
lb_group->n_lbs = nbrec_lb_group->n_load_balancer;
lb_group->lbs = xmalloc(lb_group->n_lbs * sizeof *lb_group->lbs);
lb_group->lb_ips = ovn_lb_ip_set_create();
@@ -772,10 +795,28 @@ ovn_lb_group_create(const struct nbrec_load_balancer_group *nbrec_lb_group,
&nbrec_lb_group->load_balancer[i]->header_.uuid;
lb_group->lbs[i] = ovn_northd_lb_find(lbs, lb_uuid);
}
+}
+/* Constructs a new 'struct ovn_lb_group' object from the Nb LB Group record
+ * and an array of 'struct ovn_northd_lb' objects for its associated
+ * load balancers. */
+struct ovn_lb_group *
+ovn_lb_group_create(const struct nbrec_load_balancer_group *nbrec_lb_group,
+ const struct hmap *lbs)
+{
+ struct ovn_lb_group *lb_group = xzalloc(sizeof *lb_group);
+ lb_group->uuid = nbrec_lb_group->header_.uuid;
+ ovn_lb_group_init(lb_group, nbrec_lb_group, lbs);
return lb_group;
}
+static void
+ovn_lb_group_cleanup(struct ovn_lb_group *lb_group)
+{
+ ovn_lb_ip_set_destroy(lb_group->lb_ips);
+ free(lb_group->lbs);
+}
+
void
ovn_lb_group_destroy(struct ovn_lb_group *lb_group)
{
@@ -783,11 +824,19 @@ ovn_lb_group_destroy(struct ovn_lb_group *lb_group)
return;
}
- ovn_lb_ip_set_destroy(lb_group->lb_ips);
- free(lb_group->lbs);
+ ovn_lb_group_cleanup(lb_group);
free(lb_group);
}
+void
+ovn_lb_group_reinit(struct ovn_lb_group *lb_group,
+ const struct nbrec_load_balancer_group *nbrec_lb_group,
+ const struct hmap *lbs)
+{
+ ovn_lb_group_cleanup(lb_group);
+ ovn_lb_group_init(lb_group, nbrec_lb_group, lbs);
+}
+
struct ovn_lb_group *
ovn_lb_group_find(const struct hmap *lb_groups, const struct uuid *uuid)
{
@@ -77,6 +77,9 @@ struct ovn_northd_lb {
struct sset ips_v4;
struct sset ips_v6;
+
+ /* Indicates if the load balancer has health checks configured. */
+ bool health_checks;
};
struct ovn_lb_vip {
@@ -130,6 +133,8 @@ struct ovn_northd_lb *ovn_northd_lb_find(const struct hmap *,
const struct uuid *);
const struct smap *ovn_northd_lb_get_vips(const struct ovn_northd_lb *);
void ovn_northd_lb_destroy(struct ovn_northd_lb *);
+void ovn_northd_lb_reinit(struct ovn_northd_lb *,
+ const struct nbrec_load_balancer *);
void build_lrouter_lb_ips(struct ovn_lb_ip_set *,
const struct ovn_northd_lb *);
@@ -148,6 +153,10 @@ struct ovn_lb_group *ovn_lb_group_create(
void ovn_lb_group_destroy(struct ovn_lb_group *lb_group);
struct ovn_lb_group *ovn_lb_group_find(const struct hmap *lb_groups,
const struct uuid *);
+void ovn_lb_group_reinit(
+ struct ovn_lb_group *lb_group,
+ const struct nbrec_load_balancer_group *,
+ const struct hmap *lbs);
struct ovn_lb_datapaths {
struct hmap_node hmap_node;
@@ -38,7 +38,27 @@ static void lb_data_destroy(struct ed_type_lb_data *);
static void build_lbs(const struct nbrec_load_balancer_table *,
const struct nbrec_load_balancer_group_table *,
struct hmap *lbs, struct hmap *lb_groups);
+static struct ovn_lb_group *create_lb_group(
+ const struct nbrec_load_balancer_group *, struct hmap *lbs,
+ struct hmap *lb_groups);
+static void destroy_tracked_data(struct ed_type_lb_data *);
+static inline void add_crupdated_lb_to_tracked_data(struct ovn_northd_lb *,
+ struct tracked_lb_data *,
+ bool health_checks);
+static inline void add_deleted_lb_to_tracked_data(struct ovn_northd_lb *,
+ struct tracked_lb_data *,
+ bool health_checks);
+static inline struct crupdated_lb_group *
+ add_crupdated_lb_group_to_tracked_data(struct ovn_lb_group *,
+ struct tracked_lb_data *);
+static inline void add_deleted_lb_group_to_tracked_data(
+ struct ovn_lb_group *, struct tracked_lb_data *);
+/* 'lb_data' engine node manages the NB load balancers and load balancer
+ * groups. For each NB LB, it creates 'struct ovn_northd_lb' and
+ * for each NB LB group, it creates 'struct ovn_lb_group' and stores in
+ * the respective hmaps in it data (ed_type_lb_data).
+ */
void *
en_lb_data_init(struct engine_node *node OVS_UNUSED,
struct engine_arg *arg OVS_UNUSED)
@@ -60,6 +80,7 @@ en_lb_data_run(struct engine_node *node, void *data)
const struct nbrec_load_balancer_group_table *nb_lbg_table =
EN_OVSDB_GET(engine_get_input("NB_load_balancer_group", node));
+ lb_data->tracked = false;
build_lbs(nb_lb_table, nb_lbg_table, &lb_data->lbs, &lb_data->lb_groups);
engine_set_node_state(node, EN_UPDATED);
}
@@ -71,12 +92,156 @@ en_lb_data_cleanup(void *data)
lb_data_destroy(lb_data);
}
+void
+en_lb_data_clear_tracked_data(void *data)
+{
+ struct ed_type_lb_data *lb_data = (struct ed_type_lb_data *) data;
+ destroy_tracked_data(lb_data);
+}
+
+
+/* Handler functions. */
+bool
+lb_data_load_balancer_handler(struct engine_node *node, void *data)
+{
+ const struct nbrec_load_balancer_table *nb_lb_table =
+ EN_OVSDB_GET(engine_get_input("NB_load_balancer", node));
+
+ struct ed_type_lb_data *lb_data = (struct ed_type_lb_data *) data;
+
+ lb_data->tracked = true;
+ struct tracked_lb_data *trk_lb_data = &lb_data->tracked_lb_data;
+
+ const struct nbrec_load_balancer *tracked_lb;
+ NBREC_LOAD_BALANCER_TABLE_FOR_EACH_TRACKED (tracked_lb, nb_lb_table) {
+ struct ovn_northd_lb *lb;
+ if (nbrec_load_balancer_is_new(tracked_lb)) {
+ /* New load balancer. */
+ lb = ovn_northd_lb_create(tracked_lb);
+ hmap_insert(&lb_data->lbs, &lb->hmap_node,
+ uuid_hash(&tracked_lb->header_.uuid));
+ add_crupdated_lb_to_tracked_data(lb, trk_lb_data,
+ lb->health_checks);
+ } else if (nbrec_load_balancer_is_deleted(tracked_lb)) {
+ lb = ovn_northd_lb_find(&lb_data->lbs,
+ &tracked_lb->header_.uuid);
+ ovs_assert(lb);
+ hmap_remove(&lb_data->lbs, &lb->hmap_node);
+ add_deleted_lb_to_tracked_data(lb, trk_lb_data,
+ lb->health_checks);
+ } else {
+ /* Load balancer updated. */
+ lb = ovn_northd_lb_find(&lb_data->lbs,
+ &tracked_lb->header_.uuid);
+ ovs_assert(lb);
+ bool health_checks = lb->health_checks;
+ ovn_northd_lb_reinit(lb, tracked_lb);
+ health_checks |= lb->health_checks;
+ add_crupdated_lb_to_tracked_data(lb, trk_lb_data, health_checks);
+ }
+ }
+
+ engine_set_node_state(node, EN_UPDATED);
+ return true;
+}
+
+bool
+lb_data_load_balancer_group_handler(struct engine_node *node, void *data)
+{
+ struct ed_type_lb_data *lb_data = (struct ed_type_lb_data *) data;
+ const struct nbrec_load_balancer_group_table *nb_lbg_table =
+ EN_OVSDB_GET(engine_get_input("NB_load_balancer_group", node));
+
+ lb_data->tracked = true;
+ struct tracked_lb_data *trk_lb_data = &lb_data->tracked_lb_data;
+ const struct nbrec_load_balancer_group *tracked_lb_group;
+ NBREC_LOAD_BALANCER_GROUP_TABLE_FOR_EACH_TRACKED (tracked_lb_group,
+ nb_lbg_table) {
+ if (nbrec_load_balancer_group_is_new(tracked_lb_group)) {
+ struct ovn_lb_group *lb_group =
+ create_lb_group(tracked_lb_group, &lb_data->lbs,
+ &lb_data->lb_groups);
+ struct crupdated_lb_group *clbg =
+ add_crupdated_lb_group_to_tracked_data(lb_group, trk_lb_data);
+ for (size_t i = 0; i < lb_group->n_lbs; i++) {
+ hmapx_add(&clbg->assoc_lbs, lb_group->lbs[i]);
+ }
+ } else if (nbrec_load_balancer_group_is_deleted(tracked_lb_group)) {
+ struct ovn_lb_group *lb_group;
+ lb_group = ovn_lb_group_find(&lb_data->lb_groups,
+ &tracked_lb_group->header_.uuid);
+ ovs_assert(lb_group);
+ hmap_remove(&lb_data->lb_groups, &lb_group->hmap_node);
+ add_deleted_lb_group_to_tracked_data(lb_group, trk_lb_data);
+ } else if (nbrec_load_balancer_group_is_updated(tracked_lb_group,
+ NBREC_LOAD_BALANCER_GROUP_COL_LOAD_BALANCER)) {
+
+ struct ovn_lb_group *lb_group;
+ lb_group = ovn_lb_group_find(&lb_data->lb_groups,
+ &tracked_lb_group->header_.uuid);
+ ovs_assert(lb_group);
+
+ /* Determine the lbs which are added or deleted for this
+ * lb group and add them to tracked data.
+ * Eg. If an lb group lbg1 before the update had [lb1, lb2, lb3]
+ * And in the update, lb2 was removed and lb4 got added, then
+ * add lb2 and lb4 to the trk_lb_data->crupdated_lbs. */
+ struct hmapx pre_update_lbs = HMAPX_INITIALIZER(&pre_update_lbs);
+ for (size_t i = 0; i < lb_group->n_lbs; i++) {
+ hmapx_add(&pre_update_lbs, lb_group->lbs[i]);
+ }
+ ovn_lb_group_reinit(lb_group, tracked_lb_group, &lb_data->lbs);
+ for (size_t i = 0; i < lb_group->n_lbs; i++) {
+ build_lrouter_lb_ips(lb_group->lb_ips, lb_group->lbs[i]);
+ }
+
+ struct crupdated_lb_group *clbg =
+ add_crupdated_lb_group_to_tracked_data(lb_group, trk_lb_data);
+
+ for (size_t i = 0; i < lb_group->n_lbs; i++) {
+ struct ovn_northd_lb *lb = lb_group->lbs[i];
+ struct hmapx_node *hmapx_node = hmapx_find(&pre_update_lbs,
+ lb);
+ if (!hmapx_node) {
+ hmapx_add(&clbg->assoc_lbs, lb);
+ } else {
+ hmapx_delete(&pre_update_lbs, hmapx_node);
+ }
+ }
+
+ struct hmapx_node *hmapx_node;
+ HMAPX_FOR_EACH_SAFE (hmapx_node, &pre_update_lbs) {
+ struct ovn_northd_lb *lb = hmapx_node->data;
+ /* Check if the pre updated lb is actually deleted or
+ * just disassociated from the lb group. If it's just
+ * disassociated, then set 'has_dissassoc_lbs_from_lb_grops' to
+ * true. Later if required we can add this 'lb' to an hmapx of
+ * disassociated_lbs. */
+ if (!hmapx_find(&trk_lb_data->deleted_lbs, lb)) {
+ trk_lb_data->has_dissassoc_lbs_from_lb_grops = true;
+ }
+ hmapx_delete(&pre_update_lbs, hmapx_node);
+ }
+ hmapx_destroy(&pre_update_lbs);
+ }
+ }
+
+ engine_set_node_state(node, EN_UPDATED);
+ return true;
+}
+
/* static functions. */
static void
lb_data_init(struct ed_type_lb_data *lb_data)
{
hmap_init(&lb_data->lbs);
hmap_init(&lb_data->lb_groups);
+
+ struct tracked_lb_data *trk_lb_data = &lb_data->tracked_lb_data;
+ hmapx_init(&trk_lb_data->crupdated_lbs);
+ hmapx_init(&trk_lb_data->deleted_lbs);
+ hmapx_init(&trk_lb_data->crupdated_lb_groups);
+ hmapx_init(&trk_lb_data->deleted_lb_groups);
}
static void
@@ -93,6 +258,11 @@ lb_data_destroy(struct ed_type_lb_data *lb_data)
ovn_lb_group_destroy(lb_group);
}
hmap_destroy(&lb_data->lb_groups);
+
+ destroy_tracked_data(lb_data);
+ hmapx_destroy(&lb_data->tracked_lb_data.crupdated_lbs);
+ hmapx_destroy(&lb_data->tracked_lb_data.deleted_lbs);
+ hmapx_destroy(&lb_data->tracked_lb_data.deleted_lb_groups);
}
static void
@@ -100,12 +270,9 @@ build_lbs(const struct nbrec_load_balancer_table *nbrec_load_balancer_table,
const struct nbrec_load_balancer_group_table *nbrec_lb_group_table,
struct hmap *lbs, struct hmap *lb_groups)
{
- struct ovn_lb_group *lb_group;
- struct ovn_northd_lb *lb_nb;
-
const struct nbrec_load_balancer *nbrec_lb;
NBREC_LOAD_BALANCER_TABLE_FOR_EACH (nbrec_lb, nbrec_load_balancer_table) {
- lb_nb = ovn_northd_lb_create(nbrec_lb);
+ struct ovn_northd_lb *lb_nb = ovn_northd_lb_create(nbrec_lb);
hmap_insert(lbs, &lb_nb->hmap_node,
uuid_hash(&nbrec_lb->header_.uuid));
}
@@ -113,13 +280,91 @@ build_lbs(const struct nbrec_load_balancer_table *nbrec_load_balancer_table,
const struct nbrec_load_balancer_group *nbrec_lb_group;
NBREC_LOAD_BALANCER_GROUP_TABLE_FOR_EACH (nbrec_lb_group,
nbrec_lb_group_table) {
- lb_group = ovn_lb_group_create(nbrec_lb_group, lbs);
+ create_lb_group(nbrec_lb_group, lbs, lb_groups);
+ }
+}
- for (size_t i = 0; i < lb_group->n_lbs; i++) {
- build_lrouter_lb_ips(lb_group->lb_ips, lb_group->lbs[i]);
- }
+static struct ovn_lb_group *
+create_lb_group(const struct nbrec_load_balancer_group *nbrec_lb_group,
+ struct hmap *lbs, struct hmap *lb_groups)
+{
+ struct ovn_lb_group *lb_group = ovn_lb_group_create(nbrec_lb_group, lbs);
+
+ for (size_t i = 0; i < lb_group->n_lbs; i++) {
+ build_lrouter_lb_ips(lb_group->lb_ips, lb_group->lbs[i]);
+ }
+
+ hmap_insert(lb_groups, &lb_group->hmap_node,
+ uuid_hash(&lb_group->uuid));
+
+ return lb_group;
+}
+
+static void
+destroy_tracked_data(struct ed_type_lb_data *lb_data)
+{
+ lb_data->tracked = false;
+ lb_data->tracked_lb_data.has_health_checks = false;
+ lb_data->tracked_lb_data.has_dissassoc_lbs_from_lb_grops = false;
+
+ struct hmapx_node *node;
+ HMAPX_FOR_EACH_SAFE (node, &lb_data->tracked_lb_data.deleted_lbs) {
+ ovn_northd_lb_destroy(node->data);
+ hmapx_delete(&lb_data->tracked_lb_data.deleted_lbs, node);
+ }
- hmap_insert(lb_groups, &lb_group->hmap_node,
- uuid_hash(&lb_group->uuid));
+ HMAPX_FOR_EACH_SAFE (node, &lb_data->tracked_lb_data.deleted_lb_groups) {
+ ovn_lb_group_destroy(node->data);
+ hmapx_delete(&lb_data->tracked_lb_data.deleted_lb_groups, node);
}
+
+ hmapx_clear(&lb_data->tracked_lb_data.crupdated_lbs);
+
+ struct crupdated_lb_group *crupdated_lbg;
+ HMAPX_FOR_EACH_SAFE (node, &lb_data->tracked_lb_data.crupdated_lb_groups) {
+ crupdated_lbg = node->data;
+ hmapx_destroy(&crupdated_lbg->assoc_lbs);
+ hmapx_delete(&lb_data->tracked_lb_data.crupdated_lb_groups, node);
+ free(crupdated_lbg);
+ }
+}
+
+static inline void
+add_crupdated_lb_to_tracked_data(struct ovn_northd_lb *lb,
+ struct tracked_lb_data *tracked_lb_data,
+ bool health_checks)
+{
+ hmapx_add(&tracked_lb_data->crupdated_lbs, lb);
+ if (health_checks) {
+ tracked_lb_data->has_health_checks = true;
+ }
+}
+
+static inline void
+add_deleted_lb_to_tracked_data(struct ovn_northd_lb *lb,
+ struct tracked_lb_data *tracked_lb_data,
+ bool health_checks)
+{
+ hmapx_add(&tracked_lb_data->deleted_lbs, lb);
+ if (health_checks) {
+ tracked_lb_data->has_health_checks = true;
+ }
+}
+
+static inline struct crupdated_lb_group *
+add_crupdated_lb_group_to_tracked_data(struct ovn_lb_group *lbg,
+ struct tracked_lb_data *tracked_lb_data)
+{
+ struct crupdated_lb_group *clbg = xzalloc(sizeof *clbg);
+ clbg->lbg = lbg;
+ hmapx_init(&clbg->assoc_lbs);
+ hmapx_add(&tracked_lb_data->crupdated_lb_groups, clbg);
+ return clbg;
+}
+
+static inline void
+add_deleted_lb_group_to_tracked_data(struct ovn_lb_group *lbg,
+ struct tracked_lb_data *tracked_lb_data)
+{
+ hmapx_add(&tracked_lb_data->deleted_lb_groups, lbg);
}
@@ -4,9 +4,42 @@
#include <config.h>
#include "openvswitch/hmap.h"
+#include "include/openvswitch/list.h"
+#include "lib/hmapx.h"
#include "lib/inc-proc-eng.h"
+struct ovn_northd_lb;
+struct ovn_lb_group;
+
+struct crupdated_lb_group {
+ struct ovn_lb_group *lbg;
+
+ /* hmapx of newly associated lbs to this lb group.
+ * hmapx node is 'struct ovn_northd_lb *' */
+ struct hmapx assoc_lbs;
+};
+
+struct tracked_lb_data {
+ /* Both created and updated lbs. hmapx node is 'struct ovn_northd_lb *'. */
+ struct hmapx crupdated_lbs;
+ struct hmapx deleted_lbs;
+
+ /* Both created and updated lb_groups. hmapx node is
+ * 'struct crupdated_lb_group'. */
+ struct hmapx crupdated_lb_groups;
+
+ /* Deleted lb_groups. hmapx node is 'struct ovn_lb_group *'. */
+ struct hmapx deleted_lb_groups;
+
+ /* Indicates if any of the tracked lb has health checks enabled. */
+ bool has_health_checks;
+
+ /* Indicates if any lb got disassociated from a lb group
+ * but not deleted. */
+ bool has_dissassoc_lbs_from_lb_grops;
+};
+
/* struct which maintains the data of the engine node lb_data. */
struct ed_type_lb_data {
/* hmap of load balancers. hmap node is 'struct ovn_northd_lb *' */
@@ -14,10 +47,18 @@ struct ed_type_lb_data {
/* hmap of load balancer groups. hmap node is 'struct ovn_lb_group *' */
struct hmap lb_groups;
+
+ /* tracked data*/
+ bool tracked;
+ struct tracked_lb_data tracked_lb_data;
};
void *en_lb_data_init(struct engine_node *, struct engine_arg *);
void en_lb_data_run(struct engine_node *, void *data);
void en_lb_data_cleanup(void *data);
+void en_lb_data_clear_tracked_data(void *data);
+
+bool lb_data_load_balancer_handler(struct engine_node *, void *data);
+bool lb_data_load_balancer_group_handler(struct engine_node *, void *data);
#endif /* end of EN_NORTHD_LB_DATA_H */
@@ -206,6 +206,47 @@ northd_sb_port_binding_handler(struct engine_node *node,
return true;
}
+bool
+northd_lb_data_handler(struct engine_node *node, void *data)
+{
+ struct ed_type_lb_data *lb_data = engine_get_input_data("lb_data", node);
+
+ if (!lb_data->tracked) {
+ return false;
+ }
+
+ if (lb_data->tracked_lb_data.has_health_checks) {
+ /* Fall back to recompute since a tracked load balancer
+ * has health checks configured as I-P is not yet supported
+ * for such load balancers. */
+ return false;
+ }
+
+ /* Fall back to recompute if any load balancer was dissociated from
+ * a load balancer group (but not deleted). */
+ if (lb_data->tracked_lb_data.has_dissassoc_lbs_from_lb_grops) {
+ return false;
+ }
+
+ /* Fall back to recompute if load balancer groups are deleted. */
+ if (!hmapx_is_empty(&lb_data->tracked_lb_data.deleted_lb_groups)) {
+ return false;
+ }
+
+ struct northd_data *nd = data;
+
+ if (!northd_handle_lb_data_changes(&lb_data->tracked_lb_data,
+ &nd->ls_datapaths,
+ &nd->lr_datapaths,
+ &nd->lb_datapaths_map,
+ &nd->lb_group_datapaths_map)) {
+ return false;
+ }
+
+ engine_set_node_state(node, EN_UPDATED);
+ return true;
+}
+
void
*en_northd_init(struct engine_node *node OVS_UNUSED,
struct engine_arg *arg OVS_UNUSED)
@@ -17,5 +17,6 @@ void en_northd_clear_tracked_data(void *data);
bool northd_nb_nb_global_handler(struct engine_node *, void *data OVS_UNUSED);
bool northd_nb_logical_switch_handler(struct engine_node *, void *data);
bool northd_sb_port_binding_handler(struct engine_node *, void *data);
+bool northd_lb_data_handler(struct engine_node *, void *data);
#endif /* EN_NORTHD_H */
@@ -141,13 +141,18 @@ static ENGINE_NODE(sync_to_sb_addr_set, "sync_to_sb_addr_set");
static ENGINE_NODE(fdb_aging, "fdb_aging");
static ENGINE_NODE(fdb_aging_waker, "fdb_aging_waker");
static ENGINE_NODE(sync_to_sb_lb, "sync_to_sb_lb");
-static ENGINE_NODE(lb_data, "lb_data");
+static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lb_data, "lb_data");
void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
struct ovsdb_idl_loop *sb)
{
/* Define relationships between nodes where first argument is dependent
* on the second argument */
+ engine_add_input(&en_lb_data, &en_nb_load_balancer,
+ lb_data_load_balancer_handler);
+ engine_add_input(&en_lb_data, &en_nb_load_balancer_group,
+ lb_data_load_balancer_group_handler);
+
engine_add_input(&en_northd, &en_nb_port_group, NULL);
engine_add_input(&en_northd, &en_nb_acl, NULL);
engine_add_input(&en_northd, &en_nb_logical_router, NULL);
@@ -175,13 +180,10 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
northd_sb_port_binding_handler);
engine_add_input(&en_northd, &en_nb_nb_global,
northd_nb_nb_global_handler);
+ engine_add_input(&en_northd, &en_lb_data, northd_lb_data_handler);
engine_add_input(&en_northd, &en_nb_logical_switch,
northd_nb_logical_switch_handler);
- engine_add_input(&en_lb_data, &en_nb_load_balancer, NULL);
- engine_add_input(&en_lb_data, &en_nb_load_balancer_group, NULL);
- engine_add_input(&en_northd, &en_lb_data, NULL);
-
engine_add_input(&en_mac_binding_aging, &en_nb_nb_global, NULL);
engine_add_input(&en_mac_binding_aging, &en_sb_mac_binding, NULL);
engine_add_input(&en_mac_binding_aging, &en_northd, NULL);
@@ -40,6 +40,7 @@
#include "lib/lb.h"
#include "memory.h"
#include "northd.h"
+#include "en-lb-data.h"
#include "lib/ovn-parallel-hmap.h"
#include "ovn/actions.h"
#include "ovn/features.h"
@@ -5323,6 +5324,63 @@ northd_handle_sb_port_binding_changes(
return true;
}
+/* Handler for lb_data engine changes. For every tracked lb_data
+ * it creates or deletes the ovn_lb_datapaths/ovn_lb_group_datapaths
+ * from the lb_datapaths hmap and lb_group_datapaths hmap. */
+bool
+northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data,
+ struct ovn_datapaths *ls_datapaths,
+ struct ovn_datapaths *lr_datapaths,
+ struct hmap *lb_datapaths_map,
+ struct hmap *lb_group_datapaths_map)
+{
+ struct ovn_lb_datapaths *lb_dps;
+ struct ovn_northd_lb *lb;
+ struct hmapx_node *hmapx_node;
+ HMAPX_FOR_EACH (hmapx_node, &trk_lb_data->deleted_lbs) {
+ lb = hmapx_node->data;
+ const struct uuid *lb_uuid = &lb->nlb->header_.uuid;
+
+ lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid);
+ ovs_assert(lb_dps);
+ hmap_remove(lb_datapaths_map, &lb_dps->hmap_node);
+ ovn_lb_datapaths_destroy(lb_dps);
+ }
+
+ HMAPX_FOR_EACH (hmapx_node, &trk_lb_data->crupdated_lbs) {
+ lb = hmapx_node->data;
+ const struct uuid *lb_uuid = &lb->nlb->header_.uuid;
+
+ lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid);
+ if (!lb_dps) {
+ lb_dps = ovn_lb_datapaths_create(lb, ods_size(ls_datapaths),
+ ods_size(lr_datapaths));
+ hmap_insert(lb_datapaths_map, &lb_dps->hmap_node,
+ uuid_hash(lb_uuid));
+ }
+ }
+
+ struct ovn_lb_group_datapaths *lb_group_dps;
+ struct ovn_lb_group *lbg;
+ struct crupdated_lb_group *crupdated_lbg;
+ HMAPX_FOR_EACH (hmapx_node, &trk_lb_data->crupdated_lb_groups) {
+ crupdated_lbg = hmapx_node->data;
+ lbg = crupdated_lbg->lbg;
+ const struct uuid *lb_uuid = &lbg->uuid;
+
+ lb_group_dps = ovn_lb_group_datapaths_find(lb_group_datapaths_map,
+ lb_uuid);
+ if (!lb_group_dps) {
+ lb_group_dps = ovn_lb_group_datapaths_create(
+ lbg, ods_size(ls_datapaths), ods_size(lr_datapaths));
+ hmap_insert(lb_group_datapaths_map, &lb_group_dps->hmap_node,
+ uuid_hash(lb_uuid));
+ }
+ }
+
+ return true;
+}
+
struct multicast_group {
const char *name;
uint16_t key; /* OVN_MIN_MULTICAST...OVN_MAX_MULTICAST. */
@@ -347,6 +347,13 @@ bool lflow_handle_northd_ls_changes(struct ovsdb_idl_txn *ovnsb_txn,
bool northd_handle_sb_port_binding_changes(
const struct sbrec_port_binding_table *, struct hmap *ls_ports);
+struct tracked_lb_data;
+bool northd_handle_lb_data_changes(struct tracked_lb_data *,
+ struct ovn_datapaths *ls_datapaths,
+ struct ovn_datapaths *lr_datapaths,
+ struct hmap *lb_datapaths_map,
+ struct hmap *lb_group_datapaths_map);
+
void build_bfd_table(struct ovsdb_idl_txn *ovnsb_txn,
const struct nbrec_bfd_table *,
const struct sbrec_bfd_table *,
@@ -9711,3 +9711,210 @@ AT_CHECK([grep "lr_in_gw_redirect" R1flows |sed s'/table=../table=??/' |sort], [
AT_CLEANUP
])
+
+OVN_FOR_EACH_NORTHD_NO_HV([
+AT_SETUP([Load balancer incremental processing])
+ovn_start
+
+check_engine_stats() {
+ northd_comp=$1
+ lflow_comp=$2
+
+ AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats lb_data recompute], [0], [0
+])
+
+ northd_recompute_ct=$(as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats northd recompute)
+ if [[ "$northd_comp" == "norecompute" ]]; then
+ check test "$northd_recompute_ct" -eq "0"
+ else
+ check test "$northd_recompute_ct" -ne "0"
+ fi
+
+ lflow_recompute_ct=$(as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats lflow recompute)
+ if [[ "$lflow_comp" == "norecompute" ]]; then
+ check test "$lflow_recompute_ct" -eq "0"
+ else
+ check test "$lflow_recompute_ct" -ne "0"
+ fi
+}
+
+# Test I-P for load balancers.
+# Presently ovn-northd handles I-P for NB LBs in northd_lb_data engine node
+# only.
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80
+check_engine_stats norecompute recompute
+
+CHECK_NO_CHANGE_AFTER_RECOMPUTE
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+
+check ovn-nbctl --wait=sb set load_balancer . ip_port_mappings:10.0.0.3=sw0-p1:10.0.0.2
+check_engine_stats norecompute recompute
+
+check ovn-nbctl --wait=sb set load_balancer . options:foo=bar
+check_engine_stats norecompute recompute
+
+check ovn-nbctl --wait=sb -- lb-add lb2 20.0.0.10:80 20.0.0.20:80 -- lb-add lb3 30.0.0.10:80 30.0.0.20:80
+check_engine_stats norecompute recompute
+
+CHECK_NO_CHANGE_AFTER_RECOMPUTE
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+
+check ovn-nbctl --wait=sb -- lb-del lb2 -- lb-del lb3
+check_engine_stats norecompute recompute
+
+CHECK_NO_CHANGE_AFTER_RECOMPUTE
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+
+AT_CHECK([ovn-nbctl --wait=sb \
+ -- --id=@hc create Load_Balancer_Health_Check vip="10.0.0.10\:80" \
+ options:failure_count=100 \
+ -- add Load_Balancer . health_check @hc | uuidfilt], [0], [<0>
+])
+check_engine_stats recompute recompute
+
+# Any change to load balancer health check should also result in full recompute
+# of northd node (but not northd_lb_data node)
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl --wait=sb set load_balancer_health_check . options:foo=bar1
+check_engine_stats recompute recompute
+
+# Delete the health check from the load balancer. northd engine node should do a full recompute.
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl --wait=sb clear Load_Balancer . health_check
+check_engine_stats recompute recompute
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl ls-add sw0
+check ovn-nbctl --wait=sb lr-add lr0
+check_engine_stats recompute recompute
+
+# Associate lb1 to sw0. There should be a full recompute of northd engine node
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl --wait=sb ls-lb-add sw0 lb1
+check_engine_stats recompute recompute
+
+# Disassociate lb1 from sw0. There should be a full recompute of northd engine node.
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl --wait=sb ls-lb-del sw0 lb1
+check_engine_stats recompute recompute
+
+# Test load balancer group now
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+lbg1_uuid=$(ovn-nbctl create load_balancer_group name=lbg1)
+check_engine_stats norecompute recompute
+
+CHECK_NO_CHANGE_AFTER_RECOMPUTE
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+
+lb1_uuid=$(fetch_column nb:Load_Balancer _uuid)
+
+# Add lb to the lbg1 group
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl add load_balancer_group . load_Balancer $lb1_uuid
+check_engine_stats norecompute recompute
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl clear load_balancer_group . load_Balancer
+check_engine_stats recompute recompute
+
+# Add back lb to the lbg1 group
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl add load_balancer_group . load_Balancer $lb1_uuid
+check_engine_stats norecompute recompute
+
+CHECK_NO_CHANGE_AFTER_RECOMPUTE
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl add logical_switch sw0 load_balancer_group $lbg1_uuid
+check_engine_stats recompute recompute
+
+# Update lb and this should result in recompute
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl --wait=sb set load_balancer . options:bar=foo
+check_engine_stats recompute recompute
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl clear logical_switch sw0 load_balancer_group
+check_engine_stats recompute recompute
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl add logical_router lr0 load_balancer_group $lbg1_uuid
+check_engine_stats recompute recompute
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl clear logical_router lr0 load_balancer_group
+check_engine_stats recompute recompute
+
+# Add back lb group to logical switch and then delete it.
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl add logical_switch sw0 load_balancer_group $lbg1_uuid
+check_engine_stats recompute recompute
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl clear logical_switch sw0 load_balancer_group -- \
+ destroy load_balancer_group $lbg1_uuid
+check_engine_stats recompute recompute
+
+CHECK_NO_CHANGE_AFTER_RECOMPUTE
+
+# Test the scenario where a load balancer is associated to
+# a logical switch sw0 and also to a lb group lbg1 and lbg1
+# is also associated to the logical switch sw0 and logical
+# router lr1
+
+check ovn-nbctl lr-add lr1
+check ovn-nbctl lb-add lb2 20.0.0.20:80 30.0.0.30:8080
+check ovn-nbctl lb-add lb3 30.0.0.20:80 30.0.0.30:8080
+check ovn-nbctl --wait=sb lb-add lb4 40.0.0.20:80 30.0.0.30:8080
+
+lb2_uuid=$(fetch_column nb:Load_Balancer _uuid name=lb2)
+lb3_uuid=$(fetch_column nb:Load_Balancer _uuid name=lb3)
+lb4_uuid=$(fetch_column nb:Load_Balancer _uuid name=lb4)
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+lbg1_uuid=$(ovn-nbctl create load_balancer_group name=lbg1)
+check_engine_stats norecompute recompute
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl set load_balancer_group . load_balancer="$lb2_uuid,$lb3_uuid,$lb4_uuid"
+check_engine_stats norecompute recompute
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl set logical_switch sw0 load_balancer_group=$lbg1_uuid
+check_engine_stats recompute recompute
+CHECK_NO_CHANGE_AFTER_RECOMPUTE
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl set logical_router lr1 load_balancer_group=$lbg1_uuid
+check_engine_stats recompute recompute
+CHECK_NO_CHANGE_AFTER_RECOMPUTE
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl --wait=sb ls-lb-add sw0 lb2
+check_engine_stats recompute recompute
+CHECK_NO_CHANGE_AFTER_RECOMPUTE
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl --wait=sb ls-lb-add sw0 lb3
+check_engine_stats recompute recompute
+CHECK_NO_CHANGE_AFTER_RECOMPUTE
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl --wait=sb lr-lb-add lr1 lb1
+check ovn-nbctl --wait=sb lr-lb-add lr1 lb2
+check_engine_stats recompute recompute
+CHECK_NO_CHANGE_AFTER_RECOMPUTE
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl --wait=sb ls-lb-del sw0 lb2
+check_engine_stats recompute recompute
+CHECK_NO_CHANGE_AFTER_RECOMPUTE
+
+check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
+check ovn-nbctl --wait=sb remove load_balancer_group . load_balancer $lb3_uuid
+check_engine_stats recompute recompute
+CHECK_NO_CHANGE_AFTER_RECOMPUTE
+
+AT_CLEANUP
+])