From 58f78bf44b9df97a45d7dbe08c8f95770a295a68 Mon Sep 17 00:00:00 2001 From: Dumitru Ceara Date: Mon, 12 Oct 2020 17:52:38 +0530 Subject: [PATCH 05/10] northd: Refactor load balancer vip parsing. Parsing of the load balancer VIPs is moved to a separate file - lib/lb.c. ovn-northd makes use of these functions. Upcoming patch will make use of these util functions for parsing SB Load_Balancers. Co-authored-by: Numan Siddique Signed-off-by: Numan Siddique Signed-off-by: Dumitru Ceara Acked-by: Mark Michelson (cherry-picked from master commit f1119c1257652702e0ee88cf634f2ee19cc92c44) Conflicts: northd/ovn-northd.c --- lib/automake.mk | 4 +- lib/lb.c | 301 ++++++++++++++++++++++++++++++++ lib/lb.h | 97 +++++++++++ northd/ovn-northd.c | 416 +++++++++++++------------------------------- 4 files changed, 518 insertions(+), 300 deletions(-) create mode 100644 lib/lb.c create mode 100644 lib/lb.h diff --git a/lib/automake.mk b/lib/automake.mk index f3e9c8818..430cd11fc 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -23,7 +23,9 @@ lib_libovn_la_SOURCES = \ lib/ovn-util.h \ lib/logical-fields.c \ lib/inc-proc-eng.c \ - lib/inc-proc-eng.h + lib/inc-proc-eng.h \ + lib/lb.c \ + lib/lb.h nodist_lib_libovn_la_SOURCES = \ lib/ovn-dirs.c \ lib/ovn-nb-idl.c \ diff --git a/lib/lb.c b/lib/lb.c new file mode 100644 index 000000000..a90042e58 --- /dev/null +++ b/lib/lb.c @@ -0,0 +1,301 @@ +/* Copyright (c) 2020, 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 + +#include "lb.h" +#include "lib/ovn-nb-idl.h" +#include "lib/ovn-sb-idl.h" +#include "lib/ovn-util.h" + +/* OpenvSwitch lib includes. */ +#include "openvswitch/vlog.h" +#include "lib/smap.h" + +VLOG_DEFINE_THIS_MODULE(lb); + +static +bool ovn_lb_vip_init(struct ovn_lb_vip *lb_vip, const char *lb_key, + const char *lb_value) +{ + int addr_family; + + if (!ip_address_and_port_from_lb_key(lb_key, &lb_vip->vip_str, + &lb_vip->vip_port, &addr_family)) { + return false; + } + + if (addr_family == AF_INET) { + ovs_be32 vip4; + ip_parse(lb_vip->vip_str, &vip4); + in6_addr_set_mapped_ipv4(&lb_vip->vip, vip4); + } else { + ipv6_parse(lb_vip->vip_str, &lb_vip->vip); + } + + /* Format for backend ips: "IP1:port1,IP2:port2,...". */ + size_t n_backends = 0; + size_t n_allocated_backends = 0; + char *tokstr = xstrdup(lb_value); + char *save_ptr = NULL; + for (char *token = strtok_r(tokstr, ",", &save_ptr); + token != NULL; + token = strtok_r(NULL, ",", &save_ptr)) { + + if (n_backends == n_allocated_backends) { + lb_vip->backends = x2nrealloc(lb_vip->backends, + &n_allocated_backends, + sizeof *lb_vip->backends); + } + + struct ovn_lb_backend *backend = &lb_vip->backends[n_backends]; + int backend_addr_family; + if (!ip_address_and_port_from_lb_key(token, &backend->ip_str, + &backend->port, + &backend_addr_family)) { + continue; + } + + if (addr_family != backend_addr_family) { + free(backend->ip_str); + continue; + } + + if (addr_family == AF_INET) { + ovs_be32 ip4; + ip_parse(backend->ip_str, &ip4); + in6_addr_set_mapped_ipv4(&backend->ip, ip4); + } else { + ipv6_parse(backend->ip_str, &backend->ip); + } + n_backends++; + } + free(tokstr); + lb_vip->n_backends = n_backends; + return true; +} + +static +void ovn_lb_vip_destroy(struct ovn_lb_vip *vip) +{ + free(vip->vip_str); + for (size_t i = 0; i < vip->n_backends; i++) { + free(vip->backends[i].ip_str); + } + free(vip->backends); +} + +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, + struct hmap *ports, + void * (*ovn_port_find)(const struct hmap *ports, + const char *name)) +{ + lb_vip_nb->vip_port_str = xstrdup(vip_port_str); + 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); + + struct nbrec_load_balancer_health_check *lb_health_check = NULL; + if (nbrec_lb->protocol && !strcmp(nbrec_lb->protocol, "sctp")) { + if (nbrec_lb->n_health_check > 0) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + 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)); + } + } else { + for (size_t j = 0; j < nbrec_lb->n_health_check; j++) { + if (!strcmp(nbrec_lb->health_check[j]->vip, + lb_vip_nb->vip_port_str)) { + lb_health_check = nbrec_lb->health_check[j]; + break; + } + } + } + + lb_vip_nb->lb_health_check = lb_health_check; + + for (size_t j = 0; j < lb_vip_nb->n_backends; j++) { + struct ovn_lb_backend *backend = &lb_vip->backends[j]; + struct ovn_northd_lb_backend *backend_nb = &lb_vip_nb->backends_nb[j]; + + struct ovn_port *op = NULL; + char *svc_mon_src_ip = NULL; + const char *s = smap_get(&nbrec_lb->ip_port_mappings, + backend->ip_str); + if (s) { + char *port_name = xstrdup(s); + char *p = strstr(port_name, ":"); + if (p) { + *p = 0; + p++; + op = ovn_port_find(ports, port_name); + svc_mon_src_ip = xstrdup(p); + } + free(port_name); + } + + backend_nb->op = op; + backend_nb->svc_mon_src_ip = svc_mon_src_ip; + } +} + +static +void ovn_northd_lb_vip_destroy(struct ovn_northd_lb_vip *vip) +{ + free(vip->vip_port_str); + free(vip->backend_ips); + for (size_t i = 0; i < vip->n_backends; i++) { + free(vip->backends_nb[i].svc_mon_src_ip); + } + free(vip->backends_nb); +} + +struct ovn_northd_lb * +ovn_northd_lb_create(const struct nbrec_load_balancer *nbrec_lb, + struct hmap *ports, + void * (*ovn_port_find)(const struct hmap *ports, + const char *name)) +{ + struct ovn_northd_lb *lb = xzalloc(sizeof *lb); + + lb->nlb = nbrec_lb; + 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); + 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]; + + if (!ovn_lb_vip_init(lb_vip, node->key, node->value)) { + continue; + } + ovn_northd_lb_vip_init(lb_vip_nb, lb_vip, nbrec_lb, + node->key, node->value, ports, ovn_port_find); + n_vips++; + } + + /* 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); + } + return lb; +} + +struct ovn_northd_lb * +ovn_northd_lb_find(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; +} + +void +ovn_northd_lb_add_datapath(struct ovn_northd_lb *lb, + const struct sbrec_datapath_binding *sb) +{ + if (lb->n_allocated_dps == lb->n_dps) { + lb->dps = x2nrealloc(lb->dps, &lb->n_allocated_dps, sizeof *lb->dps); + } + lb->dps[lb->n_dps++] = sb; +} + +void +ovn_northd_lb_destroy(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); + free(lb->selection_fields); + free(lb->dps); + free(lb); +} + +struct ovn_controller_lb * +ovn_controller_lb_create(const struct sbrec_load_balancer *sbrec_lb) +{ + struct ovn_controller_lb *lb = xzalloc(sizeof *lb); + + 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]; + + if (!ovn_lb_vip_init(lb_vip, node->key, node->value)) { + continue; + } + n_vips++; + } + + /* It's possible that parsing VIPs fails. Update the lb->n_vips to the + * correct value. + */ + lb->n_vips = n_vips; + 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); + free(lb); +} diff --git a/lib/lb.h b/lib/lb.h new file mode 100644 index 000000000..6644ad0d8 --- /dev/null +++ b/lib/lb.h @@ -0,0 +1,97 @@ +/* Copyright (c) 2020, 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_LIB_LB_H +#define OVN_LIB_LB_H 1 + +#include +#include +#include "openvswitch/hmap.h" + +struct nbrec_load_balancer; +struct sbrec_load_balancer; +struct sbrec_datapath_binding; +struct ovn_port; +struct uuid; + +struct ovn_northd_lb { + struct hmap_node hmap_node; + + const struct nbrec_load_balancer *nlb; /* May be NULL. */ + const struct sbrec_load_balancer *slb; /* May be NULL. */ + char *selection_fields; + struct ovn_lb_vip *vips; + struct ovn_northd_lb_vip *vips_nb; + size_t n_vips; + + size_t n_dps; + size_t n_allocated_dps; + const struct sbrec_datapath_binding **dps; +}; + +struct ovn_lb_vip { + struct in6_addr vip; + char *vip_str; + uint16_t vip_port; + + struct ovn_lb_backend *backends; + size_t n_backends; +}; + +struct ovn_lb_backend { + struct in6_addr ip; + char *ip_str; + uint16_t port; +}; + +/* ovn-northd specific backend information. */ +struct ovn_northd_lb_vip { + char *vip_port_str; + 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 { + struct ovn_port *op; /* Logical port to which the ip belong to. */ + bool health_check; + char *svc_mon_src_ip; /* Source IP to use for monitoring. */ + const struct sbrec_service_monitor *sbrec_monitor; +}; + +struct ovn_northd_lb *ovn_northd_lb_create( + const struct nbrec_load_balancer *, + struct hmap *ports, + void * (*ovn_port_find)(const struct hmap *ports, const char *name)); +struct ovn_northd_lb * ovn_northd_lb_find(struct hmap *, const struct uuid *); +void ovn_northd_lb_destroy(struct ovn_northd_lb *); +void ovn_northd_lb_add_datapath(struct ovn_northd_lb *, + const struct sbrec_datapath_binding *); + +struct ovn_controller_lb { + const struct sbrec_load_balancer *slb; /* May be NULL. */ + + struct ovn_lb_vip *vips; + size_t n_vips; +}; + +struct ovn_controller_lb *ovn_controller_lb_create( + const struct sbrec_load_balancer *); +void ovn_controller_lb_destroy(struct ovn_controller_lb *); + +#endif /* OVN_LIB_LB_H 1 */ diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index c32e25c3d..a7695bc63 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -35,6 +35,7 @@ #include "lib/ovn-nb-idl.h" #include "lib/ovn-sb-idl.h" #include "lib/ovn-util.h" +#include "lib/lb.h" #include "ovn/actions.h" #include "ovn/logical-fields.h" #include "packets.h" @@ -3329,66 +3330,6 @@ cleanup_sb_ha_chassis_groups(struct northd_context *ctx, } } -struct ovn_lb { - struct hmap_node hmap_node; - - const struct nbrec_load_balancer *nlb; /* May be NULL. */ - const struct sbrec_load_balancer *slb; /* May be NULL. */ - char *selection_fields; - struct lb_vip *vips; - size_t n_vips; - - size_t n_dps; - size_t n_allocated_dps; - const struct sbrec_datapath_binding **dps; -}; - -struct lb_vip { - char *vip; - uint16_t vip_port; - int addr_family; - char *backend_ips; - - bool health_check; - struct lb_vip_backend *backends; - size_t n_backends; -}; - -struct lb_vip_backend { - char *ip; - uint16_t port; - int addr_family; - - struct ovn_port *op; /* Logical port to which the ip belong to. */ - bool health_check; - char *svc_mon_src_ip; /* Source IP to use for monitoring. */ - const struct sbrec_service_monitor *sbrec_monitor; -}; - - -static inline struct ovn_lb * -ovn_lb_find(struct hmap *lbs, const struct uuid *uuid) -{ - struct ovn_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; -} - -static void -ovn_lb_add_datapath(struct ovn_lb *lb, struct ovn_datapath *od) -{ - if (lb->n_allocated_dps == lb->n_dps) { - lb->dps = x2nrealloc(lb->dps, &lb->n_allocated_dps, sizeof *lb->dps); - } - lb->dps[lb->n_dps++] = od->sb; -} - struct service_monitor_info { struct hmap_node hmap_node; const struct sbrec_service_monitor *sbrec_mon; @@ -3428,126 +3369,39 @@ create_or_get_service_mon(struct northd_context *ctx, return mon_info; } -static struct ovn_lb * -ovn_lb_create(struct northd_context *ctx, struct hmap *lbs, - const struct nbrec_load_balancer *nbrec_lb, - struct hmap *ports, struct hmap *monitor_map) +static void +ovn_lb_svc_create(struct northd_context *ctx, struct ovn_northd_lb *lb, + struct hmap *monitor_map) { - struct ovn_lb *lb = xzalloc(sizeof *lb); - - size_t hash = uuid_hash(&nbrec_lb->header_.uuid); - lb->nlb = nbrec_lb; - hmap_insert(lbs, &lb->hmap_node, hash); - - lb->n_vips = smap_count(&nbrec_lb->vips); - lb->vips = xcalloc(lb->n_vips, sizeof (struct lb_vip)); - struct smap_node *node; - size_t n_vips = 0; - - SMAP_FOR_EACH (node, &nbrec_lb->vips) { - char *vip; - uint16_t port; - int addr_family; + for (size_t i = 0; i < lb->n_vips; i++) { + struct ovn_lb_vip *lb_vip = &lb->vips[i]; + struct ovn_northd_lb_vip *lb_vip_nb = &lb->vips_nb[i]; - if (!ip_address_and_port_from_lb_key(node->key, &vip, &port, - &addr_family)) { + if (!lb_vip_nb->lb_health_check) { continue; } - lb->vips[n_vips].vip = vip; - lb->vips[n_vips].vip_port = port; - lb->vips[n_vips].addr_family = addr_family; - lb->vips[n_vips].backend_ips = xstrdup(node->value); - - struct nbrec_load_balancer_health_check *lb_health_check = NULL; - if (nbrec_lb->protocol && !strcmp(nbrec_lb->protocol, "sctp")) { - if (nbrec_lb->n_health_check > 0) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); - 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)); - } - } else { - for (size_t i = 0; i < nbrec_lb->n_health_check; i++) { - if (!strcmp(nbrec_lb->health_check[i]->vip, node->key)) { - lb_health_check = nbrec_lb->health_check[i]; - break; - } - } - } - - char *tokstr = xstrdup(node->value); - char *save_ptr = NULL; - char *token; - size_t n_backends = 0; - /* Format for a backend ips : IP1:port1,IP2:port2,...". */ - for (token = strtok_r(tokstr, ",", &save_ptr); - token != NULL; - token = strtok_r(NULL, ",", &save_ptr)) { - n_backends++; - } - - free(tokstr); - tokstr = xstrdup(node->value); - save_ptr = NULL; - - lb->vips[n_vips].n_backends = n_backends; - lb->vips[n_vips].backends = xcalloc(n_backends, - sizeof (struct lb_vip_backend)); - lb->vips[n_vips].health_check = lb_health_check ? true: false; + for (size_t j = 0; j < lb_vip->n_backends; j++) { + struct ovn_lb_backend *backend = &lb_vip->backends[j]; + struct ovn_northd_lb_backend *backend_nb = + &lb_vip_nb->backends_nb[j]; - size_t i = 0; - for (token = strtok_r(tokstr, ",", &save_ptr); - token != NULL; - token = strtok_r(NULL, ",", &save_ptr)) { - char *backend_ip; - uint16_t backend_port; - - if (!ip_address_and_port_from_lb_key(token, &backend_ip, - &backend_port, - &addr_family)) { - continue; - } - - /* Get the logical port to which this ip belongs to. */ - struct ovn_port *op = NULL; - char *svc_mon_src_ip = NULL; - const char *s = smap_get(&nbrec_lb->ip_port_mappings, - backend_ip); - if (s) { - char *port_name = xstrdup(s); - char *p = strstr(port_name, ":"); - if (p) { - *p = 0; - p++; - op = ovn_port_find(ports, port_name); - svc_mon_src_ip = xstrdup(p); - } - free(port_name); - } - - lb->vips[n_vips].backends[i].ip = backend_ip; - lb->vips[n_vips].backends[i].port = backend_port; - lb->vips[n_vips].backends[i].addr_family = addr_family; - lb->vips[n_vips].backends[i].op = op; - lb->vips[n_vips].backends[i].svc_mon_src_ip = svc_mon_src_ip; - - if (lb_health_check && op && svc_mon_src_ip) { - const char *protocol = nbrec_lb->protocol; + if (backend_nb->op && backend_nb->svc_mon_src_ip) { + const char *protocol = lb->nlb->protocol; if (!protocol || !protocol[0]) { protocol = "tcp"; } - lb->vips[n_vips].backends[i].health_check = true; + backend_nb->health_check = true; struct service_monitor_info *mon_info = - create_or_get_service_mon(ctx, monitor_map, backend_ip, - op->nbsp->name, backend_port, + create_or_get_service_mon(ctx, monitor_map, + backend->ip_str, + backend_nb->op->nbsp->name, + backend->port, protocol); ovs_assert(mon_info); sbrec_service_monitor_set_options( - mon_info->sbrec_mon, &lb_health_check->options); + mon_info->sbrec_mon, &lb_vip_nb->lb_health_check->options); struct eth_addr ea; if (!mon_info->sbrec_mon->src_mac || !eth_addr_from_string(mon_info->sbrec_mon->src_mac, &ea) || @@ -3557,89 +3411,45 @@ ovn_lb_create(struct northd_context *ctx, struct hmap *lbs, } if (!mon_info->sbrec_mon->src_ip || - strcmp(mon_info->sbrec_mon->src_ip, svc_mon_src_ip)) { - sbrec_service_monitor_set_src_ip(mon_info->sbrec_mon, - svc_mon_src_ip); + strcmp(mon_info->sbrec_mon->src_ip, + backend_nb->svc_mon_src_ip)) { + sbrec_service_monitor_set_src_ip( + mon_info->sbrec_mon, + backend_nb->svc_mon_src_ip); } - lb->vips[n_vips].backends[i].sbrec_monitor = - mon_info->sbrec_mon; + backend_nb->sbrec_monitor = mon_info->sbrec_mon; mon_info->required = true; - } else { - lb->vips[n_vips].backends[i].health_check = false; - } - - i++; - } - - free(tokstr); - n_vips++; - } - - char *proto = NULL; - if (nbrec_lb->protocol && nbrec_lb->protocol[0]) { - proto = nbrec_lb->protocol; - } - - if (lb->nlb->n_selection_fields) { - 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); } - - return lb; } -static void -ovn_lb_destroy(struct ovn_lb *lb) -{ - for (size_t i = 0; i < lb->n_vips; i++) { - free(lb->vips[i].vip); - free(lb->vips[i].backend_ips); - - for (size_t j = 0; j < lb->vips[i].n_backends; j++) { - free(lb->vips[i].backends[j].ip); - free(lb->vips[i].backends[j].svc_mon_src_ip); - } - - free(lb->vips[i].backends); - } - free(lb->vips); - free(lb->selection_fields); - free(lb->dps); -} - -static void build_lb_vip_ct_lb_actions(struct lb_vip *lb_vip, - struct ds *action, - char *selection_fields) +static +void build_lb_vip_ct_lb_actions(struct ovn_lb_vip *lb_vip, + struct ovn_northd_lb_vip *lb_vip_nb, + struct ds *action, + char *selection_fields) { bool skip_hash_fields = false; - if (lb_vip->health_check) { + if (lb_vip_nb->lb_health_check) { ds_put_cstr(action, "ct_lb(backends="); size_t n_active_backends = 0; - for (size_t k = 0; k < lb_vip->n_backends; k++) { - struct lb_vip_backend *backend = &lb_vip->backends[k]; - if (backend->health_check && backend->sbrec_monitor && - backend->sbrec_monitor->status && - strcmp(backend->sbrec_monitor->status, "online")) { + for (size_t i = 0; i < lb_vip->n_backends; i++) { + struct ovn_lb_backend *backend = &lb_vip->backends[i]; + struct ovn_northd_lb_backend *backend_nb = + &lb_vip_nb->backends_nb[i]; + if (backend_nb->health_check && backend_nb->sbrec_monitor && + backend_nb->sbrec_monitor->status && + strcmp(backend_nb->sbrec_monitor->status, "online")) { continue; } n_active_backends++; ds_put_format(action, "%s:%"PRIu16",", - backend->ip, backend->port); + backend->ip_str, backend->port); } if (!n_active_backends) { @@ -3651,7 +3461,7 @@ static void build_lb_vip_ct_lb_actions(struct lb_vip *lb_vip, ds_put_cstr(action, ");"); } } else { - ds_put_format(action, "ct_lb(backends=%s);", lb_vip->backend_ips); + ds_put_format(action, "ct_lb(backends=%s);", lb_vip_nb->backend_ips); } if (!skip_hash_fields && selection_fields && selection_fields[0]) { @@ -3681,7 +3491,14 @@ build_ovn_lbs(struct northd_context *ctx, struct hmap *datapaths, const struct nbrec_load_balancer *nbrec_lb; NBREC_LOAD_BALANCER_FOR_EACH (nbrec_lb, ctx->ovnnb_idl) { - ovn_lb_create(ctx, lbs, nbrec_lb, ports, &monitor_map); + struct ovn_northd_lb *lb = + ovn_northd_lb_create(nbrec_lb, ports, (void *)ovn_port_find); + hmap_insert(lbs, &lb->hmap_node, uuid_hash(&nbrec_lb->header_.uuid)); + } + + struct ovn_northd_lb *lb; + HMAP_FOR_EACH (lb, hmap_node, lbs) { + ovn_lb_svc_create(ctx, lb, &monitor_map); } struct ovn_datapath *od; @@ -3693,14 +3510,12 @@ build_ovn_lbs(struct northd_context *ctx, struct hmap *datapaths, for (size_t i = 0; i < od->nbs->n_load_balancer; i++) { const struct uuid *lb_uuid = &od->nbs->load_balancer[i]->header_.uuid; - struct ovn_lb *lb = ovn_lb_find(lbs, lb_uuid); + lb = ovn_northd_lb_find(lbs, lb_uuid); - ovn_lb_add_datapath(lb, od); + ovn_northd_lb_add_datapath(lb, od->sb); } } - struct ovn_lb *lb; - /* Delete any stale SB load balancer rows. */ const struct sbrec_load_balancer *sbrec_lb, *next; SBREC_LOAD_BALANCER_FOR_EACH_SAFE (sbrec_lb, next, ctx->ovnsb_idl) { @@ -3711,7 +3526,7 @@ build_ovn_lbs(struct northd_context *ctx, struct hmap *datapaths, continue; } - lb = ovn_lb_find(lbs, &lb_uuid); + lb = ovn_northd_lb_find(lbs, &lb_uuid); if (lb && lb->n_dps) { lb->slb = sbrec_lb; } else { @@ -3756,7 +3571,7 @@ build_ovn_lbs(struct northd_context *ctx, struct hmap *datapaths, for (size_t i = 0; i < od->nbs->n_load_balancer; i++) { const struct uuid *lb_uuid = &od->nbs->load_balancer[i]->header_.uuid; - lb = ovn_lb_find(lbs, lb_uuid); + lb = ovn_northd_lb_find(lbs, lb_uuid); sbrec_lbs[i] = lb->slb; } @@ -3777,16 +3592,6 @@ build_ovn_lbs(struct northd_context *ctx, struct hmap *datapaths, hmap_destroy(&monitor_map); } -static void -destroy_ovn_lbs(struct hmap *lbs) -{ - struct ovn_lb *lb; - HMAP_FOR_EACH_POP (lb, hmap_node, lbs) { - ovn_lb_destroy(lb); - free(lb); - } -} - /* Updates the southbound Port_Binding table so that it contains the logical * switch ports specified by the northbound database. * @@ -5171,7 +4976,7 @@ ls_has_dns_records(const struct nbrec_logical_switch *nbs) static void build_empty_lb_event_flow(struct ovn_datapath *od, struct hmap *lflows, - struct lb_vip *lb_vip, + struct ovn_lb_vip *lb_vip, struct nbrec_load_balancer *lb, int pl, struct shash *meter_groups) { @@ -5179,7 +4984,7 @@ build_empty_lb_event_flow(struct ovn_datapath *od, struct hmap *lflows, return; } - bool ipv4 = (lb_vip->addr_family == AF_INET); + bool ipv4 = IN6_IS_ADDR_V4MAPPED(&lb_vip->vip); struct ds match = DS_EMPTY_INITIALIZER; char *meter = "", *action; @@ -5188,13 +4993,13 @@ build_empty_lb_event_flow(struct ovn_datapath *od, struct hmap *lflows, } ds_put_format(&match, "ip%s.dst == %s && %s", - ipv4 ? "4": "6", lb_vip->vip, lb->protocol); + ipv4 ? "4": "6", lb_vip->vip_str, lb->protocol); - char *vip = lb_vip->vip; + char *vip = lb_vip->vip_str; if (lb_vip->vip_port) { ds_put_format(&match, " && %s.dst == %u", lb->protocol, lb_vip->vip_port); - vip = xasprintf("%s%s%s:%u", ipv4 ? "" : "[", lb_vip->vip, + vip = xasprintf("%s%s%s:%u", ipv4 ? "" : "[", lb_vip->vip_str, ipv4 ? "" : "]", lb_vip->vip_port); } @@ -5268,12 +5073,12 @@ build_pre_lb(struct ovn_datapath *od, struct hmap *lflows, bool vip_configured = false; for (int i = 0; i < od->nbs->n_load_balancer; i++) { struct nbrec_load_balancer *nb_lb = od->nbs->load_balancer[i]; - struct ovn_lb *lb = - ovn_lb_find(lbs, &nb_lb->header_.uuid); + struct ovn_northd_lb *lb = + ovn_northd_lb_find(lbs, &nb_lb->header_.uuid); ovs_assert(lb); for (size_t j = 0; j < lb->n_vips; j++) { - struct lb_vip *lb_vip = &lb->vips[j]; + struct ovn_lb_vip *lb_vip = &lb->vips[j]; build_empty_lb_event_flow(od, lflows, lb_vip, nb_lb, S_SWITCH_IN_PRE_LB, meter_groups); @@ -6008,7 +5813,8 @@ build_lb(struct ovn_datapath *od, struct hmap *lflows) static void build_lb_hairpin_rules(struct ovn_datapath *od, struct hmap *lflows, - struct ovn_lb *lb, struct lb_vip *lb_vip, + struct ovn_northd_lb *lb, + struct ovn_lb_vip *lb_vip, const char *ip_match, const char *proto) { if (lb_vip->n_backends == 0) { @@ -6030,7 +5836,7 @@ build_lb_hairpin_rules(struct ovn_datapath *od, struct hmap *lflows, */ ds_put_char(&match_reply, '('); for (size_t i = 0; i < lb_vip->n_backends; i++) { - struct lb_vip_backend *backend = &lb_vip->backends[i]; + struct ovn_lb_backend *backend = &lb_vip->backends[i]; /* Packets that after load balancing have equal source and * destination IPs should be hairpinned. @@ -6040,7 +5846,7 @@ build_lb_hairpin_rules(struct ovn_datapath *od, struct hmap *lflows, proto, backend->port); } ds_put_format(&match_initiator, "(%s.src == %s && %s.dst == %s%s)", - ip_match, backend->ip, ip_match, backend->ip, + ip_match, backend->ip_str, ip_match, backend->ip_str, ds_cstr(&proto_match)); /* Replies to hairpinned traffic are originated by backend->ip:port. */ @@ -6049,8 +5855,8 @@ build_lb_hairpin_rules(struct ovn_datapath *od, struct hmap *lflows, ds_put_format(&proto_match, " && %s.src == %"PRIu16, proto, backend->port); } - ds_put_format(&match_reply, "(%s.src == %s%s)", ip_match, backend->ip, - ds_cstr(&proto_match)); + ds_put_format(&match_reply, "(%s.src == %s%s)", + ip_match, backend->ip_str, ds_cstr(&proto_match)); ds_clear(&proto_match); if (i < lb_vip->n_backends - 1) { @@ -6064,13 +5870,13 @@ build_lb_hairpin_rules(struct ovn_datapath *od, struct hmap *lflows, * also directed through OVN. */ ds_put_format(&action, REGBIT_HAIRPIN " = 1; ct_snat(%s);", - lb_vip->vip); + lb_vip->vip_str); ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 2, ds_cstr(&match_initiator), ds_cstr(&action), &lb->nlb->header_); /* Replies to hairpinned traffic are destined to the LB VIP. */ - ds_put_format(&match_reply, " && %s.dst == %s", ip_match, lb_vip->vip); + ds_put_format(&match_reply, " && %s.dst == %s", ip_match, lb_vip->vip_str); /* UNSNAT replies for hairpinned traffic. */ ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_HAIRPIN, 1, @@ -6085,13 +5891,15 @@ build_lb_hairpin_rules(struct ovn_datapath *od, struct hmap *lflows, } static void -build_lb_rules(struct ovn_datapath *od, struct hmap *lflows, struct ovn_lb *lb) +build_lb_rules(struct ovn_datapath *od, struct hmap *lflows, + struct ovn_northd_lb *lb) { for (size_t i = 0; i < lb->n_vips; i++) { - struct lb_vip *lb_vip = &lb->vips[i]; + struct ovn_lb_vip *lb_vip = &lb->vips[i]; + struct ovn_northd_lb_vip *lb_vip_nb = &lb->vips_nb[i]; const char *ip_match = NULL; - if (lb_vip->addr_family == AF_INET) { + if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) { ip_match = "ip4"; } else { ip_match = "ip6"; @@ -6111,10 +5919,12 @@ build_lb_rules(struct ovn_datapath *od, struct hmap *lflows, struct ovn_lb *lb) /* New connections in Ingress table. */ struct ds action = DS_EMPTY_INITIALIZER; - build_lb_vip_ct_lb_actions(lb_vip, &action, lb->selection_fields); + build_lb_vip_ct_lb_actions(lb_vip, lb_vip_nb, &action, + lb->selection_fields); struct ds match = DS_EMPTY_INITIALIZER; - ds_put_format(&match, "ct.new && %s.dst == %s", ip_match, lb_vip->vip); + ds_put_format(&match, "ct.new && %s.dst == %s", ip_match, + lb_vip->vip_str); if (lb_vip->vip_port) { ds_put_format(&match, " && %s.dst == %d", proto, lb_vip->vip_port); ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_STATEFUL, 120, @@ -6174,8 +5984,8 @@ build_stateful(struct ovn_datapath *od, struct hmap *lflows, struct hmap *lbs) * connection, so it is okay if we do not hit the above match on * REGBIT_CONNTRACK_COMMIT. */ for (int i = 0; i < od->nbs->n_load_balancer; i++) { - struct ovn_lb *lb = - ovn_lb_find(lbs, &od->nbs->load_balancer[i]->header_.uuid); + struct ovn_northd_lb *lb = + ovn_northd_lb_find(lbs, &od->nbs->load_balancer[i]->header_.uuid); ovs_assert(lb); build_lb_rules(od, lflows, lb); @@ -7110,22 +6920,24 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, /* Ingress table 13: ARP/ND responder for service monitor source ip. * (priority 110)*/ - struct ovn_lb *lb; + struct ovn_northd_lb *lb; HMAP_FOR_EACH (lb, hmap_node, lbs) { for (size_t i = 0; i < lb->n_vips; i++) { - if (!lb->vips[i].health_check) { + struct ovn_northd_lb_vip *lb_vip_nb = &lb->vips_nb[i]; + if (!lb_vip_nb->lb_health_check) { continue; } - for (size_t j = 0; j < lb->vips[i].n_backends; j++) { - if (!lb->vips[i].backends[j].op || - !lb->vips[i].backends[j].svc_mon_src_ip) { + for (size_t j = 0; j < lb_vip_nb->n_backends; j++) { + struct ovn_northd_lb_backend *backend_nb = + &lb_vip_nb->backends_nb[i]; + if (!backend_nb->op || !backend_nb->svc_mon_src_ip) { continue; } ds_clear(&match); ds_put_format(&match, "arp.tpa == %s && arp.op == 1", - lb->vips[i].backends[j].svc_mon_src_ip); + backend_nb->svc_mon_src_ip); ds_clear(&actions); ds_put_format(&actions, "eth.dst = eth.src; " @@ -7139,9 +6951,9 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, "flags.loopback = 1; " "output;", svc_monitor_mac, svc_monitor_mac, - lb->vips[i].backends[j].svc_mon_src_ip); + backend_nb->svc_mon_src_ip); ovn_lflow_add_with_hint(lflows, - lb->vips[i].backends[j].op->od, + backend_nb->op->od, S_SWITCH_IN_ARP_ND_RSP, 110, ds_cstr(&match), ds_cstr(&actions), &lb->nlb->header_); @@ -8319,7 +8131,7 @@ get_force_snat_ip(struct ovn_datapath *od, const char *key_type, static void add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od, struct ds *match, struct ds *actions, int priority, - bool lb_force_snat_ip, struct lb_vip *lb_vip, + bool lb_force_snat_ip, struct ovn_lb_vip *lb_vip, const char *proto, struct nbrec_load_balancer *lb, struct shash *meter_groups, struct sset *nat_entries) { @@ -8355,13 +8167,13 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od, free(est_match); const char *ip_match = NULL; - if (lb_vip->addr_family == AF_INET) { + if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) { ip_match = "ip4"; } else { ip_match = "ip6"; } - if (sset_contains(nat_entries, lb_vip->vip)) { + if (sset_contains(nat_entries, lb_vip->vip_str)) { /* The load balancer vip is also present in the NAT entries. * So add a high priority lflow to advance the the packet * destined to the vip (and the vip port if defined) @@ -8375,7 +8187,7 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od, * S_ROUTER_IN_DNAT stage. */ struct ds unsnat_match = DS_EMPTY_INITIALIZER; ds_put_format(&unsnat_match, "%s && %s.dst == %s && %s", - ip_match, ip_match, lb_vip->vip, proto); + ip_match, ip_match, lb_vip->vip_str, proto); if (lb_vip->vip_port) { ds_put_format(&unsnat_match, " && %s.dst == %d", proto, lb_vip->vip_port); @@ -8399,8 +8211,9 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od, ds_put_format(&undnat_match, "%s && (", ip_match); for (size_t i = 0; i < lb_vip->n_backends; i++) { - struct lb_vip_backend *backend = &lb_vip->backends[i]; - ds_put_format(&undnat_match, "(%s.src == %s", ip_match, backend->ip); + struct ovn_lb_backend *backend = &lb_vip->backends[i]; + ds_put_format(&undnat_match, "(%s.src == %s", ip_match, + backend->ip_str); if (backend->port) { ds_put_format(&undnat_match, " && %s.src == %d) || ", @@ -10095,18 +9908,19 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, for (int i = 0; i < od->nbr->n_load_balancer; i++) { struct nbrec_load_balancer *nb_lb = od->nbr->load_balancer[i]; - struct ovn_lb *lb = - ovn_lb_find(lbs, &nb_lb->header_.uuid); + struct ovn_northd_lb *lb = + ovn_northd_lb_find(lbs, &nb_lb->header_.uuid); ovs_assert(lb); for (size_t j = 0; j < lb->n_vips; j++) { - struct lb_vip *lb_vip = &lb->vips[j]; + struct ovn_lb_vip *lb_vip = &lb->vips[j]; + struct ovn_northd_lb_vip *lb_vip_nb = &lb->vips_nb[j]; ds_clear(&actions); - build_lb_vip_ct_lb_actions(lb_vip, &actions, + build_lb_vip_ct_lb_actions(lb_vip, lb_vip_nb, &actions, lb->selection_fields); - if (!sset_contains(&all_ips, lb_vip->vip)) { - sset_add(&all_ips, lb_vip->vip); + if (!sset_contains(&all_ips, lb_vip->vip_str)) { + sset_add(&all_ips, lb_vip->vip_str); /* If there are any load balancing rules, we should send * the packet to conntrack for defragmentation and * tracking. This helps with two things. @@ -10116,12 +9930,12 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, * 2. If there are L4 ports in load balancing rules, we * need the defragmentation to match on L4 ports. */ ds_clear(&match); - if (lb_vip->addr_family == AF_INET) { + if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) { ds_put_format(&match, "ip && ip4.dst == %s", - lb_vip->vip); - } else if (lb_vip->addr_family == AF_INET6) { + lb_vip->vip_str); + } else { ds_put_format(&match, "ip && ip6.dst == %s", - lb_vip->vip); + lb_vip->vip_str); } ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DEFRAG, 100, ds_cstr(&match), "ct_next;", @@ -10134,12 +9948,12 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, * on ct.new with an action of "ct_lb($targets);". The other * flow is for ct.est with an action of "ct_dnat;". */ ds_clear(&match); - if (lb_vip->addr_family == AF_INET) { + if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) { ds_put_format(&match, "ip && ip4.dst == %s", - lb_vip->vip); - } else if (lb_vip->addr_family == AF_INET6) { + lb_vip->vip_str); + } else { ds_put_format(&match, "ip && ip6.dst == %s", - lb_vip->vip); + lb_vip->vip_str); } int prio = 110; @@ -12287,7 +12101,11 @@ ovnnb_db_run(struct northd_context *ctx, sync_port_groups(ctx, &port_groups); sync_meters(ctx); sync_dns_entries(ctx, datapaths); - destroy_ovn_lbs(&lbs); + + struct ovn_northd_lb *lb; + HMAP_FOR_EACH_POP (lb, hmap_node, &lbs) { + ovn_northd_lb_destroy(lb); + } hmap_destroy(&lbs); struct ovn_igmp_group *igmp_group, *next_igmp_group; -- 2.28.0