In order to reuse parsed data keep hash map of 'struct ovn_controller_lb', that is local for the controller, in separate engine node called 'lb_data'. Those data will be later on used to determine if we need to flush CT for changed/removed LB backends.
Reported-at: https://bugzilla.redhat.com/1839103 Signed-off-by: Ales Musil <[email protected]> --- v2: Rebase on top of current main. Address comments from Dumitru: - Fix the memory leak. - Fix the find function. Address comments from Mark: - Make the function lb_is_local more ergonomic. --- controller/lflow.c | 244 ++++++------------- controller/lflow.h | 14 +- controller/local_data.c | 26 ++ controller/local_data.h | 3 + controller/ovn-controller.c | 460 +++++++++++++++++++++++++++++++----- lib/lb.c | 34 +++ lib/lb.h | 8 + 7 files changed, 547 insertions(+), 242 deletions(-) diff --git a/controller/lflow.c b/controller/lflow.c index 08ce0386f..a0a26460c 100644 --- a/controller/lflow.c +++ b/controller/lflow.c @@ -98,10 +98,7 @@ consider_logical_flow(const struct sbrec_logical_flow *lflow, struct lflow_ctx_out *l_ctx_out); static void -consider_lb_hairpin_flows(struct objdep_mgr *mgr, - const struct sbrec_load_balancer *sbrec_lb, - const struct hmap *local_datapaths, - const struct smap *template_vars, +consider_lb_hairpin_flows(const struct ovn_controller_lb *lb, bool use_ct_mark, struct ovn_desired_flow_table *flow_table, struct simap *ids); @@ -801,43 +798,6 @@ lflow_handle_changed_ref(enum objdep_type type, const char *res_name, return true; } -bool -lb_handle_changed_ref(enum objdep_type type, const char *res_name, - struct ovs_list *objs_todo, - const void *in_arg, void *out_arg) -{ - struct lflow_ctx_in *l_ctx_in = CONST_CAST(struct lflow_ctx_in *, in_arg); - struct lflow_ctx_out *l_ctx_out = out_arg; - - struct object_to_resources_list_node *resource_lb_uuid; - LIST_FOR_EACH_POP (resource_lb_uuid, list_node, objs_todo) { - VLOG_DBG("Reprocess LB "UUID_FMT" for resource type: %s, name: %s", - UUID_ARGS(&resource_lb_uuid->obj_uuid), - objdep_type_name(type), res_name); - - const struct sbrec_load_balancer *lb = - sbrec_load_balancer_table_get_for_uuid( - l_ctx_in->lb_table, &resource_lb_uuid->obj_uuid); - if (!lb) { - VLOG_DBG("Failed to find LB "UUID_FMT" referred by: %s", - UUID_ARGS(&resource_lb_uuid->obj_uuid), res_name); - } else { - ofctrl_remove_flows(l_ctx_out->flow_table, - &resource_lb_uuid->obj_uuid); - - consider_lb_hairpin_flows(l_ctx_out->lb_deps_mgr, lb, - l_ctx_in->local_datapaths, - l_ctx_in->template_vars, - l_ctx_in->lb_hairpin_use_ct_mark, - l_ctx_out->flow_table, - l_ctx_out->hairpin_lb_ids); - } - - free(resource_lb_uuid); - } - return true; -} - static void lflow_parse_ctrl_meter(const struct sbrec_logical_flow *lflow, struct ovn_extend_table *meter_table, @@ -1647,10 +1607,9 @@ add_lb_vip_hairpin_reply_action(struct in6_addr *vip6, ovs_be32 vip, * original destination tuple stored by ovn-northd. */ static void -add_lb_vip_hairpin_flows(struct ovn_controller_lb *lb, +add_lb_vip_hairpin_flows(const struct ovn_controller_lb *lb, struct ovn_lb_vip *lb_vip, struct ovn_lb_backend *lb_backend, - uint8_t lb_proto, bool use_ct_mark, struct ovn_desired_flow_table *flow_table) { @@ -1689,7 +1648,7 @@ add_lb_vip_hairpin_flows(struct ovn_controller_lb *lb, ntohl(vip4)); } - add_lb_vip_hairpin_reply_action(NULL, snat_vip4, lb_proto, + add_lb_vip_hairpin_reply_action(NULL, snat_vip4, lb->proto, lb_backend->port, lb->slb->header_.uuid.parts[0], &ofpacts); @@ -1714,17 +1673,17 @@ add_lb_vip_hairpin_flows(struct ovn_controller_lb *lb, ntoh128(vip6_value)); } - add_lb_vip_hairpin_reply_action(snat_vip6, 0, lb_proto, + add_lb_vip_hairpin_reply_action(snat_vip6, 0, lb->proto, lb_backend->port, lb->slb->header_.uuid.parts[0], &ofpacts); } if (lb_backend->port) { - match_set_nw_proto(&hairpin_match, lb_proto); + match_set_nw_proto(&hairpin_match, lb->proto); match_set_tp_dst(&hairpin_match, htons(lb_backend->port)); if (!lb->hairpin_orig_tuple) { - match_set_ct_nw_proto(&hairpin_match, lb_proto); + match_set_ct_nw_proto(&hairpin_match, lb->proto); match_set_ct_tp_dst(&hairpin_match, htons(lb_vip->vip_port)); } else { match_set_reg_masked(&hairpin_match, @@ -1784,7 +1743,7 @@ add_lb_ct_snat_hairpin_for_dp(const struct ovn_controller_lb *lb, } static void -add_lb_ct_snat_hairpin_dp_flows(struct ovn_controller_lb *lb, +add_lb_ct_snat_hairpin_dp_flows(const struct ovn_controller_lb *lb, uint32_t id, struct ovn_desired_flow_table *flow_table) { @@ -1877,10 +1836,9 @@ add_lb_ct_snat_hairpin_dp_flows(struct ovn_controller_lb *lb, * that this LB belongs to. These flows (and the actual SNAT flow) get added * by add_lb_ct_snat_hairpin_dp_flows(). */ static void -add_lb_ct_snat_hairpin_vip_flow(struct ovn_controller_lb *lb, +add_lb_ct_snat_hairpin_vip_flow(const struct ovn_controller_lb *lb, uint32_t id, struct ovn_lb_vip *lb_vip, - uint8_t lb_proto, struct ovn_desired_flow_table *flow_table) { uint64_t stub[1024 / 8]; @@ -1973,10 +1931,10 @@ add_lb_ct_snat_hairpin_vip_flow(struct ovn_controller_lb *lb, } } - match_set_nw_proto(&match, lb_proto); + match_set_nw_proto(&match, lb->proto); if (lb_vip->vip_port) { if (!lb->hairpin_orig_tuple) { - match_set_ct_nw_proto(&match, lb_proto); + match_set_ct_nw_proto(&match, lb->proto); match_set_ct_tp_dst(&match, htons(lb_vip->vip_port)); } else { match_set_reg_masked(&match, MFF_LOG_LB_ORIG_TP_DPORT - MFF_REG0, @@ -2007,9 +1965,8 @@ add_lb_ct_snat_hairpin_vip_flow(struct ovn_controller_lb *lb, * Note: 'conjunctive_id' must be a unique identifier for each LB as it is used * as a conjunctive flow id. */ static void -add_lb_ct_snat_hairpin_flows(struct ovn_controller_lb *lb, +add_lb_ct_snat_hairpin_flows(const struct ovn_controller_lb *lb, uint32_t conjunctive_id, - uint8_t lb_proto, struct ovn_desired_flow_table *flow_table) { /* We must add a flow for each LB VIP. In the general case, this flow @@ -2046,102 +2003,47 @@ add_lb_ct_snat_hairpin_flows(struct ovn_controller_lb *lb, for (int i = 0; i < lb->n_vips; i++) { struct ovn_lb_vip *lb_vip = &lb->vips[i]; add_lb_ct_snat_hairpin_vip_flow(lb, conjunctive_id, - lb_vip, lb_proto, flow_table); + lb_vip, flow_table); } add_lb_ct_snat_hairpin_dp_flows(lb, conjunctive_id, flow_table); } static void -consider_lb_hairpin_flows(struct objdep_mgr *mgr, - const struct sbrec_load_balancer *sbrec_lb, - const struct hmap *local_datapaths, - const struct smap *template_vars, +consider_lb_hairpin_flows(const struct ovn_controller_lb *lb, bool use_ct_mark, struct ovn_desired_flow_table *flow_table, struct simap *ids) { - int id = simap_get(ids, sbrec_lb->name); - VLOG_DBG("Load Balancer %s has conjunctive flow id %u", - sbrec_lb->name, id); - - /* Check if we need to add flows or not. If there is one datapath - * in the local_datapaths, it means all the datapaths of the lb - * will be in the local_datapaths. */ - size_t i; - for (i = 0; i < sbrec_lb->n_datapaths; i++) { - if (get_local_datapath(local_datapaths, - sbrec_lb->datapaths[i]->tunnel_key)) { - break; - } - } - - if (sbrec_lb->n_datapaths && i == sbrec_lb->n_datapaths) { - return; - } - - struct sbrec_logical_dp_group *dp_group = sbrec_lb->datapath_group; - - for (i = 0; dp_group && i < dp_group->n_datapaths; i++) { - if (get_local_datapath(local_datapaths, - dp_group->datapaths[i]->tunnel_key)) { - break; - } - } - - if (dp_group && i == dp_group->n_datapaths) { - return; - } - - struct sset template_vars_ref = SSET_INITIALIZER(&template_vars_ref); - struct ovn_controller_lb *lb = - ovn_controller_lb_create(sbrec_lb, template_vars, &template_vars_ref); - uint8_t lb_proto = IPPROTO_TCP; - if (lb->slb->protocol && lb->slb->protocol[0]) { - if (!strcmp(lb->slb->protocol, "udp")) { - lb_proto = IPPROTO_UDP; - } else if (!strcmp(lb->slb->protocol, "sctp")) { - lb_proto = IPPROTO_SCTP; - } - } + int id = simap_get(ids, lb->slb->name); + VLOG_DBG("Load Balancer %s has conjunctive flow id %u", lb->slb->name, id); - const char *tv_name; - SSET_FOR_EACH (tv_name, &template_vars_ref) { - objdep_mgr_add(mgr, OBJDEP_TYPE_TEMPLATE, tv_name, - &sbrec_lb->header_.uuid); - } - for (i = 0; i < lb->n_vips; i++) { + for (size_t i = 0; i < lb->n_vips; i++) { struct ovn_lb_vip *lb_vip = &lb->vips[i]; for (size_t j = 0; j < lb_vip->n_backends; j++) { struct ovn_lb_backend *lb_backend = &lb_vip->backends[j]; - add_lb_vip_hairpin_flows(lb, lb_vip, lb_backend, lb_proto, + add_lb_vip_hairpin_flows(lb, lb_vip, lb_backend, use_ct_mark, flow_table); } } - add_lb_ct_snat_hairpin_flows(lb, id, lb_proto, flow_table); - - ovn_controller_lb_destroy(lb); - sset_destroy(&template_vars_ref); + add_lb_ct_snat_hairpin_flows(lb, id, flow_table); } /* Adds OpenFlow flows to flow tables for each Load balancer VIPs and * backends to handle the load balanced hairpin traffic. */ static void -add_lb_hairpin_flows(struct objdep_mgr *mgr, - const struct sbrec_load_balancer_table *lb_table, - const struct hmap *local_datapaths, - const struct smap *template_vars, +add_lb_hairpin_flows(const struct hmap *local_lbs, bool use_ct_mark, struct ovn_desired_flow_table *flow_table, struct simap *ids, struct id_pool *pool) { uint32_t id; - const struct sbrec_load_balancer *lb; - SBREC_LOAD_BALANCER_TABLE_FOR_EACH (lb, lb_table) { + const struct ovn_controller_lb *lb; + HMAP_FOR_EACH (lb, hmap_node, local_lbs) { /* Allocate a unique 32-bit integer to this load-balancer. This will * be used as a conjunctive flow id in the OFTABLE_CT_SNAT_HAIRPIN * table. @@ -2152,13 +2054,12 @@ add_lb_hairpin_flows(struct objdep_mgr *mgr, * "UINT32_MAX" load-balancers. */ - id = simap_get(ids, lb->name); + id = simap_get(ids, lb->slb->name); if (!id) { ovs_assert(id_pool_alloc_id(pool, &id)); - simap_put(ids, lb->name, id); + simap_put(ids, lb->slb->name, id); } - consider_lb_hairpin_flows(mgr, lb, local_datapaths, template_vars, - use_ct_mark, flow_table, ids); + consider_lb_hairpin_flows(lb, use_ct_mark, flow_table, ids); } } @@ -2294,9 +2195,7 @@ lflow_run(struct lflow_ctx_in *l_ctx_in, struct lflow_ctx_out *l_ctx_out) l_ctx_in->static_mac_binding_table, l_ctx_in->local_datapaths, l_ctx_out->flow_table); - add_lb_hairpin_flows(l_ctx_out->lb_deps_mgr, l_ctx_in->lb_table, - l_ctx_in->local_datapaths, - l_ctx_in->template_vars, + add_lb_hairpin_flows(l_ctx_in->local_lbs, l_ctx_in->lb_hairpin_use_ct_mark, l_ctx_out->flow_table, l_ctx_out->hairpin_lb_ids, @@ -2333,8 +2232,6 @@ lflow_destroy(void) bool lflow_add_flows_for_datapath(const struct sbrec_datapath_binding *dp, - const struct sbrec_load_balancer **dp_lbs, - size_t n_dp_lbs, struct lflow_ctx_in *l_ctx_in, struct lflow_ctx_out *l_ctx_out) { @@ -2424,17 +2321,6 @@ lflow_add_flows_for_datapath(const struct sbrec_datapath_binding *dp, } sbrec_static_mac_binding_index_destroy_row(smb_index_row); - /* Add load balancer hairpin flows if the datapath has any load balancers - * associated. */ - for (size_t i = 0; i < n_dp_lbs; i++) { - consider_lb_hairpin_flows(l_ctx_out->lb_deps_mgr, dp_lbs[i], - l_ctx_in->local_datapaths, - l_ctx_in->template_vars, - l_ctx_in->lb_hairpin_use_ct_mark, - l_ctx_out->flow_table, - l_ctx_out->hairpin_lb_ids); - } - return handled; } @@ -2529,52 +2415,58 @@ lflow_handle_changed_mc_groups(struct lflow_ctx_in *l_ctx_in, bool lflow_handle_changed_lbs(struct lflow_ctx_in *l_ctx_in, - struct lflow_ctx_out *l_ctx_out) + struct lflow_ctx_out *l_ctx_out, + const struct uuidset *deleted_lbs, + const struct uuidset *updated_lbs, + const struct uuidset *new_lbs, + const struct hmap *old_lbs) { - const struct sbrec_load_balancer *lb; + const struct ovn_controller_lb *lb; + struct id_pool *pool = l_ctx_out->hairpin_id_pool; struct simap *ids = l_ctx_out->hairpin_lb_ids; - SBREC_LOAD_BALANCER_TABLE_FOR_EACH_TRACKED (lb, l_ctx_in->lb_table) { - if (sbrec_load_balancer_is_deleted(lb)) { - VLOG_DBG("Remove hairpin flows for deleted load balancer "UUID_FMT, - UUID_ARGS(&lb->header_.uuid)); - ofctrl_remove_flows(l_ctx_out->flow_table, &lb->header_.uuid); - id_pool_free_id(pool, simap_get(ids, lb->name)); - simap_find_and_delete(ids, lb->name); - } + struct uuidset_node *uuid_node; + UUIDSET_FOR_EACH (uuid_node, deleted_lbs) { + lb = ovn_controller_lb_find(old_lbs, &uuid_node->uuid); + + VLOG_DBG("Remove hairpin flows for deleted load balancer "UUID_FMT, + UUID_ARGS(&uuid_node->uuid)); + ofctrl_remove_flows(l_ctx_out->flow_table, &uuid_node->uuid); + id_pool_free_id(pool, simap_get(ids, lb->slb->name)); + simap_find_and_delete(ids, lb->slb->name); } - SBREC_LOAD_BALANCER_TABLE_FOR_EACH_TRACKED (lb, l_ctx_in->lb_table) { - if (sbrec_load_balancer_is_deleted(lb)) { - continue; - } + UUIDSET_FOR_EACH (uuid_node, updated_lbs) { + lb = ovn_controller_lb_find(l_ctx_in->local_lbs, &uuid_node->uuid); - if (!sbrec_load_balancer_is_new(lb)) { - VLOG_DBG("Remove hairpin flows for updated load balancer "UUID_FMT, - UUID_ARGS(&lb->header_.uuid)); - ofctrl_remove_flows(l_ctx_out->flow_table, &lb->header_.uuid); - } else { - /* Allocate a unique 32-bit integer to this load-balancer. This - * will be used as a conjunctive flow id in the - * OFTABLE_CT_SNAT_HAIRPIN table. - * - * If we are unable to allocate a unique ID then we have run out of - * ids. As this is unrecoverable then we abort. However, this is - * unlikely to happen as it would be mean that we have created - * "UINT32_MAX" load-balancers. - */ - uint32_t id; - ovs_assert(id_pool_alloc_id(pool, &id)); - simap_put(ids, lb->name, id); - } + VLOG_DBG("Remove and add hairpin flows for updated load balancer " + UUID_FMT, UUID_ARGS(&uuid_node->uuid)); + ofctrl_remove_flows(l_ctx_out->flow_table, &uuid_node->uuid); + consider_lb_hairpin_flows(lb, l_ctx_in->lb_hairpin_use_ct_mark, + l_ctx_out->flow_table, + l_ctx_out->hairpin_lb_ids); + } + + UUIDSET_FOR_EACH (uuid_node, new_lbs) { + lb = ovn_controller_lb_find(l_ctx_in->local_lbs, &uuid_node->uuid); + + /* Allocate a unique 32-bit integer to this load-balancer. This + * will be used as a conjunctive flow id in the + * OFTABLE_CT_SNAT_HAIRPIN table. + * + * If we are unable to allocate a unique ID then we have run out of + * ids. As this is unrecoverable then we abort. However, this is + * unlikely to happen as it would be mean that we have created + * "UINT32_MAX" load-balancers. + */ + uint32_t id; + ovs_assert(id_pool_alloc_id(pool, &id)); + simap_put(ids, lb->slb->name, id); VLOG_DBG("Add load balancer hairpin flows for "UUID_FMT, - UUID_ARGS(&lb->header_.uuid)); - consider_lb_hairpin_flows(l_ctx_out->lb_deps_mgr, lb, - l_ctx_in->local_datapaths, - l_ctx_in->template_vars, - l_ctx_in->lb_hairpin_use_ct_mark, + UUID_ARGS(&uuid_node->uuid)); + consider_lb_hairpin_flows(lb, l_ctx_in->lb_hairpin_use_ct_mark, l_ctx_out->flow_table, l_ctx_out->hairpin_lb_ids); } diff --git a/controller/lflow.h b/controller/lflow.h index 9bb61c039..44e534696 100644 --- a/controller/lflow.h +++ b/controller/lflow.h @@ -101,7 +101,6 @@ struct lflow_ctx_in { const struct sbrec_multicast_group_table *mc_group_table; const struct sbrec_fdb_table *fdb_table; const struct sbrec_chassis *chassis; - const struct sbrec_load_balancer_table *lb_table; const struct sbrec_static_mac_binding_table *static_mac_binding_table; const struct hmap *local_datapaths; const struct shash *addr_sets; @@ -116,6 +115,7 @@ struct lflow_ctx_in { const struct controller_event_options *controller_event_opts; const struct smap *template_vars; const struct flow_collector_ids *collector_ids; + const struct hmap *local_lbs; bool lb_hairpin_use_ct_mark; }; @@ -161,13 +161,16 @@ void lflow_handle_changed_static_mac_bindings( const struct sbrec_static_mac_binding_table *smb_table, const struct hmap *local_datapaths, struct ovn_desired_flow_table *); -bool lflow_handle_changed_lbs(struct lflow_ctx_in *, struct lflow_ctx_out *); +bool lflow_handle_changed_lbs(struct lflow_ctx_in *l_ctx_in, + struct lflow_ctx_out *l_ctx_out, + const struct uuidset *deleted_lbs, + const struct uuidset *updated_lbs, + const struct uuidset *new_lbs, + const struct hmap *old_lbs); bool lflow_handle_changed_fdbs(struct lflow_ctx_in *, struct lflow_ctx_out *); void lflow_destroy(void); bool lflow_add_flows_for_datapath(const struct sbrec_datapath_binding *, - const struct sbrec_load_balancer **dp_lbs, - size_t n_dp_lbs, struct lflow_ctx_in *, struct lflow_ctx_out *); bool lflow_handle_flows_for_lport(const struct sbrec_port_binding *, @@ -178,7 +181,4 @@ bool lflow_handle_changed_mc_groups(struct lflow_ctx_in *, bool lflow_handle_changed_port_bindings(struct lflow_ctx_in *, struct lflow_ctx_out *); -bool lb_handle_changed_ref(enum objdep_type type, const char *res_name, - struct ovs_list *objs_todo, - const void *in_arg, void *out_arg); #endif /* controller/lflow.h */ diff --git a/controller/local_data.c b/controller/local_data.c index 035f10fff..abd372172 100644 --- a/controller/local_data.c +++ b/controller/local_data.c @@ -645,3 +645,29 @@ datapath_is_transit_switch(const struct sbrec_datapath_binding *ldp) { return smap_get(&ldp->external_ids, "interconn-ts") != NULL; } + +bool +lb_is_local(const struct sbrec_load_balancer *sbrec_lb, + const struct hmap *local_datapaths) +{ + /* Check if the lb is local or not. It is enough to find one datapath + * in "local_datapaths" to consider the LB to be local. */ + size_t i; + for (i = 0; i < sbrec_lb->n_datapaths; i++) { + if (get_local_datapath(local_datapaths, + sbrec_lb->datapaths[i]->tunnel_key)) { + return true; + } + } + + struct sbrec_logical_dp_group *dp_group = sbrec_lb->datapath_group; + + for (i = 0; dp_group && i < dp_group->n_datapaths; i++) { + if (get_local_datapath(local_datapaths, + dp_group->datapaths[i]->tunnel_key)) { + return true; + } + } + + return false; +} diff --git a/controller/local_data.h b/controller/local_data.h index b5429eb58..748f009aa 100644 --- a/controller/local_data.h +++ b/controller/local_data.h @@ -30,6 +30,7 @@ struct sbrec_chassis; struct ovsdb_idl_index; struct ovsrec_bridge; struct ovsrec_interface_table; +struct sbrec_load_balancer; /* A logical datapath that has some relevance to this hypervisor. A logical * datapath D is relevant to hypervisor H if: @@ -161,5 +162,7 @@ void add_local_datapath_multichassis_port(struct local_datapath *ld, const void *data); void remove_local_datapath_multichassis_port(struct local_datapath *ld, char *logical_port); +bool lb_is_local(const struct sbrec_load_balancer *sbrec_lb, + const struct hmap *local_datapaths); #endif /* controller/local_data.h */ diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 6ea96e2dd..d96f16cc2 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -38,6 +38,7 @@ #include "if-status.h" #include "ip-mcast.h" #include "openvswitch/hmap.h" +#include "lb.h" #include "lflow.h" #include "lflow-cache.h" #include "lflow-conj-ids.h" @@ -2661,6 +2662,377 @@ load_balancers_by_dp_cleanup(struct hmap *lbs) free(lbs); } +/* Engine node which is used to handle runtime related data to + * load balancers. */ +struct ed_type_lb_data { + /* Locally installed 'struct ovn_controller_lb' by UUID. */ + struct hmap local_lbs; + /* Load balancer <-> resource cross reference */ + struct objdep_mgr deps_mgr; + /* Objects processed in the current engine execution. + * Cleared by 'en_lb_data_clear_tracked_data' before each engine + * execution. */ + struct uuidset objs_processed; + + bool change_tracked; + /* Load balancers removed/updated during last run. */ + struct hmap old_lbs; + /* uuids of load balancers removed during last run. */ + struct uuidset deleted; + /* uuids of load balancers updated during last run. */ + struct uuidset updated; + /* uuids of load balancers added during last run. */ + struct uuidset new; +}; + +struct lb_data_ctx_in { + const struct sbrec_load_balancer_table *lb_table; + const struct hmap *local_datapths; + const struct smap *template_vars; +}; + +static void +lb_data_local_lb_add(struct ed_type_lb_data *lb_data, + const struct sbrec_load_balancer *sbrec_lb, + const struct smap *template_vars, bool tracked) +{ + struct sset template_vars_ref = SSET_INITIALIZER(&template_vars_ref); + const struct uuid *uuid = &sbrec_lb->header_.uuid; + + struct ovn_controller_lb *lb = + ovn_controller_lb_create(sbrec_lb, template_vars, &template_vars_ref); + hmap_insert(&lb_data->local_lbs, &lb->hmap_node, uuid_hash(uuid)); + + const char *tv_name; + SSET_FOR_EACH (tv_name, &template_vars_ref) { + objdep_mgr_add(&lb_data->deps_mgr, OBJDEP_TYPE_TEMPLATE, tv_name, + uuid); + } + + sset_destroy(&template_vars_ref); + + if (!tracked) { + return; + } + + if (ovn_controller_lb_find(&lb_data->old_lbs, uuid)) { + uuidset_insert(&lb_data->updated, uuid); + uuidset_find_and_delete(&lb_data->deleted, uuid); + } else { + uuidset_insert(&lb_data->new, uuid); + } +} + +static void +lb_data_local_lb_remove(struct ed_type_lb_data *lb_data, + struct ovn_controller_lb *lb, bool tracked) +{ + const struct uuid *uuid = &lb->slb->header_.uuid; + + objdep_mgr_remove_obj(&lb_data->deps_mgr, uuid); + hmap_remove(&lb_data->local_lbs, &lb->hmap_node); + + if (tracked) { + hmap_insert(&lb_data->old_lbs, &lb->hmap_node, uuid_hash(uuid)); + uuidset_insert(&lb_data->deleted, uuid); + } else { + ovn_controller_lb_destroy(lb); + } +} + +static bool +lb_data_handle_changed_ref(enum objdep_type type, const char *res_name, + struct ovs_list *objs_todo, const void *in_arg, + void *out_arg) +{ + const struct lb_data_ctx_in *ctx_in = in_arg; + struct ed_type_lb_data *lb_data = out_arg; + + struct object_to_resources_list_node *resource_lb_uuid; + LIST_FOR_EACH_POP (resource_lb_uuid, list_node, objs_todo) { + struct uuid *uuid = &resource_lb_uuid->obj_uuid; + + VLOG_DBG("Reprocess LB "UUID_FMT" for resource type: %s, name: %s", + UUID_ARGS(uuid), objdep_type_name(type), res_name); + + struct ovn_controller_lb *lb = + ovn_controller_lb_find(&lb_data->local_lbs, uuid); + if (!lb) { + free(resource_lb_uuid); + continue; + } + + lb_data_local_lb_remove(lb_data, lb, true); + + const struct sbrec_load_balancer *sbrec_lb = + sbrec_load_balancer_table_get_for_uuid(ctx_in->lb_table, uuid); + if (!lb_is_local(sbrec_lb, ctx_in->local_datapths)) { + free(resource_lb_uuid); + continue; + } + + lb_data_local_lb_add(lb_data, sbrec_lb, ctx_in->template_vars, true); + + free(resource_lb_uuid); + } + return true; +} + +static void * +en_lb_data_init(struct engine_node *node OVS_UNUSED, + struct engine_arg *arg OVS_UNUSED) +{ + struct ed_type_lb_data *lb_data = xzalloc(sizeof *lb_data); + + hmap_init(&lb_data->local_lbs); + objdep_mgr_init(&lb_data->deps_mgr); + uuidset_init(&lb_data->objs_processed); + lb_data->change_tracked = false; + hmap_init(&lb_data->old_lbs); + uuidset_init(&lb_data->deleted); + uuidset_init(&lb_data->updated); + uuidset_init(&lb_data->new); + + return lb_data; +} + +static void +en_lb_data_run(struct engine_node *node, void *data) +{ + struct ed_type_lb_data *lb_data = data; + struct ed_type_runtime_data *rt_data = + engine_get_input_data("runtime_data", node); + struct ed_type_template_vars *tv_data = + engine_get_input_data("template_vars", node); + const struct sbrec_load_balancer_table *lb_table = + EN_OVSDB_GET(engine_get_input("SB_load_balancer", node)); + + struct ovn_controller_lb *lb; + HMAP_FOR_EACH_SAFE (lb, hmap_node, &lb_data->local_lbs) { + lb_data_local_lb_remove(lb_data, lb, false); + } + + const struct sbrec_load_balancer *sbrec_lb; + SBREC_LOAD_BALANCER_TABLE_FOR_EACH (sbrec_lb, lb_table) { + if (!lb_is_local(sbrec_lb, &rt_data->local_datapaths)) { + continue; + } + + lb_data_local_lb_add(lb_data, sbrec_lb, + &tv_data->local_templates, false); + } + + engine_set_node_state(node, EN_UPDATED); +} + +static bool +lb_data_sb_load_balancer_handler(struct engine_node *node, void *data) +{ + struct ed_type_lb_data *lb_data = data; + struct ed_type_runtime_data *rt_data = + engine_get_input_data("runtime_data", node); + struct ed_type_template_vars *tv_data = + engine_get_input_data("template_vars", node); + const struct sbrec_load_balancer_table *lb_table = + EN_OVSDB_GET(engine_get_input("SB_load_balancer", node)); + + const struct sbrec_load_balancer *sbrec_lb; + SBREC_LOAD_BALANCER_TABLE_FOR_EACH_TRACKED (sbrec_lb, lb_table) { + struct ovn_controller_lb *lb; + + if (!sbrec_load_balancer_is_new(sbrec_lb)) { + lb = ovn_controller_lb_find(&lb_data->local_lbs, + &sbrec_lb->header_.uuid); + if (!lb) { + continue; + } + + lb_data_local_lb_remove(lb_data, lb, true); + } + + if (sbrec_load_balancer_is_deleted(sbrec_lb) || + !lb_is_local(sbrec_lb, &rt_data->local_datapaths)) { + continue; + } + + lb_data_local_lb_add(lb_data, sbrec_lb, + &tv_data->local_templates, true); + } + + lb_data->change_tracked = true; + if (!uuidset_is_empty(&lb_data->deleted) || + !uuidset_is_empty(&lb_data->updated) || + !uuidset_is_empty(&lb_data->new)) { + engine_set_node_state(node, EN_UPDATED); + } + + return true; +} + +static bool +lb_data_template_var_handler(struct engine_node *node, void *data) +{ + struct ed_type_lb_data *lb_data = data; + struct ed_type_runtime_data *rt_data = + engine_get_input_data("runtime_data", node); + struct ed_type_template_vars *tv_data = + engine_get_input_data("template_vars", node); + const struct sbrec_load_balancer_table *lb_table = + EN_OVSDB_GET(engine_get_input("SB_load_balancer", node)); + + if (!tv_data->change_tracked) { + return false; + } + + const struct lb_data_ctx_in ctx_in = { + .lb_table = lb_table, + .local_datapths = &rt_data->local_datapaths, + .template_vars = &tv_data->local_templates + }; + + const char *res_name; + bool changed; + + SSET_FOR_EACH (res_name, &tv_data->deleted) { + if (!objdep_mgr_handle_change(&lb_data->deps_mgr, + OBJDEP_TYPE_TEMPLATE, + res_name, lb_data_handle_changed_ref, + &lb_data->objs_processed, + &ctx_in, lb_data, &changed)) { + return false; + } + if (changed) { + engine_set_node_state(node, EN_UPDATED); + } + } + SSET_FOR_EACH (res_name, &tv_data->updated) { + if (!objdep_mgr_handle_change(&lb_data->deps_mgr, + OBJDEP_TYPE_TEMPLATE, + res_name, lb_data_handle_changed_ref, + &lb_data->objs_processed, + &ctx_in, lb_data, &changed)) { + return false; + } + if (changed) { + engine_set_node_state(node, EN_UPDATED); + } + } + SSET_FOR_EACH (res_name, &tv_data->new) { + if (!objdep_mgr_handle_change(&lb_data->deps_mgr, + OBJDEP_TYPE_TEMPLATE, + res_name, lb_data_handle_changed_ref, + &lb_data->objs_processed, + &ctx_in, lb_data, &changed)) { + return false; + } + if (changed) { + engine_set_node_state(node, EN_UPDATED); + } + } + + lb_data->change_tracked = true; + + return true; +} + +static bool +lb_data_runtime_data_handler(struct engine_node *node, void *data OVS_UNUSED) +{ + struct ed_type_lb_data *lb_data = data; + struct ed_type_runtime_data *rt_data = + engine_get_input_data("runtime_data", node); + struct ed_type_template_vars *tv_data = + engine_get_input_data("template_vars", node); + const struct sbrec_load_balancer_table *lb_table = + EN_OVSDB_GET(engine_get_input("SB_load_balancer", node)); + + /* There are no tracked data. Fall back to full recompute of + * lb_ct_tuple. */ + 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 hmap *lbs = NULL; + + struct tracked_datapath *tdp; + HMAP_FOR_EACH (tdp, node, tracked_dp_bindings) { + if (tdp->tracked_type != TRACKED_RESOURCE_NEW) { + continue; + } + + if (!lbs) { + lbs = load_balancers_by_dp_init(&rt_data->local_datapaths, + lb_table); + } + + struct load_balancers_by_dp *lbs_by_dp = + load_balancers_by_dp_find(lbs, tdp->dp); + if (!lbs_by_dp) { + continue; + } + + for (size_t i = 0; i < lbs_by_dp->n_dp_lbs; i++) { + const struct sbrec_load_balancer *sbrec_lb = lbs_by_dp->dp_lbs[i]; + struct ovn_controller_lb *lb = + ovn_controller_lb_find(&lb_data->local_lbs, + &sbrec_lb->header_.uuid); + + if (!lb && lb_is_local(sbrec_lb, &rt_data->local_datapaths)) { + lb_data_local_lb_add(lb_data, sbrec_lb, + &tv_data->local_templates, true); + } + } + } + + load_balancers_by_dp_cleanup(lbs); + + lb_data->change_tracked = true; + if (!uuidset_is_empty(&lb_data->deleted) || + !uuidset_is_empty(&lb_data->updated) || + !uuidset_is_empty(&lb_data->new)) { + engine_set_node_state(node, EN_UPDATED); + } + + return true; +} + +static void +en_lb_data_clear_tracked_data(void *data) +{ + struct ed_type_lb_data *lb_data = data; + + struct ovn_controller_lb *lb; + HMAP_FOR_EACH_POP (lb, hmap_node, &lb_data->old_lbs) { + ovn_controller_lb_destroy(lb); + } + + hmap_clear(&lb_data->old_lbs); + uuidset_clear(&lb_data->objs_processed); + uuidset_clear(&lb_data->deleted); + uuidset_clear(&lb_data->updated); + uuidset_clear(&lb_data->new); + lb_data->change_tracked = false; +} + +static void +en_lb_data_cleanup(void *data) +{ + struct ed_type_lb_data *lb_data = data; + + ovn_controller_lbs_destroy(&lb_data->local_lbs); + objdep_mgr_destroy(&lb_data->deps_mgr); + uuidset_destroy(&lb_data->objs_processed); + ovn_controller_lbs_destroy(&lb_data->old_lbs); + uuidset_destroy(&lb_data->deleted); + uuidset_destroy(&lb_data->updated); + uuidset_destroy(&lb_data->new); +} + /* Engine node which is used to handle the Non VIF data like * - OVS patch ports * - Tunnel ports and the related chassis information. @@ -2858,12 +3230,10 @@ struct ed_type_lflow_output { struct ovn_extend_table meter_table; /* lflow <-> resource cross reference */ struct objdep_mgr lflow_deps_mgr;; - /* load balancer <-> resource cross reference */ - struct objdep_mgr lb_deps_mgr; /* conjunciton ID usage information of lflows */ struct conj_ids conj_ids; - /* objects (lflows and lbs) processed in the current engine execution. + /* objects (lflows) processed in the current engine execution. * Cleared by en_lflow_output_clear_tracked_data before each engine * execution. */ struct uuidset objs_processed; @@ -2941,9 +3311,6 @@ init_lflow_ctx(struct engine_node *node, const struct sbrec_multicast_group_table *multicast_group_table = EN_OVSDB_GET(engine_get_input("SB_multicast_group", node)); - const struct sbrec_load_balancer_table *lb_table = - EN_OVSDB_GET(engine_get_input("SB_load_balancer", node)); - const struct sbrec_fdb_table *fdb_table = EN_OVSDB_GET(engine_get_input("SB_fdb", node)); @@ -2988,6 +3355,9 @@ init_lflow_ctx(struct engine_node *node, struct ed_type_template_vars *template_vars = engine_get_input_data("template_vars", node); + struct ed_type_lb_data *lb_data = + engine_get_input_data("lb_data", node); + l_ctx_in->sbrec_multicast_group_by_name_datapath = sbrec_mc_group_by_name_dp; l_ctx_in->sbrec_logical_flow_by_logical_datapath = @@ -3006,7 +3376,6 @@ init_lflow_ctx(struct engine_node *node, l_ctx_in->mc_group_table = multicast_group_table; l_ctx_in->fdb_table = fdb_table, l_ctx_in->chassis = chassis; - l_ctx_in->lb_table = lb_table; l_ctx_in->static_mac_binding_table = smb_table; l_ctx_in->local_datapaths = &rt_data->local_datapaths; l_ctx_in->addr_sets = addr_sets; @@ -3022,12 +3391,12 @@ init_lflow_ctx(struct engine_node *node, l_ctx_in->controller_event_opts = &fo->controller_event_opts; l_ctx_in->template_vars = &template_vars->local_templates; l_ctx_in->collector_ids = &fo->collector_ids; + l_ctx_in->local_lbs = &lb_data->local_lbs; l_ctx_out->flow_table = &fo->flow_table; l_ctx_out->group_table = &fo->group_table; l_ctx_out->meter_table = &fo->meter_table; l_ctx_out->lflow_deps_mgr = &fo->lflow_deps_mgr; - l_ctx_out->lb_deps_mgr = &fo->lb_deps_mgr; l_ctx_out->conj_ids = &fo->conj_ids; l_ctx_out->objs_processed = &fo->objs_processed; l_ctx_out->lflow_cache = fo->pd.lflow_cache; @@ -3044,7 +3413,6 @@ en_lflow_output_init(struct engine_node *node OVS_UNUSED, ovn_extend_table_init(&data->group_table); ovn_extend_table_init(&data->meter_table); objdep_mgr_init(&data->lflow_deps_mgr); - objdep_mgr_init(&data->lb_deps_mgr); lflow_conj_ids_init(&data->conj_ids); uuidset_init(&data->objs_processed); simap_init(&data->hd.ids); @@ -3070,7 +3438,6 @@ en_lflow_output_cleanup(void *data) ovn_extend_table_destroy(&flow_output_data->group_table); ovn_extend_table_destroy(&flow_output_data->meter_table); objdep_mgr_destroy(&flow_output_data->lflow_deps_mgr); - objdep_mgr_destroy(&flow_output_data->lb_deps_mgr); lflow_conj_ids_destroy(&flow_output_data->conj_ids); uuidset_destroy(&flow_output_data->objs_processed); lflow_cache_destroy(flow_output_data->pd.lflow_cache); @@ -3108,7 +3475,6 @@ en_lflow_output_run(struct engine_node *node, void *data) struct ovn_extend_table *group_table = &fo->group_table; struct ovn_extend_table *meter_table = &fo->meter_table; struct objdep_mgr *lflow_deps_mgr = &fo->lflow_deps_mgr; - struct objdep_mgr *lb_deps_mgr = &fo->lb_deps_mgr; static bool first_run = true; if (first_run) { @@ -3118,7 +3484,6 @@ en_lflow_output_run(struct engine_node *node, void *data) ovn_extend_table_clear(group_table, false /* desired */); ovn_extend_table_clear(meter_table, false /* desired */); objdep_mgr_clear(lflow_deps_mgr); - objdep_mgr_clear(lb_deps_mgr); lflow_conj_ids_clear(&fo->conj_ids); } @@ -3481,16 +3846,6 @@ lflow_output_template_vars_handler(struct engine_node *node, void *data) if (changed) { engine_set_node_state(node, EN_UPDATED); } - if (!objdep_mgr_handle_change(l_ctx_out.lb_deps_mgr, - OBJDEP_TYPE_TEMPLATE, - res_name, lb_handle_changed_ref, - l_ctx_out.objs_processed, - &l_ctx_in, &l_ctx_out, &changed)) { - return false; - } - if (changed) { - engine_set_node_state(node, EN_UPDATED); - } } SSET_FOR_EACH (res_name, &tv_data->updated) { if (!objdep_mgr_handle_change(l_ctx_out.lflow_deps_mgr, @@ -3503,16 +3858,6 @@ lflow_output_template_vars_handler(struct engine_node *node, void *data) if (changed) { engine_set_node_state(node, EN_UPDATED); } - if (!objdep_mgr_handle_change(l_ctx_out.lb_deps_mgr, - OBJDEP_TYPE_TEMPLATE, - res_name, lb_handle_changed_ref, - l_ctx_out.objs_processed, - &l_ctx_in, &l_ctx_out, &changed)) { - return false; - } - if (changed) { - engine_set_node_state(node, EN_UPDATED); - } } SSET_FOR_EACH (res_name, &tv_data->new) { if (!objdep_mgr_handle_change(l_ctx_out.lflow_deps_mgr, @@ -3525,16 +3870,6 @@ lflow_output_template_vars_handler(struct engine_node *node, void *data) if (changed) { engine_set_node_state(node, EN_UPDATED); } - if (!objdep_mgr_handle_change(l_ctx_out.lb_deps_mgr, - OBJDEP_TYPE_TEMPLATE, - res_name, lb_handle_changed_ref, - l_ctx_out.objs_processed, - &l_ctx_in, &l_ctx_out, &changed)) { - return false; - } - if (changed) { - engine_set_node_state(node, EN_UPDATED); - } } return true; @@ -3564,23 +3899,13 @@ 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; - struct hmap *lbs = NULL; init_lflow_ctx(node, fo, &l_ctx_in, &l_ctx_out); struct tracked_datapath *tdp; HMAP_FOR_EACH (tdp, node, tracked_dp_bindings) { if (tdp->tracked_type == TRACKED_RESOURCE_NEW) { - if (!lbs) { - lbs = load_balancers_by_dp_init(&rt_data->local_datapaths, - l_ctx_in.lb_table); - } - - struct load_balancers_by_dp *lbs_by_dp = - load_balancers_by_dp_find(lbs, tdp->dp); - if (!lflow_add_flows_for_datapath( - tdp->dp, lbs_by_dp ? lbs_by_dp->dp_lbs : NULL, - lbs_by_dp ? lbs_by_dp->n_dp_lbs : 0, - &l_ctx_in, &l_ctx_out)) { + if (!lflow_add_flows_for_datapath(tdp->dp, &l_ctx_in, + &l_ctx_out)) { return false; } } @@ -3594,20 +3919,29 @@ lflow_output_runtime_data_handler(struct engine_node *node, } } - load_balancers_by_dp_cleanup(lbs); engine_set_node_state(node, EN_UPDATED); return true; } static bool -lflow_output_sb_load_balancer_handler(struct engine_node *node, void *data) +lflow_output_lb_data_handler(struct engine_node *node, void *data) { struct ed_type_lflow_output *fo = data; + struct ed_type_lb_data *lb_data = engine_get_input_data("lb_data", node); + + if (!lb_data->change_tracked) { + return false; + } + struct lflow_ctx_in l_ctx_in; struct lflow_ctx_out l_ctx_out; init_lflow_ctx(node, fo, &l_ctx_in, &l_ctx_out); - bool handled = lflow_handle_changed_lbs(&l_ctx_in, &l_ctx_out); + bool handled = lflow_handle_changed_lbs(&l_ctx_in, &l_ctx_out, + &lb_data->deleted, + &lb_data->updated, + &lb_data->new, + &lb_data->old_lbs); engine_set_node_state(node, EN_UPDATED); return handled; @@ -4243,6 +4577,7 @@ main(int argc, char *argv[]) ENGINE_NODE_WITH_CLEAR_TRACK_DATA(port_groups, "port_groups"); ENGINE_NODE(northd_options, "northd_options"); ENGINE_NODE(dhcp_options, "dhcp_options"); + ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lb_data, "lb_data"); #define SB_NODE(NAME, NAME_STR) ENGINE_NODE_SB(NAME, NAME_STR); SB_NODES @@ -4258,6 +4593,13 @@ main(int argc, char *argv[]) engine_add_input(&en_template_vars, &en_sb_chassis_template_var, template_vars_sb_chassis_template_var_handler); + engine_add_input(&en_lb_data, &en_sb_load_balancer, + lb_data_sb_load_balancer_handler); + engine_add_input(&en_lb_data, &en_template_vars, + lb_data_template_var_handler); + engine_add_input(&en_lb_data, &en_runtime_data, + lb_data_runtime_data_handler); + engine_add_input(&en_addr_sets, &en_sb_address_set, addr_sets_sb_address_set_handler); engine_add_input(&en_port_groups, &en_sb_port_group, @@ -4362,8 +4704,8 @@ main(int argc, char *argv[]) engine_add_input(&en_lflow_output, &en_sb_logical_dp_group, engine_noop_handler); engine_add_input(&en_lflow_output, &en_sb_dns, NULL); - engine_add_input(&en_lflow_output, &en_sb_load_balancer, - lflow_output_sb_load_balancer_handler); + engine_add_input(&en_lflow_output, &en_lb_data, + lflow_output_lb_data_handler); engine_add_input(&en_lflow_output, &en_sb_fdb, lflow_output_sb_fdb_handler); engine_add_input(&en_lflow_output, &en_sb_meter, diff --git a/lib/lb.c b/lib/lb.c index e0e97572f..de25c68c0 100644 --- a/lib/lb.c +++ b/lib/lb.c @@ -741,6 +741,15 @@ ovn_controller_lb_create(const struct sbrec_load_balancer *sbrec_lb, lex_str_free(&value_s); } + lb->proto = IPPROTO_TCP; + if (sbrec_lb->protocol && sbrec_lb->protocol[0]) { + if (!strcmp(sbrec_lb->protocol, "udp")) { + lb->proto = IPPROTO_UDP; + } else if (!strcmp(sbrec_lb->protocol, "sctp")) { + lb->proto = IPPROTO_SCTP; + } + } + /* It's possible that parsing VIPs fails. Update the lb->n_vips to the * correct value. */ @@ -764,3 +773,28 @@ ovn_controller_lb_destroy(struct ovn_controller_lb *lb) destroy_lport_addresses(&lb->hairpin_snat_ips); free(lb); } + +void +ovn_controller_lbs_destroy(struct hmap *ovn_controller_lbs) +{ + struct ovn_controller_lb *lb; + HMAP_FOR_EACH_POP (lb, hmap_node, ovn_controller_lbs) { + ovn_controller_lb_destroy(lb); + } + + hmap_destroy(ovn_controller_lbs); +} + +struct ovn_controller_lb * +ovn_controller_lb_find(const struct hmap *ovn_controller_lbs, + const struct uuid *uuid) +{ + struct ovn_controller_lb *lb; + size_t hash = uuid_hash(uuid); + HMAP_FOR_EACH_WITH_HASH (lb, hmap_node, hash, ovn_controller_lbs) { + if (uuid_equals(&lb->slb->header_.uuid, uuid)) { + return lb; + } + } + return NULL; +} diff --git a/lib/lb.h b/lib/lb.h index 7594553d5..f32891ea6 100644 --- a/lib/lb.h +++ b/lib/lb.h @@ -172,8 +172,12 @@ ovn_lb_group_add_lr(struct ovn_lb_group *lb_group, struct ovn_datapath *lr) } struct ovn_controller_lb { + struct hmap_node hmap_node; + const struct sbrec_load_balancer *slb; /* May be NULL. */ + uint8_t proto; + struct ovn_lb_vip *vips; size_t n_vips; bool hairpin_orig_tuple; /* True if ovn-northd stores the original @@ -191,6 +195,10 @@ struct ovn_controller_lb *ovn_controller_lb_create( const struct smap *template_vars, struct sset *template_vars_ref); void ovn_controller_lb_destroy(struct ovn_controller_lb *); +void ovn_controller_lbs_destroy(struct hmap *ovn_controller_lbs); +struct ovn_controller_lb *ovn_controller_lb_find( + const struct hmap *ovn_controller_lbs, + const struct uuid *uuid); char *ovn_lb_vip_init(struct ovn_lb_vip *lb_vip, const char *lb_key, const char *lb_value, bool template, int address_family); -- 2.39.1 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
