On Tue, Jan 30, 2024 at 4:23 PM <[email protected]> wrote: > > From: Numan Siddique <[email protected]> > > It also moves the ovn-controller specific code from lib/lb.c > and lib/lb.h to controller/lb.c and controller/lb.h. > > Acked-by: Han Zhou <[email protected]> > Co-authored-by: Dumitru Ceara <[email protected]> > Signed-off-by: Dumitru Ceara <[email protected]> > Signed-off-by: Numan Siddique <[email protected]>
Recheck-request: github-robot-_Build_and_Test > --- > controller/automake.mk | 2 + > controller/lb.c | 146 ++++++++ > controller/lb.h | 55 +++ > controller/lflow.c | 1 + > lib/lb.c | 771 +--------------------------------------- > lib/lb.h | 199 +---------- > northd/automake.mk | 4 +- > northd/en-lb-data.c | 1 + > northd/en-lr-stateful.c | 1 + > northd/en-sync-sb.c | 1 + > northd/lb.c | 651 +++++++++++++++++++++++++++++++++ > northd/lb.h | 189 ++++++++++ > northd/northd.c | 1 + > 13 files changed, 1068 insertions(+), 954 deletions(-) > create mode 100644 controller/lb.c > create mode 100644 controller/lb.h > create mode 100644 northd/lb.c > create mode 100644 northd/lb.h > > diff --git a/controller/automake.mk b/controller/automake.mk > index 0dbbd5d26b..a17ff0d60b 100644 > --- a/controller/automake.mk > +++ b/controller/automake.mk > @@ -14,6 +14,8 @@ controller_ovn_controller_SOURCES = \ > controller/if-status.h \ > controller/ip-mcast.c \ > controller/ip-mcast.h \ > + controller/lb.c \ > + controller/lb.h \ > controller/lflow.c \ > controller/lflow.h \ > controller/lflow-cache.c \ > diff --git a/controller/lb.c b/controller/lb.c > new file mode 100644 > index 0000000000..8f9f20ed54 > --- /dev/null > +++ b/controller/lb.c > @@ -0,0 +1,146 @@ > +/* > + * Copyright (c) 2024, 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> > + > +/* OpenvSwitch lib includes. */ > +#include "openvswitch/vlog.h" > +#include "lib/smap.h" > + > +/* OVN includes */ > +#include "lb.h" > +#include "lib/ovn-sb-idl.h" > +#include "ovn/lex.h" > + > +VLOG_DEFINE_THIS_MODULE(controller_lb); > + > +static void > +ovn_lb_get_hairpin_snat_ip(const struct uuid *lb_uuid, > + const struct smap *lb_options, > + struct lport_addresses *hairpin_addrs) > +{ > + const char *addresses = smap_get(lb_options, "hairpin_snat_ip"); > + > + if (!addresses) { > + return; > + } > + > + if (!extract_ip_address(addresses, hairpin_addrs)) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); > + VLOG_WARN_RL(&rl, "bad hairpin_snat_ip %s in load balancer "UUID_FMT, > + addresses, UUID_ARGS(lb_uuid)); > + } > +} > + > +struct ovn_controller_lb * > +ovn_controller_lb_create(const struct sbrec_load_balancer *sbrec_lb, > + const struct smap *template_vars, > + struct sset *template_vars_ref) > +{ > + struct ovn_controller_lb *lb = xzalloc(sizeof *lb); > + bool template = smap_get_bool(&sbrec_lb->options, "template", false); > + > + lb->slb = sbrec_lb; > + lb->n_vips = smap_count(&sbrec_lb->vips); > + lb->vips = xcalloc(lb->n_vips, sizeof *lb->vips); > + > + struct smap_node *node; > + size_t n_vips = 0; > + > + SMAP_FOR_EACH (node, &sbrec_lb->vips) { > + struct ovn_lb_vip *lb_vip = &lb->vips[n_vips]; > + > + struct lex_str key_s = template > + ? lexer_parse_template_string(node->key, > + template_vars, > + > template_vars_ref) > + : lex_str_use(node->key); > + struct lex_str value_s = template > + ? lexer_parse_template_string(node->value, > + template_vars, > + > template_vars_ref) > + : lex_str_use(node->value); > + char *error = ovn_lb_vip_init_explicit(lb_vip, > + lex_str_get(&key_s), > + lex_str_get(&value_s)); > + if (error) { > + free(error); > + } else { > + n_vips++; > + } > + lex_str_free(&key_s); > + 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. > + */ > + lb->n_vips = n_vips; > + > + lb->hairpin_orig_tuple = smap_get_bool(&sbrec_lb->options, > + "hairpin_orig_tuple", > + false); > + lb->ct_flush = smap_get_bool(&sbrec_lb->options, "ct_flush", false); > + ovn_lb_get_hairpin_snat_ip(&sbrec_lb->header_.uuid, &sbrec_lb->options, > + &lb->hairpin_snat_ips); > + return lb; > +} > + > +void > +ovn_controller_lb_destroy(struct ovn_controller_lb *lb) > +{ > + for (size_t i = 0; i < lb->n_vips; i++) { > + ovn_lb_vip_destroy(&lb->vips[i]); > + } > + free(lb->vips); > + 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/controller/lb.h b/controller/lb.h > new file mode 100644 > index 0000000000..84d51c3329 > --- /dev/null > +++ b/controller/lb.h > @@ -0,0 +1,55 @@ > +/* > + * Copyright (c) 2024, 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_CONTROLLER_LB_H > +#define OVN_CONTROLLER_LB_H 1 > + > +#include "lib/lb.h" > + > +struct sbrec_load_balancer; > + > +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 > + * destination tuple in registers. > + */ > + bool ct_flush; /* True if we should flush CT after backend removal. */ > + > + struct lport_addresses hairpin_snat_ips; /* IP (v4 and/or v6) to be used > + * as source for hairpinned > + * traffic. > + */ > +}; > + > +struct ovn_controller_lb *ovn_controller_lb_create( > + const struct sbrec_load_balancer *, > + 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); > + > +#endif /* OVN_CONTROLLER_LB_H */ > + > diff --git a/controller/lflow.c b/controller/lflow.c > index c0cf0aa106..895d17d193 100644 > --- a/controller/lflow.c > +++ b/controller/lflow.c > @@ -18,6 +18,7 @@ > #include "lflow.h" > #include "coverage.h" > #include "ha-chassis.h" > +#include "lb.h" > #include "lflow-cache.h" > #include "local_data.h" > #include "lport.h" > diff --git a/lib/lb.c b/lib/lb.c > index d0d562b6fb..e67a5fcfd0 100644 > --- a/lib/lb.c > +++ b/lib/lb.c > @@ -16,76 +16,16 @@ > #include <config.h> > > #include "lb.h" > -#include "lib/ovn-nb-idl.h" > -#include "lib/ovn-sb-idl.h" > #include "lib/ovn-util.h" > -#include "northd/northd.h" > #include "ovn/lex.h" > > /* OpenvSwitch lib includes. */ > #include "openvswitch/vlog.h" > -#include "lib/bitmap.h" > -#include "lib/smap.h" > -#include "socket-util.h" > > VLOG_DEFINE_THIS_MODULE(lb); > > -static const char *lb_neighbor_responder_mode_names[] = { > - [LB_NEIGH_RESPOND_REACHABLE] = "reachable", > - [LB_NEIGH_RESPOND_ALL] = "all", > - [LB_NEIGH_RESPOND_NONE] = "none", > -}; > - > -static struct nbrec_load_balancer_health_check * > -ovn_lb_get_health_check(const struct nbrec_load_balancer *nbrec_lb, > - const char *vip_port_str, bool template); > static void ovn_lb_backends_clear(struct ovn_lb_vip *vip); > > -struct ovn_lb_ip_set * > -ovn_lb_ip_set_create(void) > -{ > - struct ovn_lb_ip_set *lb_ip_set = xzalloc(sizeof *lb_ip_set); > - > - sset_init(&lb_ip_set->ips_v4); > - sset_init(&lb_ip_set->ips_v4_routable); > - sset_init(&lb_ip_set->ips_v4_reachable); > - sset_init(&lb_ip_set->ips_v6); > - sset_init(&lb_ip_set->ips_v6_routable); > - sset_init(&lb_ip_set->ips_v6_reachable); > - > - return lb_ip_set; > -} > - > -void > -ovn_lb_ip_set_destroy(struct ovn_lb_ip_set *lb_ip_set) > -{ > - if (!lb_ip_set) { > - return; > - } > - sset_destroy(&lb_ip_set->ips_v4); > - sset_destroy(&lb_ip_set->ips_v4_routable); > - sset_destroy(&lb_ip_set->ips_v4_reachable); > - sset_destroy(&lb_ip_set->ips_v6); > - sset_destroy(&lb_ip_set->ips_v6_routable); > - sset_destroy(&lb_ip_set->ips_v6_reachable); > - free(lb_ip_set); > -} > - > -struct ovn_lb_ip_set * > -ovn_lb_ip_set_clone(struct ovn_lb_ip_set *lb_ip_set) > -{ > - struct ovn_lb_ip_set *clone = ovn_lb_ip_set_create(); > - > - sset_clone(&clone->ips_v4, &lb_ip_set->ips_v4); > - sset_clone(&clone->ips_v4_routable, &lb_ip_set->ips_v4_routable); > - sset_clone(&clone->ips_v4_reachable, &lb_ip_set->ips_v4_reachable); > - sset_clone(&clone->ips_v6, &lb_ip_set->ips_v6); > - sset_clone(&clone->ips_v6_routable, &lb_ip_set->ips_v6_routable); > - sset_clone(&clone->ips_v6_reachable, &lb_ip_set->ips_v6_reachable); > - > - return clone; > -} > - > /* Format for backend ips: "IP1:port1,IP2:port2,...". */ > static char * > ovn_lb_backends_init_explicit(struct ovn_lb_vip *lb_vip, const char *value) > @@ -160,9 +100,9 @@ ovn_lb_backends_init_explicit(struct ovn_lb_vip *lb_vip, > const char *value) > return NULL; > } > > -static > -char *ovn_lb_vip_init_explicit(struct ovn_lb_vip *lb_vip, const char *lb_key, > - const char *lb_value) > +char * > +ovn_lb_vip_init_explicit(struct ovn_lb_vip *lb_vip, const char *lb_key, > + const char *lb_value) > { > if (!ip_address_and_port_from_lb_key(lb_key, &lb_vip->vip_str, > &lb_vip->vip, &lb_vip->vip_port, > @@ -369,22 +309,6 @@ ovn_lb_vip_format__(const struct ovn_lb_vip *vip, struct > ds *s, > } > } > > -/* Formats the VIP in the way the ovn-controller expects it, that is, > - * template IPv6 variables need to be between brackets too. > - */ > -static char * > -ovn_lb_vip6_template_format_internal(const struct ovn_lb_vip *vip) > -{ > - struct ds s = DS_EMPTY_INITIALIZER; > - > - if (vip->vip_str && *vip->vip_str == LEX_TEMPLATE_PREFIX) { > - ovn_lb_vip_format__(vip, &s, true); > - } else { > - ovn_lb_vip_format(vip, &s, !!vip->port_str); > - } > - return ds_steal_cstr(&s); > -} > - > void > ovn_lb_vip_format(const struct ovn_lb_vip *vip, struct ds *s, bool template) > { > @@ -417,540 +341,20 @@ ovn_lb_vip_backends_format(const struct ovn_lb_vip > *vip, struct ds *s) > } > } > > -static > -void ovn_northd_lb_vip_init(struct ovn_northd_lb_vip *lb_vip_nb, > - const struct ovn_lb_vip *lb_vip, > - const struct nbrec_load_balancer *nbrec_lb, > - const char *vip_port_str, const char > *backend_ips, > - bool template) > -{ > - lb_vip_nb->backend_ips = xstrdup(backend_ips); > - lb_vip_nb->n_backends = lb_vip->n_backends; > - lb_vip_nb->backends_nb = xcalloc(lb_vip_nb->n_backends, > - sizeof *lb_vip_nb->backends_nb); > - lb_vip_nb->lb_health_check = > - ovn_lb_get_health_check(nbrec_lb, vip_port_str, template); > -} > - > -static void > -ovn_lb_vip_backends_health_check_init(const struct ovn_northd_lb *lb, > - const struct ovn_lb_vip *lb_vip, > - struct ovn_northd_lb_vip *lb_vip_nb) > -{ > - struct ds key = DS_EMPTY_INITIALIZER; > - > - for (size_t j = 0; j < lb_vip->n_backends; j++) { > - struct ovn_lb_backend *backend = &lb_vip->backends[j]; > - ds_clear(&key); > - ds_put_format(&key, IN6_IS_ADDR_V4MAPPED(&lb_vip->vip) > - ? "%s" : "[%s]", backend->ip_str); > - > - const char *s = smap_get(&lb->nlb->ip_port_mappings, ds_cstr(&key)); > - if (!s) { > - continue; > - } > - > - char *svc_mon_src_ip = NULL; > - char *port_name = xstrdup(s); > - char *p = strstr(port_name, ":"); > - if (p) { > - *p = 0; > - p++; > - struct sockaddr_storage svc_mon_src_addr; > - if (!inet_parse_address(p, &svc_mon_src_addr)) { > - static struct vlog_rate_limit rl = > - VLOG_RATE_LIMIT_INIT(5, 1); > - VLOG_WARN_RL(&rl, "Invalid svc mon src IP %s", p); > - } else { > - struct ds src_ip_s = DS_EMPTY_INITIALIZER; > - ss_format_address_nobracks(&svc_mon_src_addr, > - &src_ip_s); > - svc_mon_src_ip = ds_steal_cstr(&src_ip_s); > - } > - } > - > - if (svc_mon_src_ip) { > - struct ovn_northd_lb_backend *backend_nb = > - &lb_vip_nb->backends_nb[j]; > - backend_nb->health_check = true; > - backend_nb->logical_port = xstrdup(port_name); > - backend_nb->svc_mon_src_ip = svc_mon_src_ip; > - } > - free(port_name); > - } > - > - ds_destroy(&key); > -} > - > -static > -void ovn_northd_lb_vip_destroy(struct ovn_northd_lb_vip *vip) > -{ > - free(vip->backend_ips); > - for (size_t i = 0; i < vip->n_backends; i++) { > - free(vip->backends_nb[i].logical_port); > - free(vip->backends_nb[i].svc_mon_src_ip); > - } > - free(vip->backends_nb); > -} > - > -static void > -ovn_lb_get_hairpin_snat_ip(const struct uuid *lb_uuid, > - const struct smap *lb_options, > - struct lport_addresses *hairpin_addrs) > -{ > - const char *addresses = smap_get(lb_options, "hairpin_snat_ip"); > - > - if (!addresses) { > - return; > - } > - > - if (!extract_ip_address(addresses, hairpin_addrs)) { > - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); > - VLOG_WARN_RL(&rl, "bad hairpin_snat_ip %s in load balancer "UUID_FMT, > - addresses, UUID_ARGS(lb_uuid)); > - } > -} > - > -static bool > -ovn_lb_get_routable_mode(const struct nbrec_load_balancer *nbrec_lb, > - bool routable, bool template) > -{ > - if (template && routable) { > - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); > - VLOG_WARN_RL(&rl, "Template load balancer "UUID_FMT" does not suport > " > - "option 'add_route'. Forcing it to disabled.", > - UUID_ARGS(&nbrec_lb->header_.uuid)); > - return false; > - } > - return routable; > -} > - > -static bool > -ovn_lb_neigh_mode_is_valid(enum lb_neighbor_responder_mode mode, bool > template) > -{ > - if (!template) { > - return true; > - } > - > - switch (mode) { > - case LB_NEIGH_RESPOND_REACHABLE: > - return false; > - case LB_NEIGH_RESPOND_ALL: > - case LB_NEIGH_RESPOND_NONE: > - return true; > - } > - return false; > -} > - > -static enum lb_neighbor_responder_mode > -ovn_lb_get_neigh_mode(const struct nbrec_load_balancer *nbrec_lb, > - const char *mode, bool template) > -{ > - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); > - enum lb_neighbor_responder_mode default_mode = > - template ? LB_NEIGH_RESPOND_NONE : LB_NEIGH_RESPOND_REACHABLE; > - > - if (!mode) { > - mode = lb_neighbor_responder_mode_names[default_mode]; > - } > - > - for (size_t i = 0; i < ARRAY_SIZE(lb_neighbor_responder_mode_names); > i++) { > - if (!strcmp(mode, lb_neighbor_responder_mode_names[i])) { > - if (ovn_lb_neigh_mode_is_valid(i, template)) { > - return i; > - } > - break; > - } > - } > - > - VLOG_WARN_RL(&rl, "Invalid neighbor responder mode %s for load balancer " > - UUID_FMT", forcing it to %s", > - mode, UUID_ARGS(&nbrec_lb->header_.uuid), > - lb_neighbor_responder_mode_names[default_mode]); > - return default_mode; > -} > - > -static struct nbrec_load_balancer_health_check * > -ovn_lb_get_health_check(const struct nbrec_load_balancer *nbrec_lb, > - const char *vip_port_str, bool template) > -{ > - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); > - > - if (!nbrec_lb->n_health_check) { > - return NULL; > - } > - > - if (nbrec_lb->protocol && !strcmp(nbrec_lb->protocol, "sctp")) { > - VLOG_WARN_RL(&rl, > - "SCTP load balancers do not currently support " > - "health checks. Not creating health checks for " > - "load balancer " UUID_FMT, > - UUID_ARGS(&nbrec_lb->header_.uuid)); > - return NULL; > - } > - > - if (template) { > - VLOG_WARN_RL(&rl, > - "Template load balancers do not currently support " > - "health checks. Not creating health checks for " > - "load balancer " UUID_FMT, > - UUID_ARGS(&nbrec_lb->header_.uuid)); > - return NULL; > - } > - > - for (size_t i = 0; i < nbrec_lb->n_health_check; i++) { > - if (!strcmp(nbrec_lb->health_check[i]->vip, vip_port_str)) { > - return nbrec_lb->health_check[i]; > - } > - } > - return NULL; > -} > - > -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"); > - int address_family = !strcmp(smap_get_def(&nbrec_lb->options, > - "address-family", "ipv4"), > - "ipv4") > - ? AF_INET > - : AF_INET6; > - > - lb->nlb = nbrec_lb; > - lb->proto = is_udp ? "udp" : is_sctp ? "sctp" : "tcp"; > - lb->n_vips = smap_count(&nbrec_lb->vips); > - lb->vips = xcalloc(lb->n_vips, sizeof *lb->vips); > - lb->vips_nb = xcalloc(lb->n_vips, sizeof *lb->vips_nb); > - smap_init(&lb->template_vips); > - lb->controller_event = smap_get_bool(&nbrec_lb->options, "event", false); > - > - bool routable = smap_get_bool(&nbrec_lb->options, "add_route", false); > - lb->routable = ovn_lb_get_routable_mode(nbrec_lb, routable, template); > - > - lb->skip_snat = smap_get_bool(&nbrec_lb->options, "skip_snat", false); > - lb->template = template; > - > - const char *mode = smap_get(&nbrec_lb->options, "neighbor_responder"); > - lb->neigh_mode = ovn_lb_get_neigh_mode(nbrec_lb, mode, template); > - > - uint32_t affinity_timeout = > - smap_get_uint(&nbrec_lb->options, "affinity_timeout", 0); > - if (affinity_timeout > UINT16_MAX) { > - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); > - VLOG_WARN_RL(&rl, "max affinity_timeout timeout value is %u", > - UINT16_MAX); > - affinity_timeout = UINT16_MAX; > - } > - lb->affinity_timeout = affinity_timeout; > - > - sset_init(&lb->ips_v4); > - sset_init(&lb->ips_v6); > - struct smap_node *node; > - size_t n_vips = 0; > - > - SMAP_FOR_EACH (node, &nbrec_lb->vips) { > - struct ovn_lb_vip *lb_vip = &lb->vips[n_vips]; > - struct ovn_northd_lb_vip *lb_vip_nb = &lb->vips_nb[n_vips]; > - > - char *error = ovn_lb_vip_init(lb_vip, node->key, node->value, > - template, address_family); > - if (error) { > - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); > - VLOG_WARN_RL(&rl, "Failed to initialize LB VIP: %s", error); > - ovn_lb_vip_destroy(lb_vip); > - free(error); > - continue; > - } > - lb_vip->empty_backend_rej = smap_get_bool(&nbrec_lb->options, > - "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 { > - sset_add(&lb->ips_v6, lb_vip->vip_str); > - } > - > - if (lb->template && address_family == AF_INET6) { > - smap_add_nocopy(&lb->template_vips, > - ovn_lb_vip6_template_format_internal(lb_vip), > - xstrdup(node->value)); > - } > - n_vips++; > - > - if (lb_vip_nb->lb_health_check) { > - ovn_lb_vip_backends_health_check_init(lb, lb_vip, lb_vip_nb); > - } > - } > - > - /* It's possible that parsing VIPs fails. Update the lb->n_vips to the > - * correct value. > - */ > - lb->n_vips = n_vips; > - > - if (nbrec_lb->n_selection_fields) { > - char *proto = NULL; > - if (nbrec_lb->protocol && nbrec_lb->protocol[0]) { > - proto = nbrec_lb->protocol; > - } > - > - struct ds sel_fields = DS_EMPTY_INITIALIZER; > - for (size_t i = 0; i < lb->nlb->n_selection_fields; i++) { > - char *field = lb->nlb->selection_fields[i]; > - if (!strcmp(field, "tp_src") && proto) { > - ds_put_format(&sel_fields, "%s_src,", proto); > - } else if (!strcmp(field, "tp_dst") && proto) { > - ds_put_format(&sel_fields, "%s_dst,", proto); > - } else { > - ds_put_format(&sel_fields, "%s,", field); > - } > - } > - 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; > -} > - > -struct ovn_northd_lb * > -ovn_northd_lb_find(const struct hmap *lbs, const struct uuid *uuid) > -{ > - struct ovn_northd_lb *lb; > - size_t hash = uuid_hash(uuid); > - HMAP_FOR_EACH_WITH_HASH (lb, hmap_node, hash, lbs) { > - if (uuid_equals(&lb->nlb->header_.uuid, uuid)) { > - return lb; > - } > - } > - return NULL; > -} > - > -const struct smap * > -ovn_northd_lb_get_vips(const struct ovn_northd_lb *lb) > -{ > - if (!smap_is_empty(&lb->template_vips)) { > - return &lb->template_vips; > - } > - return &lb->nlb->vips; > -} > - > -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]); > - ovn_northd_lb_vip_destroy(&lb->vips_nb[i]); > - } > - 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); > -} > - > -void > -ovn_northd_lb_reinit(struct ovn_northd_lb *lb, > - const struct nbrec_load_balancer *nbrec_lb) > -{ > - ovn_northd_lb_cleanup(lb); > - ovn_northd_lb_init(lb, nbrec_lb); > -} > - > -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(); > - > - for (size_t i = 0; i < nbrec_lb_group->n_load_balancer; i++) { > - const struct uuid *lb_uuid = > - &nbrec_lb_group->load_balancer[i]->header_.uuid; > - lb_group->lbs[i] = ovn_northd_lb_find(lbs, lb_uuid); > - lb_group->has_routable_lb |= lb_group->lbs[i]->routable; > - } > -} > - > -/* 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); > - lb_group->lb_ips = NULL; > - lb_group->has_routable_lb = false; > - free(lb_group->lbs); > -} > - > -void > -ovn_lb_group_destroy(struct ovn_lb_group *lb_group) > -{ > - if (!lb_group) { > - return; > - } > - > - 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) > -{ > - struct ovn_lb_group *lb_group; > - size_t hash = uuid_hash(uuid); > - > - HMAP_FOR_EACH_WITH_HASH (lb_group, hmap_node, hash, lb_groups) { > - if (uuid_equals(&lb_group->uuid, uuid)) { > - return lb_group; > - } > - } > - return NULL; > -} > - > -struct ovn_controller_lb * > -ovn_controller_lb_create(const struct sbrec_load_balancer *sbrec_lb, > - const struct smap *template_vars, > - struct sset *template_vars_ref) > -{ > - struct ovn_controller_lb *lb = xzalloc(sizeof *lb); > - bool template = smap_get_bool(&sbrec_lb->options, "template", false); > - > - lb->slb = sbrec_lb; > - lb->n_vips = smap_count(&sbrec_lb->vips); > - lb->vips = xcalloc(lb->n_vips, sizeof *lb->vips); > - > - struct smap_node *node; > - size_t n_vips = 0; > - > - SMAP_FOR_EACH (node, &sbrec_lb->vips) { > - struct ovn_lb_vip *lb_vip = &lb->vips[n_vips]; > - > - struct lex_str key_s = template > - ? lexer_parse_template_string(node->key, > - template_vars, > - > template_vars_ref) > - : lex_str_use(node->key); > - struct lex_str value_s = template > - ? lexer_parse_template_string(node->value, > - template_vars, > - > template_vars_ref) > - : lex_str_use(node->value); > - char *error = ovn_lb_vip_init_explicit(lb_vip, > - lex_str_get(&key_s), > - lex_str_get(&value_s)); > - if (error) { > - free(error); > - } else { > - n_vips++; > - } > - lex_str_free(&key_s); > - 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. > - */ > - lb->n_vips = n_vips; > - > - lb->hairpin_orig_tuple = smap_get_bool(&sbrec_lb->options, > - "hairpin_orig_tuple", > - false); > - lb->ct_flush = smap_get_bool(&sbrec_lb->options, "ct_flush", false); > - ovn_lb_get_hairpin_snat_ip(&sbrec_lb->header_.uuid, &sbrec_lb->options, > - &lb->hairpin_snat_ips); > - return lb; > -} > - > -void > -ovn_controller_lb_destroy(struct ovn_controller_lb *lb) > -{ > - for (size_t i = 0; i < lb->n_vips; i++) { > - ovn_lb_vip_destroy(&lb->vips[i]); > - } > - free(lb->vips); > - destroy_lport_addresses(&lb->hairpin_snat_ips); > - free(lb); > -} > - > -void > -ovn_controller_lbs_destroy(struct hmap *ovn_controller_lbs) > +/* Formats the VIP in the way the ovn-controller expects it, that is, > + * template IPv6 variables need to be between brackets too. > + */ > +char * > +ovn_lb_vip6_template_format_internal(const struct ovn_lb_vip *vip) > { > - 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 ds s = DS_EMPTY_INITIALIZER; > > -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; > - } > + if (vip->vip_str && *vip->vip_str == LEX_TEMPLATE_PREFIX) { > + ovn_lb_vip_format__(vip, &s, true); > + } else { > + ovn_lb_vip_format(vip, &s, !!vip->port_str); > } > - return NULL; > + return ds_steal_cstr(&s); > } > > static uint32_t > @@ -1020,150 +424,3 @@ ovn_lb_5tuples_destroy(struct hmap *tuples) > > hmap_destroy(tuples); > } > - > -void > -build_lrouter_lb_ips(struct ovn_lb_ip_set *lb_ips, > - const struct ovn_northd_lb *lb) > -{ > - add_ips_to_lb_ip_set(lb_ips, lb->routable, &lb->ips_v4, &lb->ips_v6); > -} > - > -void > -add_ips_to_lb_ip_set(struct ovn_lb_ip_set *lb_ips, > - bool is_routable, > - const struct sset *lb_ips_v4, > - const struct sset *lb_ips_v6) > -{ > - const char *ip_address; > - > - SSET_FOR_EACH (ip_address, lb_ips_v4) { > - sset_add(&lb_ips->ips_v4, ip_address); > - if (is_routable) { > - sset_add(&lb_ips->ips_v4_routable, ip_address); > - } > - } > - SSET_FOR_EACH (ip_address, lb_ips_v6) { > - sset_add(&lb_ips->ips_v6, ip_address); > - if (is_routable) { > - sset_add(&lb_ips->ips_v6_routable, ip_address); > - } > - } > -} > - > -void > -remove_ips_from_lb_ip_set(struct ovn_lb_ip_set *lb_ips, > - bool is_routable, > - const struct sset *lb_ips_v4, > - const struct sset *lb_ips_v6) > -{ > - const char *ip_address; > - > - SSET_FOR_EACH (ip_address, lb_ips_v4) { > - sset_find_and_delete(&lb_ips->ips_v4, ip_address); > - if (is_routable) { > - sset_find_and_delete(&lb_ips->ips_v4_routable, ip_address); > - } > - } > - SSET_FOR_EACH (ip_address, lb_ips_v6) { > - sset_find_and_delete(&lb_ips->ips_v6, ip_address); > - if (is_routable) { > - sset_find_and_delete(&lb_ips->ips_v6_routable, ip_address); > - } > - } > -} > - > -/* lb datapaths functions */ > -struct ovn_lb_datapaths * > -ovn_lb_datapaths_create(const struct ovn_northd_lb *lb, size_t > n_ls_datapaths, > - size_t n_lr_datapaths) > -{ > - struct ovn_lb_datapaths *lb_dps = xzalloc(sizeof *lb_dps); > - lb_dps->lb = lb; > - lb_dps->nb_ls_map = bitmap_allocate(n_ls_datapaths); > - lb_dps->nb_lr_map = bitmap_allocate(n_lr_datapaths); > - > - return lb_dps; > -} > - > -struct ovn_lb_datapaths * > -ovn_lb_datapaths_find(const struct hmap *lb_dps_map, > - const struct uuid *lb_uuid) > -{ > - struct ovn_lb_datapaths *lb_dps; > - size_t hash = uuid_hash(lb_uuid); > - HMAP_FOR_EACH_WITH_HASH (lb_dps, hmap_node, hash, lb_dps_map) { > - if (uuid_equals(&lb_dps->lb->nlb->header_.uuid, lb_uuid)) { > - return lb_dps; > - } > - } > - return NULL; > -} > - > -void > -ovn_lb_datapaths_destroy(struct ovn_lb_datapaths *lb_dps) > -{ > - bitmap_free(lb_dps->nb_lr_map); > - bitmap_free(lb_dps->nb_ls_map); > - free(lb_dps); > -} > - > -void > -ovn_lb_datapaths_add_lr(struct ovn_lb_datapaths *lb_dps, size_t n, > - struct ovn_datapath **ods) > -{ > - for (size_t i = 0; i < n; i++) { > - if (!bitmap_is_set(lb_dps->nb_lr_map, ods[i]->index)) { > - bitmap_set1(lb_dps->nb_lr_map, ods[i]->index); > - lb_dps->n_nb_lr++; > - } > - } > -} > - > -void > -ovn_lb_datapaths_add_ls(struct ovn_lb_datapaths *lb_dps, size_t n, > - struct ovn_datapath **ods) > -{ > - for (size_t i = 0; i < n; i++) { > - if (!bitmap_is_set(lb_dps->nb_ls_map, ods[i]->index)) { > - bitmap_set1(lb_dps->nb_ls_map, ods[i]->index); > - lb_dps->n_nb_ls++; > - } > - } > -} > - > -struct ovn_lb_group_datapaths * > -ovn_lb_group_datapaths_create(const struct ovn_lb_group *lb_group, > - size_t max_ls_datapaths, > - size_t max_lr_datapaths) > -{ > - struct ovn_lb_group_datapaths *lb_group_dps = > - xzalloc(sizeof *lb_group_dps); > - lb_group_dps->lb_group = lb_group; > - lb_group_dps->ls = xmalloc(max_ls_datapaths * sizeof *lb_group_dps->ls); > - lb_group_dps->lr = xmalloc(max_lr_datapaths * sizeof *lb_group_dps->lr); > - > - return lb_group_dps; > -} > - > -void > -ovn_lb_group_datapaths_destroy(struct ovn_lb_group_datapaths *lb_group_dps) > -{ > - free(lb_group_dps->ls); > - free(lb_group_dps->lr); > - free(lb_group_dps); > -} > - > -struct ovn_lb_group_datapaths * > -ovn_lb_group_datapaths_find(const struct hmap *lb_group_dps_map, > - const struct uuid *lb_group_uuid) > -{ > - struct ovn_lb_group_datapaths *lb_group_dps; > - size_t hash = uuid_hash(lb_group_uuid); > - > - HMAP_FOR_EACH_WITH_HASH (lb_group_dps, hmap_node, hash, > lb_group_dps_map) { > - if (uuid_equals(&lb_group_dps->lb_group->uuid, lb_group_uuid)) { > - return lb_group_dps; > - } > - } > - return NULL; > -} > diff --git a/lib/lb.h b/lib/lb.h > index b8e3c1e8fb..bcc677f82e 100644 > --- a/lib/lb.h > +++ b/lib/lb.h > @@ -25,63 +25,8 @@ > #include "sset.h" > #include "uuid.h" > > -struct nbrec_load_balancer; > -struct nbrec_load_balancer_group; > -struct sbrec_load_balancer; > -struct sbrec_datapath_binding; > -struct ovn_datapath; > -struct ovn_dp_group; > -struct ovn_port; > struct uuid; > > -enum lb_neighbor_responder_mode { > - LB_NEIGH_RESPOND_REACHABLE, > - LB_NEIGH_RESPOND_ALL, > - LB_NEIGH_RESPOND_NONE, > -}; > - > -/* The "routable" ssets are subsets of the load balancer IPs for which IP > - * routes and ARP resolution flows are automatically added. */ > -struct ovn_lb_ip_set { > - struct sset ips_v4; > - struct sset ips_v4_routable; > - struct sset ips_v4_reachable; > - struct sset ips_v6; > - struct sset ips_v6_routable; > - struct sset ips_v6_reachable; > -}; > - > -struct ovn_lb_ip_set *ovn_lb_ip_set_create(void); > -void ovn_lb_ip_set_destroy(struct ovn_lb_ip_set *); > -struct ovn_lb_ip_set *ovn_lb_ip_set_clone(struct ovn_lb_ip_set *); > - > -struct ovn_northd_lb { > - struct hmap_node hmap_node; > - > - const struct nbrec_load_balancer *nlb; /* May be NULL. */ > - const char *proto; > - char *selection_fields; > - struct ovn_lb_vip *vips; > - struct ovn_northd_lb_vip *vips_nb; > - struct smap template_vips; /* Slightly changed template VIPs, populated > - * if needed. Until now it's only required > - * for IPv6 template load balancers. */ > - size_t n_vips; > - > - enum lb_neighbor_responder_mode neigh_mode; > - bool controller_event; > - bool routable; > - bool skip_snat; > - bool template; > - uint16_t affinity_timeout; > - > - struct sset ips_v4; > - struct sset ips_v6; > - > - /* Indicates if the load balancer has health checks configured. */ > - bool health_checks; > -}; > - > struct ovn_lb_vip { > struct in6_addr vip; /* Only used in ovn-controller. */ > char *vip_str; /* Actual VIP string representation (without port). > @@ -113,153 +58,15 @@ struct ovn_lb_backend { > */ > }; > > -/* ovn-northd specific backend information. */ > -struct ovn_northd_lb_vip { > - char *backend_ips; > - struct ovn_northd_lb_backend *backends_nb; > - size_t n_backends; > - > - struct nbrec_load_balancer_health_check *lb_health_check; > -}; > - > -struct ovn_northd_lb_backend { > - bool health_check; > - char *logical_port; /* Logical port to which the ip belong to. */ > - char *svc_mon_src_ip; /* Source IP to use for monitoring. */ > -}; > - > -struct ovn_northd_lb *ovn_northd_lb_create(const struct nbrec_load_balancer > *); > -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 *); > -void add_ips_to_lb_ip_set(struct ovn_lb_ip_set *lb_ips, > - bool is_routable, > - const struct sset *lb_ips_v4, > - const struct sset *lb_ips_v6); > -void remove_ips_from_lb_ip_set(struct ovn_lb_ip_set *lb_ips, > - bool is_routable, > - const struct sset *lb_ips_v4, > - const struct sset *lb_ips_v6); > - > -struct ovn_lb_group { > - struct hmap_node hmap_node; > - struct uuid uuid; > - size_t n_lbs; > - struct ovn_northd_lb **lbs; > - struct ovn_lb_ip_set *lb_ips; > - bool has_routable_lb; > -}; > - > -struct ovn_lb_group *ovn_lb_group_create( > - const struct nbrec_load_balancer_group *, > - const struct hmap *lbs); > -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; > - > - const struct ovn_northd_lb *lb; > - size_t n_nb_ls; > - unsigned long *nb_ls_map; > - > - size_t n_nb_lr; > - unsigned long *nb_lr_map; > -}; > - > -struct ovn_lb_datapaths *ovn_lb_datapaths_create(const struct ovn_northd_lb > *, > - size_t n_ls_datapaths, > - size_t n_lr_datapaths); > -struct ovn_lb_datapaths *ovn_lb_datapaths_find(const struct hmap *, > - const struct uuid *); > -void ovn_lb_datapaths_destroy(struct ovn_lb_datapaths *); > -void ovn_lb_datapaths_add_lr(struct ovn_lb_datapaths *, size_t n, > - struct ovn_datapath **); > -void ovn_lb_datapaths_add_ls(struct ovn_lb_datapaths *, size_t n, > - struct ovn_datapath **); > - > -struct ovn_lb_group_datapaths { > - struct hmap_node hmap_node; > - > - const struct ovn_lb_group *lb_group; > - > - /* Datapaths to which 'lb_group' is applied. */ > - size_t n_ls; > - struct ovn_datapath **ls; > - size_t n_lr; > - struct ovn_datapath **lr; > -}; > - > -struct ovn_lb_group_datapaths *ovn_lb_group_datapaths_create( > - const struct ovn_lb_group *, size_t max_ls_datapaths, > - size_t max_lr_datapaths); > - > -void ovn_lb_group_datapaths_destroy(struct ovn_lb_group_datapaths *); > -struct ovn_lb_group_datapaths *ovn_lb_group_datapaths_find( > - const struct hmap *lb_group_dps, const struct uuid *); > - > -static inline void > -ovn_lb_group_datapaths_add_ls(struct ovn_lb_group_datapaths *lbg_dps, size_t > n, > - struct ovn_datapath **ods) > -{ > - memcpy(&lbg_dps->ls[lbg_dps->n_ls], ods, n * sizeof *ods); > - lbg_dps->n_ls += n; > -} > - > -static inline void > -ovn_lb_group_datapaths_add_lr(struct ovn_lb_group_datapaths *lbg_dps, > - struct ovn_datapath *lr) > -{ > - lbg_dps->lr[lbg_dps->n_lr++] = 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 > - * destination tuple in registers. > - */ > - bool ct_flush; /* True if we should flush CT after backend removal. */ > - > - struct lport_addresses hairpin_snat_ips; /* IP (v4 and/or v6) to be used > - * as source for hairpinned > - * traffic. > - */ > -}; > - > -struct ovn_controller_lb *ovn_controller_lb_create( > - const struct sbrec_load_balancer *, > - 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); > +char *ovn_lb_vip_init_explicit(struct ovn_lb_vip *lb_vip, const char *lb_key, > + const char *lb_value); > void ovn_lb_vip_destroy(struct ovn_lb_vip *vip); > void ovn_lb_vip_format(const struct ovn_lb_vip *vip, struct ds *s, > bool template); > void ovn_lb_vip_backends_format(const struct ovn_lb_vip *vip, struct ds *s); > +char *ovn_lb_vip6_template_format_internal(const struct ovn_lb_vip *vip); > > struct ovn_lb_5tuple { > struct hmap_node hmap_node; > diff --git a/northd/automake.mk b/northd/automake.mk > index 7c6d56a4ff..19abb0dece 100644 > --- a/northd/automake.mk > +++ b/northd/automake.mk > @@ -35,7 +35,9 @@ northd_ovn_northd_SOURCES = \ > northd/ipam.c \ > northd/ipam.h \ > northd/lflow-mgr.c \ > - northd/lflow-mgr.h > + northd/lflow-mgr.h \ > + northd/lb.c \ > + northd/lb.h > northd_ovn_northd_LDADD = \ > lib/libovn.la \ > $(OVSDB_LIBDIR)/libovsdb.la \ > diff --git a/northd/en-lb-data.c b/northd/en-lb-data.c > index d06f46a54b..6ad3fbb35f 100644 > --- a/northd/en-lb-data.c > +++ b/northd/en-lb-data.c > @@ -25,6 +25,7 @@ > > /* OVN includes */ > #include "en-lb-data.h" > +#include "lb.h" > #include "lib/inc-proc-eng.h" > #include "lib/lb.h" > #include "lib/ovn-nb-idl.h" > diff --git a/northd/en-lr-stateful.c b/northd/en-lr-stateful.c > index 8665b3c791..3e2a6c254e 100644 > --- a/northd/en-lr-stateful.c > +++ b/northd/en-lr-stateful.c > @@ -33,6 +33,7 @@ > #include "en-lb-data.h" > #include "en-lr-nat.h" > #include "en-lr-stateful.h" > +#include "lb.h" > #include "lib/inc-proc-eng.h" > #include "lib/lb.h" > #include "lib/ovn-nb-idl.h" > diff --git a/northd/en-sync-sb.c b/northd/en-sync-sb.c > index 53f687f220..9ca59d4338 100644 > --- a/northd/en-sync-sb.c > +++ b/northd/en-sync-sb.c > @@ -24,6 +24,7 @@ > #include "en-lr-nat.h" > #include "en-lr-stateful.h" > #include "en-sync-sb.h" > +#include "lb.h" > #include "lib/inc-proc-eng.h" > #include "lib/lb.h" > #include "lib/ovn-nb-idl.h" > diff --git a/northd/lb.c b/northd/lb.c > new file mode 100644 > index 0000000000..e35569cb70 > --- /dev/null > +++ b/northd/lb.c > @@ -0,0 +1,651 @@ > +/* > + * Copyright (c) 2024, 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> > + > +/* OVS includes */ > +#include "lib/bitmap.h" > +#include "openvswitch/vlog.h" > +#include "socket-util.h" > + > +/* OVN includes */ > +#include "lb.h" > +#include "lib/ovn-nb-idl.h" > +#include "northd.h" > +#include "ovn/lex.h" > + > +VLOG_DEFINE_THIS_MODULE(northd_lb); > + > +static const char *lb_neighbor_responder_mode_names[] = { > + [LB_NEIGH_RESPOND_REACHABLE] = "reachable", > + [LB_NEIGH_RESPOND_ALL] = "all", > + [LB_NEIGH_RESPOND_NONE] = "none", > +}; > + > +static struct nbrec_load_balancer_health_check * > +ovn_lb_get_health_check(const struct nbrec_load_balancer *nbrec_lb, > + const char *vip_port_str, bool template); > + > +struct ovn_lb_ip_set * > +ovn_lb_ip_set_create(void) > +{ > + struct ovn_lb_ip_set *lb_ip_set = xzalloc(sizeof *lb_ip_set); > + > + sset_init(&lb_ip_set->ips_v4); > + sset_init(&lb_ip_set->ips_v4_routable); > + sset_init(&lb_ip_set->ips_v4_reachable); > + sset_init(&lb_ip_set->ips_v6); > + sset_init(&lb_ip_set->ips_v6_routable); > + sset_init(&lb_ip_set->ips_v6_reachable); > + > + return lb_ip_set; > +} > + > +void > +ovn_lb_ip_set_destroy(struct ovn_lb_ip_set *lb_ip_set) > +{ > + if (!lb_ip_set) { > + return; > + } > + sset_destroy(&lb_ip_set->ips_v4); > + sset_destroy(&lb_ip_set->ips_v4_routable); > + sset_destroy(&lb_ip_set->ips_v4_reachable); > + sset_destroy(&lb_ip_set->ips_v6); > + sset_destroy(&lb_ip_set->ips_v6_routable); > + sset_destroy(&lb_ip_set->ips_v6_reachable); > + free(lb_ip_set); > +} > + > +struct ovn_lb_ip_set * > +ovn_lb_ip_set_clone(struct ovn_lb_ip_set *lb_ip_set) > +{ > + struct ovn_lb_ip_set *clone = ovn_lb_ip_set_create(); > + > + sset_clone(&clone->ips_v4, &lb_ip_set->ips_v4); > + sset_clone(&clone->ips_v4_routable, &lb_ip_set->ips_v4_routable); > + sset_clone(&clone->ips_v4_reachable, &lb_ip_set->ips_v4_reachable); > + sset_clone(&clone->ips_v6, &lb_ip_set->ips_v6); > + sset_clone(&clone->ips_v6_routable, &lb_ip_set->ips_v6_routable); > + sset_clone(&clone->ips_v6_reachable, &lb_ip_set->ips_v6_reachable); > + > + return clone; > +} > + > +static > +void ovn_northd_lb_vip_init(struct ovn_northd_lb_vip *lb_vip_nb, > + const struct ovn_lb_vip *lb_vip, > + const struct nbrec_load_balancer *nbrec_lb, > + const char *vip_port_str, const char > *backend_ips, > + bool template) > +{ > + lb_vip_nb->backend_ips = xstrdup(backend_ips); > + lb_vip_nb->n_backends = lb_vip->n_backends; > + lb_vip_nb->backends_nb = xcalloc(lb_vip_nb->n_backends, > + sizeof *lb_vip_nb->backends_nb); > + lb_vip_nb->lb_health_check = > + ovn_lb_get_health_check(nbrec_lb, vip_port_str, template); > +} > + > +static void > +ovn_lb_vip_backends_health_check_init(const struct ovn_northd_lb *lb, > + const struct ovn_lb_vip *lb_vip, > + struct ovn_northd_lb_vip *lb_vip_nb) > +{ > + struct ds key = DS_EMPTY_INITIALIZER; > + > + for (size_t j = 0; j < lb_vip->n_backends; j++) { > + struct ovn_lb_backend *backend = &lb_vip->backends[j]; > + ds_clear(&key); > + ds_put_format(&key, IN6_IS_ADDR_V4MAPPED(&lb_vip->vip) > + ? "%s" : "[%s]", backend->ip_str); > + > + const char *s = smap_get(&lb->nlb->ip_port_mappings, ds_cstr(&key)); > + if (!s) { > + continue; > + } > + > + char *svc_mon_src_ip = NULL; > + char *port_name = xstrdup(s); > + char *p = strstr(port_name, ":"); > + if (p) { > + *p = 0; > + p++; > + struct sockaddr_storage svc_mon_src_addr; > + if (!inet_parse_address(p, &svc_mon_src_addr)) { > + static struct vlog_rate_limit rl = > + VLOG_RATE_LIMIT_INIT(5, 1); > + VLOG_WARN_RL(&rl, "Invalid svc mon src IP %s", p); > + } else { > + struct ds src_ip_s = DS_EMPTY_INITIALIZER; > + ss_format_address_nobracks(&svc_mon_src_addr, > + &src_ip_s); > + svc_mon_src_ip = ds_steal_cstr(&src_ip_s); > + } > + } > + > + if (svc_mon_src_ip) { > + struct ovn_northd_lb_backend *backend_nb = > + &lb_vip_nb->backends_nb[j]; > + backend_nb->health_check = true; > + backend_nb->logical_port = xstrdup(port_name); > + backend_nb->svc_mon_src_ip = svc_mon_src_ip; > + } > + free(port_name); > + } > + > + ds_destroy(&key); > +} > + > +static > +void ovn_northd_lb_vip_destroy(struct ovn_northd_lb_vip *vip) > +{ > + free(vip->backend_ips); > + for (size_t i = 0; i < vip->n_backends; i++) { > + free(vip->backends_nb[i].logical_port); > + free(vip->backends_nb[i].svc_mon_src_ip); > + } > + free(vip->backends_nb); > +} > + > +static bool > +ovn_lb_get_routable_mode(const struct nbrec_load_balancer *nbrec_lb, > + bool routable, bool template) > +{ > + if (template && routable) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); > + VLOG_WARN_RL(&rl, "Template load balancer "UUID_FMT" does not suport > " > + "option 'add_route'. Forcing it to disabled.", > + UUID_ARGS(&nbrec_lb->header_.uuid)); > + return false; > + } > + return routable; > +} > + > +static bool > +ovn_lb_neigh_mode_is_valid(enum lb_neighbor_responder_mode mode, bool > template) > +{ > + if (!template) { > + return true; > + } > + > + switch (mode) { > + case LB_NEIGH_RESPOND_REACHABLE: > + return false; > + case LB_NEIGH_RESPOND_ALL: > + case LB_NEIGH_RESPOND_NONE: > + return true; > + } > + return false; > +} > + > +static enum lb_neighbor_responder_mode > +ovn_lb_get_neigh_mode(const struct nbrec_load_balancer *nbrec_lb, > + const char *mode, bool template) > +{ > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); > + enum lb_neighbor_responder_mode default_mode = > + template ? LB_NEIGH_RESPOND_NONE : LB_NEIGH_RESPOND_REACHABLE; > + > + if (!mode) { > + mode = lb_neighbor_responder_mode_names[default_mode]; > + } > + > + for (size_t i = 0; i < ARRAY_SIZE(lb_neighbor_responder_mode_names); > i++) { > + if (!strcmp(mode, lb_neighbor_responder_mode_names[i])) { > + if (ovn_lb_neigh_mode_is_valid(i, template)) { > + return i; > + } > + break; > + } > + } > + > + VLOG_WARN_RL(&rl, "Invalid neighbor responder mode %s for load balancer " > + UUID_FMT", forcing it to %s", > + mode, UUID_ARGS(&nbrec_lb->header_.uuid), > + lb_neighbor_responder_mode_names[default_mode]); > + return default_mode; > +} > + > +static struct nbrec_load_balancer_health_check * > +ovn_lb_get_health_check(const struct nbrec_load_balancer *nbrec_lb, > + const char *vip_port_str, bool template) > +{ > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); > + > + if (!nbrec_lb->n_health_check) { > + return NULL; > + } > + > + if (nbrec_lb->protocol && !strcmp(nbrec_lb->protocol, "sctp")) { > + VLOG_WARN_RL(&rl, > + "SCTP load balancers do not currently support " > + "health checks. Not creating health checks for " > + "load balancer " UUID_FMT, > + UUID_ARGS(&nbrec_lb->header_.uuid)); > + return NULL; > + } > + > + if (template) { > + VLOG_WARN_RL(&rl, > + "Template load balancers do not currently support " > + "health checks. Not creating health checks for " > + "load balancer " UUID_FMT, > + UUID_ARGS(&nbrec_lb->header_.uuid)); > + return NULL; > + } > + > + for (size_t i = 0; i < nbrec_lb->n_health_check; i++) { > + if (!strcmp(nbrec_lb->health_check[i]->vip, vip_port_str)) { > + return nbrec_lb->health_check[i]; > + } > + } > + return NULL; > +} > + > +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"); > + int address_family = !strcmp(smap_get_def(&nbrec_lb->options, > + "address-family", "ipv4"), > + "ipv4") > + ? AF_INET > + : AF_INET6; > + > + lb->nlb = nbrec_lb; > + lb->proto = is_udp ? "udp" : is_sctp ? "sctp" : "tcp"; > + lb->n_vips = smap_count(&nbrec_lb->vips); > + lb->vips = xcalloc(lb->n_vips, sizeof *lb->vips); > + lb->vips_nb = xcalloc(lb->n_vips, sizeof *lb->vips_nb); > + smap_init(&lb->template_vips); > + lb->controller_event = smap_get_bool(&nbrec_lb->options, "event", false); > + > + bool routable = smap_get_bool(&nbrec_lb->options, "add_route", false); > + lb->routable = ovn_lb_get_routable_mode(nbrec_lb, routable, template); > + > + lb->skip_snat = smap_get_bool(&nbrec_lb->options, "skip_snat", false); > + lb->template = template; > + > + const char *mode = smap_get(&nbrec_lb->options, "neighbor_responder"); > + lb->neigh_mode = ovn_lb_get_neigh_mode(nbrec_lb, mode, template); > + > + uint32_t affinity_timeout = > + smap_get_uint(&nbrec_lb->options, "affinity_timeout", 0); > + if (affinity_timeout > UINT16_MAX) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); > + VLOG_WARN_RL(&rl, "max affinity_timeout timeout value is %u", > + UINT16_MAX); > + affinity_timeout = UINT16_MAX; > + } > + lb->affinity_timeout = affinity_timeout; > + > + sset_init(&lb->ips_v4); > + sset_init(&lb->ips_v6); > + struct smap_node *node; > + size_t n_vips = 0; > + > + SMAP_FOR_EACH (node, &nbrec_lb->vips) { > + struct ovn_lb_vip *lb_vip = &lb->vips[n_vips]; > + struct ovn_northd_lb_vip *lb_vip_nb = &lb->vips_nb[n_vips]; > + > + char *error = ovn_lb_vip_init(lb_vip, node->key, node->value, > + template, address_family); > + if (error) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); > + VLOG_WARN_RL(&rl, "Failed to initialize LB VIP: %s", error); > + ovn_lb_vip_destroy(lb_vip); > + free(error); > + continue; > + } > + lb_vip->empty_backend_rej = smap_get_bool(&nbrec_lb->options, > + "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 { > + sset_add(&lb->ips_v6, lb_vip->vip_str); > + } > + > + if (lb->template && address_family == AF_INET6) { > + smap_add_nocopy(&lb->template_vips, > + ovn_lb_vip6_template_format_internal(lb_vip), > + xstrdup(node->value)); > + } > + n_vips++; > + > + if (lb_vip_nb->lb_health_check) { > + ovn_lb_vip_backends_health_check_init(lb, lb_vip, lb_vip_nb); > + } > + } > + > + /* It's possible that parsing VIPs fails. Update the lb->n_vips to the > + * correct value. > + */ > + lb->n_vips = n_vips; > + > + if (nbrec_lb->n_selection_fields) { > + char *proto = NULL; > + if (nbrec_lb->protocol && nbrec_lb->protocol[0]) { > + proto = nbrec_lb->protocol; > + } > + > + struct ds sel_fields = DS_EMPTY_INITIALIZER; > + for (size_t i = 0; i < lb->nlb->n_selection_fields; i++) { > + char *field = lb->nlb->selection_fields[i]; > + if (!strcmp(field, "tp_src") && proto) { > + ds_put_format(&sel_fields, "%s_src,", proto); > + } else if (!strcmp(field, "tp_dst") && proto) { > + ds_put_format(&sel_fields, "%s_dst,", proto); > + } else { > + ds_put_format(&sel_fields, "%s,", field); > + } > + } > + 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; > +} > + > +struct ovn_northd_lb * > +ovn_northd_lb_find(const struct hmap *lbs, const struct uuid *uuid) > +{ > + struct ovn_northd_lb *lb; > + size_t hash = uuid_hash(uuid); > + HMAP_FOR_EACH_WITH_HASH (lb, hmap_node, hash, lbs) { > + if (uuid_equals(&lb->nlb->header_.uuid, uuid)) { > + return lb; > + } > + } > + return NULL; > +} > + > +const struct smap * > +ovn_northd_lb_get_vips(const struct ovn_northd_lb *lb) > +{ > + if (!smap_is_empty(&lb->template_vips)) { > + return &lb->template_vips; > + } > + return &lb->nlb->vips; > +} > + > +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]); > + ovn_northd_lb_vip_destroy(&lb->vips_nb[i]); > + } > + 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); > +} > + > +void > +ovn_northd_lb_reinit(struct ovn_northd_lb *lb, > + const struct nbrec_load_balancer *nbrec_lb) > +{ > + ovn_northd_lb_cleanup(lb); > + ovn_northd_lb_init(lb, nbrec_lb); > +} > + > +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(); > + > + for (size_t i = 0; i < nbrec_lb_group->n_load_balancer; i++) { > + const struct uuid *lb_uuid = > + &nbrec_lb_group->load_balancer[i]->header_.uuid; > + lb_group->lbs[i] = ovn_northd_lb_find(lbs, lb_uuid); > + lb_group->has_routable_lb |= lb_group->lbs[i]->routable; > + } > +} > + > +/* 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); > + lb_group->lb_ips = NULL; > + lb_group->has_routable_lb = false; > + free(lb_group->lbs); > +} > + > +void > +ovn_lb_group_destroy(struct ovn_lb_group *lb_group) > +{ > + if (!lb_group) { > + return; > + } > + > + 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) > +{ > + struct ovn_lb_group *lb_group; > + size_t hash = uuid_hash(uuid); > + > + HMAP_FOR_EACH_WITH_HASH (lb_group, hmap_node, hash, lb_groups) { > + if (uuid_equals(&lb_group->uuid, uuid)) { > + return lb_group; > + } > + } > + return NULL; > +} > + > +void > +build_lrouter_lb_ips(struct ovn_lb_ip_set *lb_ips, > + const struct ovn_northd_lb *lb) > +{ > + add_ips_to_lb_ip_set(lb_ips, lb->routable, &lb->ips_v4, &lb->ips_v6); > +} > + > +void > +add_ips_to_lb_ip_set(struct ovn_lb_ip_set *lb_ips, > + bool is_routable, > + const struct sset *lb_ips_v4, > + const struct sset *lb_ips_v6) > +{ > + const char *ip_address; > + > + SSET_FOR_EACH (ip_address, lb_ips_v4) { > + sset_add(&lb_ips->ips_v4, ip_address); > + if (is_routable) { > + sset_add(&lb_ips->ips_v4_routable, ip_address); > + } > + } > + SSET_FOR_EACH (ip_address, lb_ips_v6) { > + sset_add(&lb_ips->ips_v6, ip_address); > + if (is_routable) { > + sset_add(&lb_ips->ips_v6_routable, ip_address); > + } > + } > +} > + > +void > +remove_ips_from_lb_ip_set(struct ovn_lb_ip_set *lb_ips, > + bool is_routable, > + const struct sset *lb_ips_v4, > + const struct sset *lb_ips_v6) > +{ > + const char *ip_address; > + > + SSET_FOR_EACH (ip_address, lb_ips_v4) { > + sset_find_and_delete(&lb_ips->ips_v4, ip_address); > + if (is_routable) { > + sset_find_and_delete(&lb_ips->ips_v4_routable, ip_address); > + } > + } > + SSET_FOR_EACH (ip_address, lb_ips_v6) { > + sset_find_and_delete(&lb_ips->ips_v6, ip_address); > + if (is_routable) { > + sset_find_and_delete(&lb_ips->ips_v6_routable, ip_address); > + } > + } > +} > + > +/* lb datapaths functions */ > +struct ovn_lb_datapaths * > +ovn_lb_datapaths_create(const struct ovn_northd_lb *lb, size_t > n_ls_datapaths, > + size_t n_lr_datapaths) > +{ > + struct ovn_lb_datapaths *lb_dps = xzalloc(sizeof *lb_dps); > + lb_dps->lb = lb; > + lb_dps->nb_ls_map = bitmap_allocate(n_ls_datapaths); > + lb_dps->nb_lr_map = bitmap_allocate(n_lr_datapaths); > + > + return lb_dps; > +} > + > +void > +ovn_lb_datapaths_destroy(struct ovn_lb_datapaths *lb_dps) > +{ > + bitmap_free(lb_dps->nb_lr_map); > + bitmap_free(lb_dps->nb_ls_map); > + free(lb_dps); > +} > + > +void > +ovn_lb_datapaths_add_lr(struct ovn_lb_datapaths *lb_dps, size_t n, > + struct ovn_datapath **ods) > +{ > + for (size_t i = 0; i < n; i++) { > + if (!bitmap_is_set(lb_dps->nb_lr_map, ods[i]->index)) { > + bitmap_set1(lb_dps->nb_lr_map, ods[i]->index); > + lb_dps->n_nb_lr++; > + } > + } > +} > + > +void > +ovn_lb_datapaths_add_ls(struct ovn_lb_datapaths *lb_dps, size_t n, > + struct ovn_datapath **ods) > +{ > + for (size_t i = 0; i < n; i++) { > + if (!bitmap_is_set(lb_dps->nb_ls_map, ods[i]->index)) { > + bitmap_set1(lb_dps->nb_ls_map, ods[i]->index); > + lb_dps->n_nb_ls++; > + } > + } > +} > + > +struct ovn_lb_datapaths * > +ovn_lb_datapaths_find(const struct hmap *lb_dps_map, > + const struct uuid *lb_uuid) > +{ > + struct ovn_lb_datapaths *lb_dps; > + size_t hash = uuid_hash(lb_uuid); > + HMAP_FOR_EACH_WITH_HASH (lb_dps, hmap_node, hash, lb_dps_map) { > + if (uuid_equals(&lb_dps->lb->nlb->header_.uuid, lb_uuid)) { > + return lb_dps; > + } > + } > + return NULL; > +} > + > +struct ovn_lb_group_datapaths * > +ovn_lb_group_datapaths_create(const struct ovn_lb_group *lb_group, > + size_t max_ls_datapaths, > + size_t max_lr_datapaths) > +{ > + struct ovn_lb_group_datapaths *lb_group_dps = > + xzalloc(sizeof *lb_group_dps); > + lb_group_dps->lb_group = lb_group; > + lb_group_dps->ls = xmalloc(max_ls_datapaths * sizeof *lb_group_dps->ls); > + lb_group_dps->lr = xmalloc(max_lr_datapaths * sizeof *lb_group_dps->lr); > + > + return lb_group_dps; > +} > + > +void > +ovn_lb_group_datapaths_destroy(struct ovn_lb_group_datapaths *lb_group_dps) > +{ > + free(lb_group_dps->ls); > + free(lb_group_dps->lr); > + free(lb_group_dps); > +} > + > +struct ovn_lb_group_datapaths * > +ovn_lb_group_datapaths_find(const struct hmap *lb_group_dps_map, > + const struct uuid *lb_group_uuid) > +{ > + struct ovn_lb_group_datapaths *lb_group_dps; > + size_t hash = uuid_hash(lb_group_uuid); > + > + HMAP_FOR_EACH_WITH_HASH (lb_group_dps, hmap_node, hash, > lb_group_dps_map) { > + if (uuid_equals(&lb_group_dps->lb_group->uuid, lb_group_uuid)) { > + return lb_group_dps; > + } > + } > + return NULL; > +} > diff --git a/northd/lb.h b/northd/lb.h > new file mode 100644 > index 0000000000..00f81c3533 > --- /dev/null > +++ b/northd/lb.h > @@ -0,0 +1,189 @@ > +/* > + * Copyright (c) 2024, 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_NORTHD_LB_H > +#define OVN_NORTHD_LB_H 1 > + > +#include "openvswitch/hmap.h" > +#include "uuid.h" > + > +#include "lib/lb.h" > + > +struct nbrec_load_balancer; > +struct nbrec_load_balancer_group; > +struct ovn_datapath; > + > +enum lb_neighbor_responder_mode { > + LB_NEIGH_RESPOND_REACHABLE, > + LB_NEIGH_RESPOND_ALL, > + LB_NEIGH_RESPOND_NONE, > +}; > + > +/* The "routable" ssets are subsets of the load balancer IPs for which IP > + * routes and ARP resolution flows are automatically added. */ > +struct ovn_lb_ip_set { > + struct sset ips_v4; > + struct sset ips_v4_routable; > + struct sset ips_v4_reachable; > + struct sset ips_v6; > + struct sset ips_v6_routable; > + struct sset ips_v6_reachable; > +}; > + > +struct ovn_lb_ip_set *ovn_lb_ip_set_create(void); > +void ovn_lb_ip_set_destroy(struct ovn_lb_ip_set *); > +struct ovn_lb_ip_set *ovn_lb_ip_set_clone(struct ovn_lb_ip_set *); > + > +struct ovn_northd_lb { > + struct hmap_node hmap_node; > + > + const struct nbrec_load_balancer *nlb; /* May be NULL. */ > + const char *proto; > + char *selection_fields; > + struct ovn_lb_vip *vips; > + struct ovn_northd_lb_vip *vips_nb; > + struct smap template_vips; /* Slightly changed template VIPs, populated > + * if needed. Until now it's only required > + * for IPv6 template load balancers. */ > + size_t n_vips; > + > + enum lb_neighbor_responder_mode neigh_mode; > + bool controller_event; > + bool routable; > + bool skip_snat; > + bool template; > + uint16_t affinity_timeout; > + > + struct sset ips_v4; > + struct sset ips_v6; > + > + /* Indicates if the load balancer has health checks configured. */ > + bool health_checks; > +}; > + > +/* ovn-northd specific backend information. */ > +struct ovn_northd_lb_vip { > + char *backend_ips; > + struct ovn_northd_lb_backend *backends_nb; > + size_t n_backends; > + > + struct nbrec_load_balancer_health_check *lb_health_check; > +}; > + > +struct ovn_northd_lb_backend { > + bool health_check; > + char *logical_port; /* Logical port to which the ip belong to. */ > + char *svc_mon_src_ip; /* Source IP to use for monitoring. */ > +}; > + > +struct ovn_northd_lb *ovn_northd_lb_create(const struct nbrec_load_balancer > *); > +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 *); > +void add_ips_to_lb_ip_set(struct ovn_lb_ip_set *lb_ips, > + bool is_routable, > + const struct sset *lb_ips_v4, > + const struct sset *lb_ips_v6); > +void remove_ips_from_lb_ip_set(struct ovn_lb_ip_set *lb_ips, > + bool is_routable, > + const struct sset *lb_ips_v4, > + const struct sset *lb_ips_v6); > + > +struct ovn_lb_group { > + struct hmap_node hmap_node; > + struct uuid uuid; > + size_t n_lbs; > + struct ovn_northd_lb **lbs; > + struct ovn_lb_ip_set *lb_ips; > + bool has_routable_lb; > +}; > + > +struct ovn_lb_group *ovn_lb_group_create( > + const struct nbrec_load_balancer_group *, > + const struct hmap *lbs); > +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; > + > + const struct ovn_northd_lb *lb; > + size_t n_nb_ls; > + unsigned long *nb_ls_map; > + > + size_t n_nb_lr; > + unsigned long *nb_lr_map; > +}; > + > +struct ovn_lb_datapaths *ovn_lb_datapaths_create(const struct ovn_northd_lb > *, > + size_t n_ls_datapaths, > + size_t n_lr_datapaths); > +struct ovn_lb_datapaths *ovn_lb_datapaths_find(const struct hmap *, > + const struct uuid *); > +void ovn_lb_datapaths_destroy(struct ovn_lb_datapaths *); > + > +void ovn_lb_datapaths_add_lr(struct ovn_lb_datapaths *, size_t n, > + struct ovn_datapath **); > +void ovn_lb_datapaths_add_ls(struct ovn_lb_datapaths *, size_t n, > + struct ovn_datapath **); > + > +struct ovn_lb_group_datapaths { > + struct hmap_node hmap_node; > + > + const struct ovn_lb_group *lb_group; > + > + /* Datapaths to which 'lb_group' is applied. */ > + size_t n_ls; > + struct ovn_datapath **ls; > + size_t n_lr; > + struct ovn_datapath **lr; > +}; > + > +struct ovn_lb_group_datapaths *ovn_lb_group_datapaths_create( > + const struct ovn_lb_group *, size_t max_ls_datapaths, > + size_t max_lr_datapaths); > + > +void ovn_lb_group_datapaths_destroy(struct ovn_lb_group_datapaths *); > +struct ovn_lb_group_datapaths *ovn_lb_group_datapaths_find( > + const struct hmap *lb_group_dps, const struct uuid *); > + > +static inline void > +ovn_lb_group_datapaths_add_ls(struct ovn_lb_group_datapaths *lbg_dps, size_t > n, > + struct ovn_datapath **ods) > +{ > + memcpy(&lbg_dps->ls[lbg_dps->n_ls], ods, n * sizeof *ods); > + lbg_dps->n_ls += n; > +} > + > +static inline void > +ovn_lb_group_datapaths_add_lr(struct ovn_lb_group_datapaths *lbg_dps, > + struct ovn_datapath *lr) > +{ > + lbg_dps->lr[lbg_dps->n_lr++] = lr; > +} > + > +#endif /* OVN_NORTHD_LB_H */ > diff --git a/northd/northd.c b/northd/northd.c > index cb53ec9716..00899e3d1a 100644 > --- a/northd/northd.c > +++ b/northd/northd.c > @@ -31,6 +31,7 @@ > #include "openvswitch/hmap.h" > #include "openvswitch/json.h" > #include "ovn/lex.h" > +#include "lb.h" > #include "lib/chassis-index.h" > #include "lib/ip-mcast-index.h" > #include "lib/static-mac-binding-index.h" > -- > 2.43.0 > > _______________________________________________ > dev mailing list > [email protected] > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
