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

Reply via email to