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

Reply via email to