On Fri, Jul 25, 2025 at 2:34 PM Lucas Vargas Dias via dev < ovs-dev@openvswitch.org> wrote:
> 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> > --- > Thank you Lucas, there are some minor comments that took care of during merge. > 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..ad3e03839 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 > *); > nit: The return type and function name should be on the same line. > + > +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; > + } > + > + bool num_dynamic_addresses = false; > nit: The name is strange for bool. I have changed it to 'has_dynamic_address'. > + 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 = true; > + 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 > > I went ahead and merged it to main with the changes. Regards, Ales _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev