ctdb-ipalloc: Move create_merged_ip_list() into ipalloc
authorMartin Schwenke <martin@meltin.net>
Mon, 23 May 2016 10:23:18 +0000 (20:23 +1000)
committerAmitay Isaacs <amitay@samba.org>
Mon, 4 Jul 2016 13:42:25 +0000 (15:42 +0200)
How the existing IP layout is constructed and how the merged IP list is
sorted are important aspects of the IP allocation algorithm.  Construct the
merged IP list when known and available IPs are assigned.

Signed-off-by: Martin Schwenke <martin@meltin.net>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
ctdb/server/ctdb_takeover.c
ctdb/server/ipalloc.c
ctdb/tests/src/ctdb_takeover_tests.c

index b40bbad..c45b218 100644 (file)
@@ -1129,31 +1129,6 @@ int ctdb_set_public_addresses(struct ctdb_context *ctdb, bool check_addresses)
        return 0;
 }
 
-static void *add_ip_callback(void *parm, void *data)
-{
-       struct public_ip_list *this_ip = parm;
-       struct public_ip_list *prev_ip = data;
-
-       if (prev_ip == NULL) {
-               return parm;
-       }
-       if (this_ip->pnn == -1) {
-               this_ip->pnn = prev_ip->pnn;
-       }
-
-       return parm;
-}
-
-static int getips_count_callback(void *param, void *data)
-{
-       struct public_ip_list **ip_list = (struct public_ip_list **)param;
-       struct public_ip_list *new_ip = (struct public_ip_list *)data;
-
-       new_ip->next = *ip_list;
-       *ip_list     = new_ip;
-       return 0;
-}
-
 static struct ctdb_public_ip_list *
 ctdb_fetch_remote_public_ips(struct ctdb_context *ctdb,
                             TALLOC_CTX *mem_ctx,
@@ -1210,61 +1185,6 @@ ctdb_fetch_remote_public_ips(struct ctdb_context *ctdb,
        return public_ips;
 }
 
-static struct public_ip_list *
-create_merged_ip_list(struct ipalloc_state *ipalloc_state)
-{
-       int i, j;
-       struct public_ip_list *ip_list;
-       struct ctdb_public_ip_list *public_ips;
-       struct trbt_tree *ip_tree;
-
-       ip_tree = trbt_create(ipalloc_state, 0);
-
-       if (ipalloc_state->known_public_ips == NULL) {
-               DEBUG(DEBUG_ERR, ("Known public IPs not set\n"));
-               return NULL;
-       }
-
-       for (i=0; i < ipalloc_state->num; i++) {
-
-               public_ips = &ipalloc_state->known_public_ips[i];
-
-               for (j=0; j < public_ips->num; j++) {
-                       struct public_ip_list *tmp_ip;
-
-                       /* This is returned as part of ip_list */
-                       tmp_ip = talloc_zero(ipalloc_state, struct public_ip_list);
-                       if (tmp_ip == NULL) {
-                               DEBUG(DEBUG_ERR,
-                                     (__location__ " out of memory\n"));
-                               talloc_free(ip_tree);
-                               return NULL;
-                       }
-
-                       /* Do not use information about IP addresses hosted
-                        * on other nodes, it may not be accurate */
-                       if (public_ips->ip[j].pnn == i) {
-                               tmp_ip->pnn = public_ips->ip[j].pnn;
-                       } else {
-                               tmp_ip->pnn = -1;
-                       }
-                       tmp_ip->addr = public_ips->ip[j].addr;
-                       tmp_ip->next = NULL;
-
-                       trbt_insertarray32_callback(ip_tree,
-                               IP_KEYLEN, ip_key(&public_ips->ip[j].addr),
-                               add_ip_callback,
-                               tmp_ip);
-               }
-       }
-
-       ip_list = NULL;
-       trbt_traversearray32(ip_tree, IP_KEYLEN, getips_count_callback, &ip_list);
-       talloc_free(ip_tree);
-
-       return ip_list;
-}
-
 static bool all_nodes_are_disabled(struct ctdb_node_map_old *nodemap)
 {
        int i;
@@ -1624,7 +1544,6 @@ static void takeover_run_process_failures(struct ctdb_context *ctdb,
  * - Use ipalloc_set_public_ips() to set known and available IP
      addresses for allocation
  * - If no available IP addresses then early exit
- * - Build list of (known IPs, currently assigned node)
  * - Populate list of nodes to force rebalance - internal structure,
  *   currently no way to fetch, only used by LCP2 for nodes that have
  *   had new IP addresses added
@@ -1717,23 +1636,15 @@ int ctdb_takeover_run(struct ctdb_context *ctdb, struct ctdb_node_map_old *nodem
                goto ipreallocated;
        }
 
-       /* since nodes only know about those public addresses that
-          can be served by that particular node, no single node has
-          a full list of all public addresses that exist in the cluster.
-          Walk over all node structures and create a merged list of
-          all public addresses that exist in the cluster.
-       */
-       all_ips = create_merged_ip_list(ipalloc_state);
-       if (all_ips == NULL) {
-               talloc_free(tmp_ctx);
-               return -1;
-       }
-       ipalloc_state->all_ips = all_ips;
-
        ipalloc_state->force_rebalance_nodes = force_rebalance_nodes;
 
        /* Do the IP reassignment calculations */
        ipalloc(ipalloc_state);
+       if (ipalloc_state->all_ips == NULL) {
+               talloc_free(tmp_ctx);
+               return -1;
+       }
+       all_ips = ipalloc_state->all_ips;
 
        /* Now tell all nodes to release any public IPs should not
         * host.  This will be a NOOP on nodes that don't currently
index fa2503d..d60da03 100644 (file)
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <talloc.h>
+
 #include "replace.h"
 #include "system/network.h"
 
 #include "lib/util/debug.h"
 
 #include "common/logging.h"
+#include "common/rb_tree.h"
 
 #include "server/ipalloc_private.h"
 
+static void *add_ip_callback(void *parm, void *data)
+{
+       struct public_ip_list *this_ip = parm;
+       struct public_ip_list *prev_ip = data;
+
+       if (prev_ip == NULL) {
+               return parm;
+       }
+       if (this_ip->pnn == -1) {
+               this_ip->pnn = prev_ip->pnn;
+       }
+
+       return parm;
+}
+
+static int getips_count_callback(void *param, void *data)
+{
+       struct public_ip_list **ip_list = (struct public_ip_list **)param;
+       struct public_ip_list *new_ip = (struct public_ip_list *)data;
+
+       new_ip->next = *ip_list;
+       *ip_list     = new_ip;
+       return 0;
+}
+
+/* Nodes only know about those public addresses that they are
+ * configured to serve and no individual node has a full list of all
+ * public addresses configured across the cluster.  Therefore, a
+ * merged list of all public addresses needs to be built so that IP
+ * allocation can be done. */
+static struct public_ip_list *
+create_merged_ip_list(struct ipalloc_state *ipalloc_state)
+{
+       int i, j;
+       struct public_ip_list *ip_list;
+       struct ctdb_public_ip_list *public_ips;
+       struct trbt_tree *ip_tree;
+
+       ip_tree = trbt_create(ipalloc_state, 0);
+
+       if (ipalloc_state->known_public_ips == NULL) {
+               DEBUG(DEBUG_ERR, ("Known public IPs not set\n"));
+               return NULL;
+       }
+
+       for (i=0; i < ipalloc_state->num; i++) {
+
+               public_ips = &ipalloc_state->known_public_ips[i];
+
+               for (j=0; j < public_ips->num; j++) {
+                       struct public_ip_list *tmp_ip;
+
+                       /* This is returned as part of ip_list */
+                       tmp_ip = talloc_zero(ipalloc_state, struct public_ip_list);
+                       if (tmp_ip == NULL) {
+                               DEBUG(DEBUG_ERR,
+                                     (__location__ " out of memory\n"));
+                               talloc_free(ip_tree);
+                               return NULL;
+                       }
+
+                       /* Do not use information about IP addresses hosted
+                        * on other nodes, it may not be accurate */
+                       if (public_ips->ip[j].pnn == i) {
+                               tmp_ip->pnn = public_ips->ip[j].pnn;
+                       } else {
+                               tmp_ip->pnn = -1;
+                       }
+                       tmp_ip->addr = public_ips->ip[j].addr;
+                       tmp_ip->next = NULL;
+
+                       trbt_insertarray32_callback(ip_tree,
+                               IP_KEYLEN, ip_key(&public_ips->ip[j].addr),
+                               add_ip_callback,
+                               tmp_ip);
+               }
+       }
+
+       ip_list = NULL;
+       trbt_traversearray32(ip_tree, IP_KEYLEN, getips_count_callback, &ip_list);
+       talloc_free(ip_tree);
+
+       return ip_list;
+}
+
 bool ipalloc_set_public_ips(struct ipalloc_state *ipalloc_state,
                            struct ctdb_public_ip_list *known_ips,
                            struct ctdb_public_ip_list *available_ips)
@@ -35,7 +123,9 @@ bool ipalloc_set_public_ips(struct ipalloc_state *ipalloc_state,
        ipalloc_state->known_public_ips = known_ips;
        ipalloc_state->available_public_ips = available_ips;
 
-       return true;
+       ipalloc_state->all_ips = create_merged_ip_list(ipalloc_state);
+
+       return (ipalloc_state->all_ips != NULL);
 }
 
 /* The calculation part of the IP allocation algorithm. */
index 162de2b..5189e25 100644 (file)
@@ -318,8 +318,6 @@ static void ctdb_test_init(const char nodestates[],
                             tval_noiptakeover,
                             tval_noiptakeoverondisabled);
 
-       (*ipalloc_state)->all_ips = create_merged_ip_list(*ipalloc_state);
-
        (*ipalloc_state)->force_rebalance_nodes = NULL;
 }