Refactor of build ipam function removing unnecessary ovn_port_find call. Also, functions from ipam could be used in future for incremental processing.
Signed-off-by: Lucas Vargas Dias <lucas.vd...@luizalabs.com> --- northd/ipam.c | 496 +++++++++++++++++++++++++++++++++++++++++++++++ northd/ipam.h | 35 ++++ northd/northd.c | 497 +----------------------------------------------- 3 files changed, 538 insertions(+), 490 deletions(-) diff --git a/northd/ipam.c b/northd/ipam.c index 04fa357a5..280d9b425 100644 --- a/northd/ipam.c +++ b/northd/ipam.c @@ -6,6 +6,7 @@ #include <netinet/in.h> #include "ipam.h" +#include "northd.h" #include "ovn/lex.h" #include "smap.h" @@ -23,6 +24,33 @@ static void init_ipam_ipv4(const char *subnet_str, static bool ipam_is_duplicate_mac(struct eth_addr *ea, uint64_t mac64, bool warn); +static void +ipam_insert_ip_for_datapath(struct ovn_datapath *, uint32_t, bool); + +static void +ipam_insert_lsp_addresses(struct ovn_datapath *, struct lport_addresses *); + +static enum dynamic_update_type dynamic_mac_changed(const char *, + struct dynamic_address_update *); + +static enum dynamic_update_type dynamic_ip4_changed(const char *, + struct dynamic_address_update *); + +static enum dynamic_update_type dynamic_ip6_changed(const char *, + struct dynamic_address_update *); + +static bool dynamic_addresses_check_for_updates(const char *, + struct dynamic_address_update *); + +static void update_unchanged_dynamic_addresses( + struct dynamic_address_update *); + +static void set_lsp_dynamic_addresses(const char *, + struct ovn_port *); + +static void set_dynamic_updates(const char *, + struct dynamic_address_update *); + void init_ipam_info(struct ipam_info *info, const struct smap *config, const char *id) { @@ -40,6 +68,18 @@ init_ipam_info(struct ipam_info *info, const struct smap *config, const char *id } } +void +init_ipam_info_for_datapath(struct ovn_datapath *od) +{ + if (!od->nbs) { + return; + } + + char uuid_s[UUID_LEN + 1]; + sprintf(uuid_s, UUID_FMT, UUID_ARGS(&od->key)); + init_ipam_info(&od->ipam_info, &od->nbs->other_config, uuid_s); +} + void destroy_ipam_info(struct ipam_info *info) { @@ -69,6 +109,17 @@ ipam_insert_ip(struct ipam_info *info, uint32_t ip, bool dynamic) return true; } +static void +ipam_insert_ip_for_datapath(struct ovn_datapath *od, uint32_t ip, + bool dynamic) +{ + if (!od) { + return; + } + + ipam_insert_ip(&od->ipam_info, ip, dynamic); +} + uint32_t ipam_get_unused_ip(struct ipam_info *info) { @@ -338,3 +389,448 @@ ipam_is_duplicate_mac(struct eth_addr *ea, uint64_t mac64, bool warn) return false; } +static enum dynamic_update_type +dynamic_mac_changed(const char *lsp_addresses, + struct dynamic_address_update *update) +{ + struct eth_addr ea; + + if (ovs_scan(lsp_addresses, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(ea))) { + if (eth_addr_equals(ea, update->current_addresses.ea)) { + return NONE; + } else { + /* MAC is still static, but it has changed */ + update->static_mac = ea; + return STATIC; + } + } + + uint64_t mac64 = eth_addr_to_uint64(update->current_addresses.ea); + uint64_t prefix = eth_addr_to_uint64(get_mac_prefix()); + + if ((mac64 ^ prefix) >> 24) { + return DYNAMIC; + } else { + return NONE; + } +} + +static enum dynamic_update_type +dynamic_ip4_changed(const char *lsp_addrs, + struct dynamic_address_update *update) +{ + const struct ipam_info *ipam = &update->op->od->ipam_info; + const struct lport_addresses *cur_addresses = &update->current_addresses; + bool dynamic_ip4 = ipam->allocated_ipv4s != NULL; + + if (!dynamic_ip4) { + if (update->current_addresses.n_ipv4_addrs) { + return REMOVE; + } else { + return NONE; + } + } + + if (!cur_addresses->n_ipv4_addrs) { + /* IPv4 was previously static but now is dynamic */ + return DYNAMIC; + } + + uint32_t ip4 = ntohl(cur_addresses->ipv4_addrs[0].addr); + if (ip4 < ipam->start_ipv4) { + return DYNAMIC; + } + + uint32_t index = ip4 - ipam->start_ipv4; + if (index >= ipam->total_ipv4s - 1 || + bitmap_is_set(ipam->allocated_ipv4s, index)) { + /* Previously assigned dynamic IPv4 address can no longer be used. + * It's either outside the subnet, conflicts with an excluded IP, + * or conflicts with a statically-assigned address on the switch + */ + return DYNAMIC; + } else { + char ipv6_s[IPV6_SCAN_LEN + 1]; + ovs_be32 new_ip; + int n = 0; + + if ((ovs_scan(lsp_addrs, "dynamic "IP_SCAN_FMT"%n", + IP_SCAN_ARGS(&new_ip), &n) + && lsp_addrs[n] == '\0') || + (ovs_scan(lsp_addrs, "dynamic "IP_SCAN_FMT" "IPV6_SCAN_FMT"%n", + IP_SCAN_ARGS(&new_ip), ipv6_s, &n) + && lsp_addrs[n] == '\0')) { + index = ntohl(new_ip) - ipam->start_ipv4; + if (ntohl(new_ip) < ipam->start_ipv4 || + index > ipam->total_ipv4s || + bitmap_is_set(ipam->allocated_ipv4s, index)) { + /* new static ip is not valid */ + return DYNAMIC; + } else if (cur_addresses->ipv4_addrs[0].addr != new_ip) { + update->ipv4 = STATIC; + update->static_ip = new_ip; + return STATIC; + } + } + return NONE; + } +} + +static enum dynamic_update_type +dynamic_ip6_changed(const char *lsp_addrs, + struct dynamic_address_update *update) +{ + bool dynamic_ip6 = update->op->od->ipam_info.ipv6_prefix_set; + struct eth_addr ea; + + if (!dynamic_ip6) { + if (update->current_addresses.n_ipv6_addrs) { + /* IPv6 was dynamic but now is not */ + return REMOVE; + } else { + /* IPv6 has never been dynamic */ + return NONE; + } + } + + if (!update->current_addresses.n_ipv6_addrs || + ovs_scan(lsp_addrs, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(ea))) { + /* IPv6 was previously static but now is dynamic */ + return DYNAMIC; + } + + const struct lport_addresses *cur_addresses; + char ipv6_s[IPV6_SCAN_LEN + 1]; + ovs_be32 new_ip; + int n = 0; + + if ((ovs_scan(lsp_addrs, "dynamic "IPV6_SCAN_FMT"%n", + ipv6_s, &n) && lsp_addrs[n] == '\0') || + (ovs_scan(lsp_addrs, "dynamic "IP_SCAN_FMT" "IPV6_SCAN_FMT"%n", + IP_SCAN_ARGS(&new_ip), ipv6_s, &n) + && lsp_addrs[n] == '\0')) { + struct in6_addr ipv6; + + if (!ipv6_parse(ipv6_s, &ipv6)) { + return DYNAMIC; + } + + struct in6_addr masked = ipv6_addr_bitand(&ipv6, + &update->op->od->ipam_info.ipv6_prefix); + if (!IN6_ARE_ADDR_EQUAL(&masked, + &update->op->od->ipam_info.ipv6_prefix)) { + return DYNAMIC; + } + + cur_addresses = &update->current_addresses; + + if (!IN6_ARE_ADDR_EQUAL(&cur_addresses->ipv6_addrs[0].addr, + &ipv6)) { + update->static_ipv6 = ipv6; + return STATIC; + } + } else if (update->mac != NONE) { + return DYNAMIC; + } + + return NONE; +} + +/* Check previously assigned dynamic addresses for validity. This will + * check if the assigned addresses need to change. + * + * Returns true if any changes to dynamic addresses are required + */ +static bool +dynamic_addresses_check_for_updates(const char *lsp_addrs, + struct dynamic_address_update *update) +{ + update->mac = dynamic_mac_changed(lsp_addrs, update); + update->ipv4 = dynamic_ip4_changed(lsp_addrs, update); + update->ipv6 = dynamic_ip6_changed(lsp_addrs, update); + if (update->mac == NONE && + update->ipv4 == NONE && + update->ipv6 == NONE) { + return false; + } else { + return true; + } +} + +/* For addresses that do not need to be updated, go ahead and insert them + * into IPAM. This way, their addresses will be claimed and cannot be assigned + * elsewhere later. + */ +static void +update_unchanged_dynamic_addresses(struct dynamic_address_update *update) +{ + if (update->mac == NONE) { + ipam_insert_mac(&update->current_addresses.ea, false); + } + if (update->ipv4 == NONE && update->current_addresses.n_ipv4_addrs) { + ipam_insert_ip_for_datapath(update->op->od, + ntohl(update->current_addresses.ipv4_addrs[0].addr), + true); + } +} + +static void +set_lsp_dynamic_addresses(const char *dynamic_addresses, struct ovn_port *op) +{ + extract_lsp_addresses(dynamic_addresses, &op->lsp_addrs[op->n_lsp_addrs]); + op->n_lsp_addrs++; +} + +/* Determines which components (MAC, IPv4, and IPv6) of dynamic + * addresses need to be assigned. This is used exclusively for + * ports that do not have dynamic addresses already assigned. + */ +static void +set_dynamic_updates(const char *addrspec, + struct dynamic_address_update *update) +{ + bool has_ipv4 = false, has_ipv6 = false; + char ipv6_s[IPV6_SCAN_LEN + 1]; + struct eth_addr mac; + ovs_be32 ip; + int n = 0; + if (ovs_scan(addrspec, ETH_ADDR_SCAN_FMT" dynamic%n", + ETH_ADDR_SCAN_ARGS(mac), &n) + && addrspec[n] == '\0') { + update->mac = STATIC; + update->static_mac = mac; + } else { + update->mac = DYNAMIC; + } + + if ((ovs_scan(addrspec, "dynamic "IP_SCAN_FMT"%n", + IP_SCAN_ARGS(&ip), &n) && addrspec[n] == '\0')) { + has_ipv4 = true; + } else if ((ovs_scan(addrspec, "dynamic "IPV6_SCAN_FMT"%n", + ipv6_s, &n) && addrspec[n] == '\0')) { + has_ipv6 = true; + } else if ((ovs_scan(addrspec, "dynamic "IP_SCAN_FMT" "IPV6_SCAN_FMT"%n", + IP_SCAN_ARGS(&ip), ipv6_s, &n) + && addrspec[n] == '\0')) { + has_ipv4 = has_ipv6 = true; + } + + if (has_ipv4) { + update->ipv4 = STATIC; + update->static_ip = ip; + } else if (update->op->od->ipam_info.allocated_ipv4s) { + update->ipv4 = DYNAMIC; + } else { + update->ipv4 = NONE; + } + + if (has_ipv6 && ipv6_parse(ipv6_s, &update->static_ipv6)) { + update->ipv6 = STATIC; + } else if (update->op->od->ipam_info.ipv6_prefix_set) { + update->ipv6 = DYNAMIC; + } else { + update->ipv6 = NONE; + } +} + +void +update_dynamic_addresses(struct dynamic_address_update *update) +{ + ovs_be32 ip4 = 0; + switch (update->ipv4) { + case NONE: + if (update->current_addresses.n_ipv4_addrs) { + ip4 = update->current_addresses.ipv4_addrs[0].addr; + } + break; + case REMOVE: + break; + case STATIC: + ip4 = update->static_ip; + break; + case DYNAMIC: + ip4 = htonl(ipam_get_unused_ip(&update->od->ipam_info)); + VLOG_INFO("Assigned dynamic IPv4 address '"IP_FMT"' to port '%s'", + IP_ARGS(ip4), update->op->nbsp->name); + } + + struct eth_addr mac; + switch (update->mac) { + case NONE: + mac = update->current_addresses.ea; + break; + case REMOVE: + OVS_NOT_REACHED(); + case STATIC: + mac = update->static_mac; + break; + case DYNAMIC: + eth_addr_from_uint64(ipam_get_unused_mac(ip4), &mac); + VLOG_INFO("Assigned dynamic MAC address '"ETH_ADDR_FMT"' to port '%s'", + ETH_ADDR_ARGS(mac), update->op->nbsp->name); + break; + } + + struct in6_addr ip6 = in6addr_any; + switch (update->ipv6) { + case NONE: + if (update->current_addresses.n_ipv6_addrs) { + ip6 = update->current_addresses.ipv6_addrs[0].addr; + } + break; + case REMOVE: + break; + case STATIC: + ip6 = update->static_ipv6; + break; + case DYNAMIC: + in6_generate_eui64(mac, &update->od->ipam_info.ipv6_prefix, &ip6); + struct ds ip6_ds = DS_EMPTY_INITIALIZER; + ipv6_format_addr(&ip6, &ip6_ds); + VLOG_INFO("Assigned dynamic IPv6 address '%s' to port '%s'", + ip6_ds.string, update->op->nbsp->name); + ds_destroy(&ip6_ds); + break; + } + + struct ds new_addr = DS_EMPTY_INITIALIZER; + ds_put_format(&new_addr, ETH_ADDR_FMT, ETH_ADDR_ARGS(mac)); + ipam_insert_mac(&mac, true); + + if (ip4) { + ipam_insert_ip_for_datapath(update->od, ntohl(ip4), true); + ds_put_format(&new_addr, " "IP_FMT, IP_ARGS(ip4)); + } + if (!IN6_ARE_ADDR_EQUAL(&ip6, &in6addr_any)) { + char ip6_s[INET6_ADDRSTRLEN + 1]; + ipv6_string_mapped(ip6_s, &ip6); + ds_put_format(&new_addr, " %s", ip6_s); + } + nbrec_logical_switch_port_set_dynamic_addresses(update->op->nbsp, + ds_cstr(&new_addr)); + set_lsp_dynamic_addresses(ds_cstr(&new_addr), update->op); + ds_destroy(&new_addr); +} + + +void +update_ipam_ls(struct ovn_datapath *od, struct vector *updates, + bool recompute) +{ + ovs_assert(od); + ovs_assert(od->nbs); + ovs_assert(updates); + + struct ovn_port *op; + HMAP_FOR_EACH (op, dp_node, &od->ports) { + const struct nbrec_logical_switch_port *nbsp = op->nbsp; + ovs_assert(nbsp); + + if (!od->ipam_info.allocated_ipv4s && + !od->ipam_info.ipv6_prefix_set && + !od->ipam_info.mac_only) { + if (nbsp->dynamic_addresses) { + nbrec_logical_switch_port_set_dynamic_addresses(nbsp, + NULL); + } + continue; + } + + int num_dynamic_addresses = 0; + for (size_t j = 0; j < nbsp->n_addresses; j++) { + if (!is_dynamic_lsp_address(nbsp->addresses[j])) { + continue; + } + if (num_dynamic_addresses) { + static struct vlog_rate_limit rl + = VLOG_RATE_LIMIT_INIT(1, 1); + VLOG_WARN_RL(&rl, "More than one dynamic address " + "configured for logical switch port '%s'", + nbsp->name); + continue; + } + num_dynamic_addresses++; + struct dynamic_address_update update = { + .op = op, + .od = od, + }; + init_lport_addresses(&update.current_addresses); + if (nbsp->dynamic_addresses) { + bool any_changed; + extract_lsp_addresses(nbsp->dynamic_addresses, + &update.current_addresses); + any_changed = dynamic_addresses_check_for_updates( + nbsp->addresses[j], &update); + update_unchanged_dynamic_addresses(&update); + if (any_changed) { + vector_push(updates, &update); + } else { + /* No changes to dynamic addresses */ + if (recompute) { + set_lsp_dynamic_addresses(nbsp->dynamic_addresses, op); + } + destroy_lport_addresses(&update.current_addresses); + } + } else { + set_dynamic_updates(nbsp->addresses[j], &update); + vector_push(updates, &update); + } + } + + if (!num_dynamic_addresses && nbsp->dynamic_addresses) { + nbrec_logical_switch_port_set_dynamic_addresses(nbsp, NULL); + } + } +} + +void +ipam_add_port_addresses(struct ovn_datapath *od, struct ovn_port *op) +{ + if (!od || !op) { + return; + } + + if (op->n_lsp_non_router_addrs) { + /* Add all the port's addresses to address data structures. */ + for (size_t i = 0; i < op->n_lsp_non_router_addrs; i++) { + ipam_insert_lsp_addresses(od, &op->lsp_addrs[i]); + } + } else if (op->lrp_networks.ea_s[0]) { + ipam_insert_mac(&op->lrp_networks.ea, true); + + if (!op->peer || !op->peer->nbsp || !op->peer->od || !op->peer->od->nbs + || !smap_get(&op->peer->od->nbs->other_config, "subnet")) { + return; + } + + for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { + uint32_t ip = ntohl(op->lrp_networks.ipv4_addrs[i].addr); + /* If the router has the first IP address of the subnet, don't add + * it to IPAM. We already added this when we initialized IPAM for + * the datapath. This will just result in an erroneous message + * about a duplicate IP address. + */ + if (ip != op->peer->od->ipam_info.start_ipv4) { + ipam_insert_ip_for_datapath(op->peer->od, ip, false); + } + } + } +} + +static void +ipam_insert_lsp_addresses(struct ovn_datapath *od, + struct lport_addresses *laddrs) +{ + ipam_insert_mac(&laddrs->ea, true); + + /* IP is only added to IPAM if the switch's subnet option + * is set, whereas MAC is always added to MACAM. */ + if (!od->ipam_info.allocated_ipv4s) { + return; + } + + for (size_t j = 0; j < laddrs->n_ipv4_addrs; j++) { + uint32_t ip = ntohl(laddrs->ipv4_addrs[j].addr); + ipam_insert_ip_for_datapath(od, ip, false); + } +} diff --git a/northd/ipam.h b/northd/ipam.h index 6240f9ab7..c825875a8 100644 --- a/northd/ipam.h +++ b/northd/ipam.h @@ -5,6 +5,8 @@ #include <stdbool.h> #include "openvswitch/types.h" +#include "lib/vec.h" +#include "lib/ovn-util.h" struct ipam_info { uint32_t start_ipv4; @@ -17,9 +19,36 @@ struct ipam_info { }; struct smap; +struct ovn_datapath; +struct ovn_port; + + +enum dynamic_update_type { + NONE, /* No change to the address */ + REMOVE, /* Address is no longer dynamic */ + STATIC, /* Use static address (MAC only) */ + DYNAMIC, /* Assign a new dynamic address */ +}; + +struct dynamic_address_update { + struct ovn_datapath *od; + struct ovn_port *op; + + struct lport_addresses current_addresses; + struct eth_addr static_mac; + ovs_be32 static_ip; + struct in6_addr static_ipv6; + enum dynamic_update_type mac; + enum dynamic_update_type ipv4; + enum dynamic_update_type ipv6; +}; + void init_ipam_info(struct ipam_info *info, const struct smap *config, const char *id); + +void init_ipam_info_for_datapath(struct ovn_datapath *od); + void destroy_ipam_info(struct ipam_info *info); bool ipam_insert_ip(struct ipam_info *info, uint32_t ip, bool dynamic); @@ -36,4 +65,10 @@ struct eth_addr get_mac_prefix(void); const char *set_mac_prefix(const char *hint); +void update_ipam_ls(struct ovn_datapath *, struct vector *, bool); + +void update_dynamic_addresses(struct dynamic_address_update *); + +void ipam_add_port_addresses(struct ovn_datapath *, struct ovn_port *); + #endif /* NORTHD_IPAM_H */ diff --git a/northd/northd.c b/northd/northd.c index 9b21786fa..ef2271fdf 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -604,18 +604,6 @@ lrouter_is_enabled(const struct nbrec_logical_router *lrouter) return !lrouter->enabled || *lrouter->enabled; } -static void -init_ipam_info_for_datapath(struct ovn_datapath *od) -{ - if (!od->nbs) { - return; - } - - char uuid_s[UUID_LEN + 1]; - sprintf(uuid_s, UUID_FMT, UUID_ARGS(&od->key)); - init_ipam_info(&od->ipam_info, &od->nbs->other_config, uuid_s); -} - static void init_mcast_info_for_router_datapath(struct ovn_datapath *od) { @@ -1502,67 +1490,7 @@ ovn_port_get_peer(const struct hmap *lr_ports, struct ovn_port *op) return ovn_port_find(lr_ports, peer_name); } -static void -ipam_insert_ip_for_datapath(struct ovn_datapath *od, uint32_t ip, bool dynamic) -{ - if (!od) { - return; - } - - ipam_insert_ip(&od->ipam_info, ip, dynamic); -} - -static void -ipam_insert_lsp_addresses(struct ovn_datapath *od, - struct lport_addresses *laddrs) -{ - ipam_insert_mac(&laddrs->ea, true); - /* IP is only added to IPAM if the switch's subnet option - * is set, whereas MAC is always added to MACAM. */ - if (!od->ipam_info.allocated_ipv4s) { - return; - } - - for (size_t j = 0; j < laddrs->n_ipv4_addrs; j++) { - uint32_t ip = ntohl(laddrs->ipv4_addrs[j].addr); - ipam_insert_ip_for_datapath(od, ip, false); - } -} - -static void -ipam_add_port_addresses(struct ovn_datapath *od, struct ovn_port *op) -{ - if (!od || !op) { - return; - } - - if (op->n_lsp_non_router_addrs) { - /* Add all the port's addresses to address data structures. */ - for (size_t i = 0; i < op->n_lsp_non_router_addrs; i++) { - ipam_insert_lsp_addresses(od, &op->lsp_addrs[i]); - } - } else if (op->lrp_networks.ea_s[0]) { - ipam_insert_mac(&op->lrp_networks.ea, true); - - if (!op->peer || !op->peer->nbsp || !op->peer->od || !op->peer->od->nbs - || !smap_get(&op->peer->od->nbs->other_config, "subnet")) { - return; - } - - for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { - uint32_t ip = ntohl(op->lrp_networks.ipv4_addrs[i].addr); - /* If the router has the first IP address of the subnet, don't add - * it to IPAM. We already added this when we initialized IPAM for - * the datapath. This will just result in an erroneous message - * about a duplicate IP address. - */ - if (ip != op->peer->od->ipam_info.start_ipv4) { - ipam_insert_ip_for_datapath(op->peer->od, ip, false); - } - } - } -} /* Returns true if the given router port 'op' (assumed to be a distributed * gateway port) is the relevant DGP where the NAT rule of the router needs to @@ -1578,444 +1506,33 @@ is_nat_gateway_port(const struct nbrec_nat *nat, const struct ovn_port *op) return true; } -enum dynamic_update_type { - NONE, /* No change to the address */ - REMOVE, /* Address is no longer dynamic */ - STATIC, /* Use static address (MAC only) */ - DYNAMIC, /* Assign a new dynamic address */ -}; - -struct dynamic_address_update { - struct ovs_list node; /* In build_ipam()'s list of updates. */ - - struct ovn_datapath *od; - struct ovn_port *op; - - struct lport_addresses current_addresses; - struct eth_addr static_mac; - ovs_be32 static_ip; - struct in6_addr static_ipv6; - enum dynamic_update_type mac; - enum dynamic_update_type ipv4; - enum dynamic_update_type ipv6; -}; - -static enum dynamic_update_type -dynamic_mac_changed(const char *lsp_addresses, - struct dynamic_address_update *update) -{ - struct eth_addr ea; - - if (ovs_scan(lsp_addresses, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(ea))) { - if (eth_addr_equals(ea, update->current_addresses.ea)) { - return NONE; - } else { - /* MAC is still static, but it has changed */ - update->static_mac = ea; - return STATIC; - } - } - - uint64_t mac64 = eth_addr_to_uint64(update->current_addresses.ea); - uint64_t prefix = eth_addr_to_uint64(get_mac_prefix()); - - if ((mac64 ^ prefix) >> 24) { - return DYNAMIC; - } else { - return NONE; - } -} - -static enum dynamic_update_type -dynamic_ip4_changed(const char *lsp_addrs, - struct dynamic_address_update *update) -{ - const struct ipam_info *ipam = &update->op->od->ipam_info; - const struct lport_addresses *cur_addresses = &update->current_addresses; - bool dynamic_ip4 = ipam->allocated_ipv4s != NULL; - - if (!dynamic_ip4) { - if (update->current_addresses.n_ipv4_addrs) { - return REMOVE; - } else { - return NONE; - } - } - - if (!cur_addresses->n_ipv4_addrs) { - /* IPv4 was previously static but now is dynamic */ - return DYNAMIC; - } - - uint32_t ip4 = ntohl(cur_addresses->ipv4_addrs[0].addr); - if (ip4 < ipam->start_ipv4) { - return DYNAMIC; - } - - uint32_t index = ip4 - ipam->start_ipv4; - if (index >= ipam->total_ipv4s - 1 || - bitmap_is_set(ipam->allocated_ipv4s, index)) { - /* Previously assigned dynamic IPv4 address can no longer be used. - * It's either outside the subnet, conflicts with an excluded IP, - * or conflicts with a statically-assigned address on the switch - */ - return DYNAMIC; - } else { - char ipv6_s[IPV6_SCAN_LEN + 1]; - ovs_be32 new_ip; - int n = 0; - - if ((ovs_scan(lsp_addrs, "dynamic "IP_SCAN_FMT"%n", - IP_SCAN_ARGS(&new_ip), &n) - && lsp_addrs[n] == '\0') || - (ovs_scan(lsp_addrs, "dynamic "IP_SCAN_FMT" "IPV6_SCAN_FMT"%n", - IP_SCAN_ARGS(&new_ip), ipv6_s, &n) - && lsp_addrs[n] == '\0')) { - index = ntohl(new_ip) - ipam->start_ipv4; - if (ntohl(new_ip) < ipam->start_ipv4 || - index > ipam->total_ipv4s || - bitmap_is_set(ipam->allocated_ipv4s, index)) { - /* new static ip is not valid */ - return DYNAMIC; - } else if (cur_addresses->ipv4_addrs[0].addr != new_ip) { - update->ipv4 = STATIC; - update->static_ip = new_ip; - return STATIC; - } - } - return NONE; - } -} - -static enum dynamic_update_type -dynamic_ip6_changed(const char *lsp_addrs, - struct dynamic_address_update *update) -{ - bool dynamic_ip6 = update->op->od->ipam_info.ipv6_prefix_set; - struct eth_addr ea; - - if (!dynamic_ip6) { - if (update->current_addresses.n_ipv6_addrs) { - /* IPv6 was dynamic but now is not */ - return REMOVE; - } else { - /* IPv6 has never been dynamic */ - return NONE; - } - } - - if (!update->current_addresses.n_ipv6_addrs || - ovs_scan(lsp_addrs, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(ea))) { - /* IPv6 was previously static but now is dynamic */ - return DYNAMIC; - } - - const struct lport_addresses *cur_addresses; - char ipv6_s[IPV6_SCAN_LEN + 1]; - ovs_be32 new_ip; - int n = 0; - - if ((ovs_scan(lsp_addrs, "dynamic "IPV6_SCAN_FMT"%n", - ipv6_s, &n) && lsp_addrs[n] == '\0') || - (ovs_scan(lsp_addrs, "dynamic "IP_SCAN_FMT" "IPV6_SCAN_FMT"%n", - IP_SCAN_ARGS(&new_ip), ipv6_s, &n) - && lsp_addrs[n] == '\0')) { - struct in6_addr ipv6; - - if (!ipv6_parse(ipv6_s, &ipv6)) { - return DYNAMIC; - } - - struct in6_addr masked = ipv6_addr_bitand(&ipv6, - &update->op->od->ipam_info.ipv6_prefix); - if (!IN6_ARE_ADDR_EQUAL(&masked, - &update->op->od->ipam_info.ipv6_prefix)) { - return DYNAMIC; - } - - cur_addresses = &update->current_addresses; - - if (!IN6_ARE_ADDR_EQUAL(&cur_addresses->ipv6_addrs[0].addr, - &ipv6)) { - update->static_ipv6 = ipv6; - return STATIC; - } - } else if (update->mac != NONE) { - return DYNAMIC; - } - - return NONE; -} - -/* Check previously assigned dynamic addresses for validity. This will - * check if the assigned addresses need to change. - * - * Returns true if any changes to dynamic addresses are required - */ -static bool -dynamic_addresses_check_for_updates(const char *lsp_addrs, - struct dynamic_address_update *update) -{ - update->mac = dynamic_mac_changed(lsp_addrs, update); - update->ipv4 = dynamic_ip4_changed(lsp_addrs, update); - update->ipv6 = dynamic_ip6_changed(lsp_addrs, update); - if (update->mac == NONE && - update->ipv4 == NONE && - update->ipv6 == NONE) { - return false; - } else { - return true; - } -} -/* For addresses that do not need to be updated, go ahead and insert them - * into IPAM. This way, their addresses will be claimed and cannot be assigned - * elsewhere later. - */ static void -update_unchanged_dynamic_addresses(struct dynamic_address_update *update) -{ - if (update->mac == NONE) { - ipam_insert_mac(&update->current_addresses.ea, false); - } - if (update->ipv4 == NONE && update->current_addresses.n_ipv4_addrs) { - ipam_insert_ip_for_datapath(update->op->od, - ntohl(update->current_addresses.ipv4_addrs[0].addr), - true); - } -} - -static void -set_lsp_dynamic_addresses(const char *dynamic_addresses, struct ovn_port *op) -{ - extract_lsp_addresses(dynamic_addresses, &op->lsp_addrs[op->n_lsp_addrs]); - op->n_lsp_addrs++; -} - -/* Determines which components (MAC, IPv4, and IPv6) of dynamic - * addresses need to be assigned. This is used exclusively for - * ports that do not have dynamic addresses already assigned. - */ -static void -set_dynamic_updates(const char *addrspec, - struct dynamic_address_update *update) -{ - bool has_ipv4 = false, has_ipv6 = false; - char ipv6_s[IPV6_SCAN_LEN + 1]; - struct eth_addr mac; - ovs_be32 ip; - int n = 0; - if (ovs_scan(addrspec, ETH_ADDR_SCAN_FMT" dynamic%n", - ETH_ADDR_SCAN_ARGS(mac), &n) - && addrspec[n] == '\0') { - update->mac = STATIC; - update->static_mac = mac; - } else { - update->mac = DYNAMIC; - } - - if ((ovs_scan(addrspec, "dynamic "IP_SCAN_FMT"%n", - IP_SCAN_ARGS(&ip), &n) && addrspec[n] == '\0')) { - has_ipv4 = true; - } else if ((ovs_scan(addrspec, "dynamic "IPV6_SCAN_FMT"%n", - ipv6_s, &n) && addrspec[n] == '\0')) { - has_ipv6 = true; - } else if ((ovs_scan(addrspec, "dynamic "IP_SCAN_FMT" "IPV6_SCAN_FMT"%n", - IP_SCAN_ARGS(&ip), ipv6_s, &n) - && addrspec[n] == '\0')) { - has_ipv4 = has_ipv6 = true; - } - - if (has_ipv4) { - update->ipv4 = STATIC; - update->static_ip = ip; - } else if (update->op->od->ipam_info.allocated_ipv4s) { - update->ipv4 = DYNAMIC; - } else { - update->ipv4 = NONE; - } - - if (has_ipv6 && ipv6_parse(ipv6_s, &update->static_ipv6)) { - update->ipv6 = STATIC; - } else if (update->op->od->ipam_info.ipv6_prefix_set) { - update->ipv6 = DYNAMIC; - } else { - update->ipv6 = NONE; - } -} - -static void -update_dynamic_addresses(struct dynamic_address_update *update) -{ - ovs_be32 ip4 = 0; - switch (update->ipv4) { - case NONE: - if (update->current_addresses.n_ipv4_addrs) { - ip4 = update->current_addresses.ipv4_addrs[0].addr; - } - break; - case REMOVE: - break; - case STATIC: - ip4 = update->static_ip; - break; - case DYNAMIC: - ip4 = htonl(ipam_get_unused_ip(&update->od->ipam_info)); - VLOG_INFO("Assigned dynamic IPv4 address '"IP_FMT"' to port '%s'", - IP_ARGS(ip4), update->op->nbsp->name); - } - - struct eth_addr mac; - switch (update->mac) { - case NONE: - mac = update->current_addresses.ea; - break; - case REMOVE: - OVS_NOT_REACHED(); - case STATIC: - mac = update->static_mac; - break; - case DYNAMIC: - eth_addr_from_uint64(ipam_get_unused_mac(ip4), &mac); - VLOG_INFO("Assigned dynamic MAC address '"ETH_ADDR_FMT"' to port '%s'", - ETH_ADDR_ARGS(mac), update->op->nbsp->name); - break; - } - - struct in6_addr ip6 = in6addr_any; - switch (update->ipv6) { - case NONE: - if (update->current_addresses.n_ipv6_addrs) { - ip6 = update->current_addresses.ipv6_addrs[0].addr; - } - break; - case REMOVE: - break; - case STATIC: - ip6 = update->static_ipv6; - break; - case DYNAMIC: - in6_generate_eui64(mac, &update->od->ipam_info.ipv6_prefix, &ip6); - struct ds ip6_ds = DS_EMPTY_INITIALIZER; - ipv6_format_addr(&ip6, &ip6_ds); - VLOG_INFO("Assigned dynamic IPv6 address '%s' to port '%s'", - ip6_ds.string, update->op->nbsp->name); - ds_destroy(&ip6_ds); - break; - } - - struct ds new_addr = DS_EMPTY_INITIALIZER; - ds_put_format(&new_addr, ETH_ADDR_FMT, ETH_ADDR_ARGS(mac)); - ipam_insert_mac(&mac, true); - - if (ip4) { - ipam_insert_ip_for_datapath(update->od, ntohl(ip4), true); - ds_put_format(&new_addr, " "IP_FMT, IP_ARGS(ip4)); - } - if (!IN6_ARE_ADDR_EQUAL(&ip6, &in6addr_any)) { - char ip6_s[INET6_ADDRSTRLEN + 1]; - ipv6_string_mapped(ip6_s, &ip6); - ds_put_format(&new_addr, " %s", ip6_s); - } - nbrec_logical_switch_port_set_dynamic_addresses(update->op->nbsp, - ds_cstr(&new_addr)); - set_lsp_dynamic_addresses(ds_cstr(&new_addr), update->op); - ds_destroy(&new_addr); -} - -static void -build_ipam(struct hmap *ls_datapaths, struct hmap *ls_ports) +build_ipam(struct hmap *ls_datapaths) { /* IPAM generally stands for IP address management. In non-virtualized * world, MAC addresses come with the hardware. But, with virtualized * workloads, they need to be assigned and managed. This function * does both IP address management (ipam) and MAC address management * (macam). */ + struct vector updates = + VECTOR_EMPTY_INITIALIZER(struct dynamic_address_update); /* If the switch's other_config:subnet is set, allocate new addresses for * ports that have the "dynamic" keyword in their addresses column. */ struct ovn_datapath *od; - struct ovs_list updates; - - ovs_list_init(&updates); HMAP_FOR_EACH (od, key_node, ls_datapaths) { - ovs_assert(od->nbs); - - for (size_t i = 0; i < od->nbs->n_ports; i++) { - const struct nbrec_logical_switch_port *nbsp = od->nbs->ports[i]; - - if (!od->ipam_info.allocated_ipv4s && - !od->ipam_info.ipv6_prefix_set && - !od->ipam_info.mac_only) { - if (nbsp->dynamic_addresses) { - nbrec_logical_switch_port_set_dynamic_addresses(nbsp, - NULL); - } - continue; - } - - struct ovn_port *op = ovn_port_find(ls_ports, nbsp->name); - if (!op || op->nbsp != nbsp || op->peer) { - /* Do not allocate addresses for logical switch ports that - * have a peer. */ - continue; - } - - int num_dynamic_addresses = 0; - for (size_t j = 0; j < nbsp->n_addresses; j++) { - if (!is_dynamic_lsp_address(nbsp->addresses[j])) { - continue; - } - if (num_dynamic_addresses) { - static struct vlog_rate_limit rl - = VLOG_RATE_LIMIT_INIT(1, 1); - VLOG_WARN_RL(&rl, "More than one dynamic address " - "configured for logical switch port '%s'", - nbsp->name); - continue; - } - num_dynamic_addresses++; - struct dynamic_address_update *update - = xzalloc(sizeof *update); - update->op = op; - update->od = od; - if (nbsp->dynamic_addresses) { - bool any_changed; - extract_lsp_addresses(nbsp->dynamic_addresses, - &update->current_addresses); - any_changed = dynamic_addresses_check_for_updates( - nbsp->addresses[j], update); - update_unchanged_dynamic_addresses(update); - if (any_changed) { - ovs_list_push_back(&updates, &update->node); - } else { - /* No changes to dynamic addresses */ - set_lsp_dynamic_addresses(nbsp->dynamic_addresses, op); - destroy_lport_addresses(&update->current_addresses); - free(update); - } - } else { - set_dynamic_updates(nbsp->addresses[j], update); - ovs_list_push_back(&updates, &update->node); - } - } - - if (!num_dynamic_addresses && nbsp->dynamic_addresses) { - nbrec_logical_switch_port_set_dynamic_addresses(nbsp, NULL); - } - } - + update_ipam_ls(od, &updates, true); } - /* After retaining all unchanged dynamic addresses, now assign * new ones. */ struct dynamic_address_update *update; - LIST_FOR_EACH_POP (update, node, &updates) { + VECTOR_FOR_EACH_PTR (&updates, update) { update_dynamic_addresses(update); destroy_lport_addresses(&update->current_addresses); - free(update); } + vector_destroy(&updates); } /* Tag allocation for nested containers. @@ -19497,7 +19014,7 @@ ovnnb_db_run(struct northd_input *input_data, build_lb_count_dps(&data->lb_datapaths_map, ods_size(&data->ls_datapaths), ods_size(&data->lr_datapaths)); - build_ipam(&data->ls_datapaths.datapaths, &data->ls_ports); + build_ipam(&data->ls_datapaths.datapaths); build_lrouter_groups(&data->lr_ports, &data->lr_datapaths); build_ip_mcast(ovnsb_txn, input_data->sbrec_ip_multicast_table, input_data->sbrec_ip_mcast_by_dp, -- 2.34.1 -- _'Esta mensagem é direcionada apenas para os endereços constantes no cabeçalho inicial. Se você não está listado nos endereços constantes no cabeçalho, pedimos-lhe que desconsidere completamente o conteúdo dessa mensagem e cuja cópia, encaminhamento e/ou execução das ações citadas estão imediatamente anuladas e proibidas'._ * **'Apesar do Magazine Luiza tomar todas as precauções razoáveis para assegurar que nenhum vírus esteja presente nesse e-mail, a empresa não poderá aceitar a responsabilidade por quaisquer perdas ou danos causados por esse e-mail ou por seus anexos'.* _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev