The IPAM is keeping track of used addresses for given LS to avoid
conflicts and potentially assigning already used address to the
next LSP. However during I-P the IPAM was destroyed and created
again from scratch without adding back the already used IPs. Make
sure we add those IPs back.

Fixes: 31c704a388a7 ("northd: Incremental processing of LSPs IPAM in "northd" 
node.")
Reported-at: https://issues.redhat.com/browse/FDP-2982
Signed-off-by: Ales Musil <[email protected]>
---
 northd/ipam.c       | 79 ++++++++++++++-------------------------------
 northd/ipam.h       |  4 ++-
 northd/northd.c     | 12 ++++++-
 tests/ovn-macros.at | 11 +++++++
 tests/ovn-northd.at | 31 ++++++++++++++++++
 tests/ovn.at        | 16 ++++-----
 6 files changed, 89 insertions(+), 64 deletions(-)

diff --git a/northd/ipam.c b/northd/ipam.c
index a1801e554..5f80649c5 100644
--- a/northd/ipam.c
+++ b/northd/ipam.c
@@ -24,11 +24,6 @@ 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 *);
 
@@ -109,17 +104,6 @@ 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)
 {
@@ -568,7 +552,7 @@ update_unchanged_dynamic_addresses(struct 
dynamic_address_update *update)
         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,
+        ipam_insert_ip(&update->op->od->ipam_info,
                        ntohl(update->current_addresses.ipv4_addrs[0].addr),
                        true);
     }
@@ -698,7 +682,7 @@ update_dynamic_addresses(struct dynamic_address_update 
*update)
     ipam_insert_mac(&mac, true);
 
     if (ip4) {
-        ipam_insert_ip_for_datapath(update->od, ntohl(ip4), true);
+        ipam_insert_ip(&update->od->ipam_info, ntohl(ip4), true);
         ds_put_format(&new_addr, " "IP_FMT, IP_ARGS(ip4));
     }
     if (!IN6_ARE_ADDR_EQUAL(&ip6, &in6addr_any)) {
@@ -783,54 +767,41 @@ update_ipam_ls(struct ovn_datapath *od, struct vector 
*updates,
     }
 }
 
-void
-ipam_add_port_addresses(struct ovn_datapath *od, struct ovn_port *op)
+static void
+ipam_add_lport_addresses(struct ipam_info *info,
+                         const struct lport_addresses *laddrs)
 {
-    if (!od || !op) {
-        return;
+    for (size_t j = 0; j < laddrs->n_ipv4_addrs; j++) {
+        ipam_insert_ip(info, ntohl(laddrs->ipv4_addrs[j].addr), false);
     }
+}
+
+void
+ipam_add_lsp_port_addresses(struct ovn_port *op, bool check_mac_duplicate)
+{
+    ovs_assert(op->nbsp);
+
+    struct ipam_info *info = &op->od->ipam_info;
 
     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;
+            ipam_insert_mac(&op->lsp_addrs[i].ea, check_mac_duplicate);
+            ipam_add_lport_addresses(info, &op->lsp_addrs[i]);
         }
+    }
 
-        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);
-            }
-        }
+    if (op->peer && op->peer->nbrp) {
+        ipam_add_lport_addresses(info, &op->peer->lrp_networks);
     }
 }
 
-static void
-ipam_insert_lsp_addresses(struct ovn_datapath *od,
-                          struct lport_addresses *laddrs)
+void
+ipam_add_lrp_port_addresses(struct ovn_port *op)
 {
-    ipam_insert_mac(&laddrs->ea, true);
+    ovs_assert(op->nbrp);
 
-    /* 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);
+    if (op->lrp_networks.ea_s[0]) {
+        ipam_insert_mac(&op->lrp_networks.ea, true);
     }
 }
diff --git a/northd/ipam.h b/northd/ipam.h
index c825875a8..24dd23232 100644
--- a/northd/ipam.h
+++ b/northd/ipam.h
@@ -69,6 +69,8 @@ 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 *);
+void ipam_add_lrp_port_addresses(struct ovn_port *);
+
+void ipam_add_lsp_port_addresses(struct ovn_port *, bool check_mac_duplicate);
 
 #endif /* NORTHD_IPAM_H */
diff --git a/northd/northd.c b/northd/northd.c
index 983975dac..b1371e4bf 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -2034,7 +2034,11 @@ join_logical_ports(const struct sbrec_port_binding_table 
*sbrec_pb_table,
      * it relies on proper peers to be set
      */
     HMAP_FOR_EACH (op, key_node, ports) {
-        ipam_add_port_addresses(op->od, op);
+        if (op->nbsp) {
+            ipam_add_lsp_port_addresses(op, true);
+        } else if (op->nbrp) {
+            ipam_add_lrp_port_addresses(op);
+        }
     }
 }
 
@@ -5217,6 +5221,12 @@ bool northd_handle_ipam_changes(struct northd_data *nd)
             od->ipam_info_initialized = false;
         }
         init_ipam_info_for_datapath(od);
+
+        struct ovn_port *op;
+        HMAP_FOR_EACH (op, dp_node, &od->ports) {
+            ipam_add_lsp_port_addresses(op, false);
+        }
+
         update_ipam_ls(od, &updates, false);
     }
 
diff --git a/tests/ovn-macros.at b/tests/ovn-macros.at
index 8e77be3af..aeb4149d5 100644
--- a/tests/ovn-macros.at
+++ b/tests/ovn-macros.at
@@ -1442,6 +1442,17 @@ restart_ovsdb_controller_updates() {
   AT_CHECK([nft delete table ip ovn-test])
 }
 
+sleep_nb() {
+  echo NB going to sleep
+  AT_CHECK([kill -STOP $(cat ovn-nb/ovsdb-server.pid)])
+  on_exit "test -e ovn-nb/ovsdb-server.pid && kill -CONT $(cat 
ovn-nb/ovsdb-server.pid)"
+}
+
+wake_up_nb() {
+  echo NB waking up
+  AT_CHECK([kill -CONT $(cat ovn-nb/ovsdb-server.pid)])
+}
+
 trim_zeros() {
     sed 's/\(00\)\{1,\}$//'
 }
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index e29f6d7b5..a7cfc15ea 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -19902,3 +19902,34 @@ check ovn-nbctl --wait=sb lsp-set-addresses lport1 
"f0:00:0f:01:02:04 192.168.0.
 check_row_count sb:Service_Monitor 2
 
 AT_CLEANUP
+
+AT_SETUP([ipam router ports - incremental processing])
+ovn_start
+check ovn-nbctl ls-add sw
+check ovn-nbctl set logical_switch sw other-config:subnet=192.168.1.0/24
+for i in 2 3 4; do
+    check ovn-nbctl lr-add ro$i
+    check ovn-nbctl lsp-add sw swp$i
+    check ovn-nbctl --wait=sb sync
+
+    sleep_northd
+    check ovn-nbctl lsp-set-addresses swp$i "02:00:00:00:00:0$i dynamic"
+    sleep_nb
+
+
+    wake_up_northd
+    sleep_northd
+
+    wake_up_nb
+    cidr=$(ovn-nbctl get logical_switch_port swp$i dynamic_addresses |cut -f2 
-d' '|cut -f1 -d\")
+    wake_up_northd
+
+    check ovn-nbctl --wait=sb lrp-add ro$i rop$i 02:00:00:00:00:0$i $cidr/24 \
+        -- set logical_switch_port swp$i type=router \
+           options:router-port=rop$i addresses=router
+    AT_CHECK_UNQUOTED([ovn-nbctl get logical_router_port rop$i networks], [0], 
[[["192.168.1.$i/24"]]
+])
+done
+
+OVN_CLEANUP_NORTHD
+AT_CLEANUP
diff --git a/tests/ovn.at b/tests/ovn.at
index 9082bba82..979c6d192 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -9335,7 +9335,7 @@ done
 # and addresses set by the user.
 check ovn-nbctl lsp-set-addresses p0 "0a:00:00:a8:01:17 192.168.1.2 
192.168.1.12 192.168.1.14"
 check ovn-nbctl --wait=sb lsp-add sw0 p20 -- lsp-set-addresses p20 dynamic
-check_dynamic_addresses p20 "0a:00:00:a8:01:03 192.168.1.13"
+check_dynamic_addresses p20 "0a:00:00:a8:01:18 192.168.1.13"
 
 # Test for logical router port address management.
 check_uuid ovn-nbctl create Logical_Router name=R1
@@ -9344,12 +9344,12 @@ network="192.168.1.1/24" mac=\"0a:00:00:a8:01:19\" \
 -- add Logical_Router R1 ports @lrp -- lsp-add sw0 rp-sw0 \
 -- set Logical_Switch_Port rp-sw0 type=router options:router-port=sw0
 check ovn-nbctl --wait=sb lsp-add sw0 p21 -- lsp-set-addresses p21 dynamic
-check_dynamic_addresses p21 "0a:00:00:a8:01:18 192.168.1.15"
+check_dynamic_addresses p21 "0a:00:00:a8:01:1a 192.168.1.15"
 
 # Test for address reuse after logical port is deleted.
 check ovn-nbctl lsp-del p0
 check ovn-nbctl --wait=sb lsp-add sw0 p23 -- lsp-set-addresses p23 dynamic
-check_dynamic_addresses p23 "0a:00:00:a8:01:1a 192.168.1.2"
+check_dynamic_addresses p23 "0a:00:00:a8:01:03 192.168.1.2"
 
 # Test for multiple addresses to one logical port.
 check ovn-nbctl lsp-add sw0 p25 -- lsp-set-addresses p25 \
@@ -9409,19 +9409,19 @@ check_dynamic_addresses p33 "0a:00:00:a8:01:1f 
192.168.1.22"
 check ovn-nbctl --wait=sb lsp-add sw0 p34 -- lsp-set-addresses p34 \
 "dynamic"
 # 192.168.1.51 should be assigned as 192.168.1.23-192.168.1.50 is excluded.
-check_dynamic_addresses p34 "0a:00:00:a8:01:20 192.168.1.51"
+check_dynamic_addresses p34 "0a:00:00:a8:01:34 192.168.1.51"
 
 # Now clear the exclude_ips list. 192.168.1.19 should be assigned.
 check ovn-nbctl --wait=sb set Logical-switch sw0 
other_config:exclude_ips="invalid"
 check ovn-nbctl --wait=sb lsp-add sw0 p35 -- lsp-set-addresses p35 "dynamic"
-check_dynamic_addresses p35 "0a:00:00:a8:01:21 192.168.1.19"
+check_dynamic_addresses p35 "0a:00:00:a8:01:20 192.168.1.19"
 
 # Set invalid data in exclude_ips list. It should be ignored.
 check ovn-nbctl --wait=sb set Logical-switch sw0 
other_config:exclude_ips="182.168.1.30"
 check ovn-nbctl --wait=sb lsp-add sw0 p36 -- lsp-set-addresses p36 \
 "dynamic"
 # 192.168.1.21 should be assigned as that's the next free one.
-check_dynamic_addresses p36 "0a:00:00:a8:01:22 192.168.1.21"
+check_dynamic_addresses p36 "0a:00:00:a8:01:21 192.168.1.21"
 
 # Clear the dynamic addresses assignment request.
 check ovn-nbctl --wait=sb clear logical_switch_port p36 addresses
@@ -9433,7 +9433,7 @@ check ovn-nbctl --wait=sb lsp-add sw0 p37 -- 
lsp-set-addresses p37 "dynamic"
 
 # With prefix aef0 and mac 0a:00:00:00:00:26, the dynamic IPv6 should be
 # - aef0::800:ff:fe00:26 (EUI64)
-check_dynamic_addresses p37 "0a:00:00:a8:01:22 192.168.1.21 
aef0::800:ff:fea8:122"
+check_dynamic_addresses p37 "0a:00:00:a8:01:21 192.168.1.21 
aef0::800:ff:fea8:121"
 
 check ovn-nbctl --wait=sb ls-add sw4
 check ovn-nbctl --wait=sb set Logical-switch sw4 
other_config:ipv6_prefix="bef0::" \
@@ -9463,7 +9463,7 @@ check_dynamic_addresses p41 ''
 
 # Set a subnet. Now p41 should have an ipv4 address, too
 check ovn-nbctl --wait=sb add Logical-Switch sw5 other_config 
subnet=192.168.1.0/24
-check_dynamic_addresses p41 "0a:00:00:a8:01:23 192.168.1.2"
+check_dynamic_addresses p41 "0a:00:00:a8:01:22 192.168.1.2"
 
 # Clear the other_config. The IPv4 address should be gone
 check ovn-nbctl --wait=sb clear Logical-Switch sw5 other_config
-- 
2.53.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to