#include "common/logging.h"
#include "common/rb_tree.h"
+#include "protocol/protocol_util.h"
+
#include "server/ipalloc_private.h"
+/* Initialise main ipalloc state and sub-structures */
+struct ipalloc_state *
+ipalloc_state_init(TALLOC_CTX *mem_ctx,
+ uint32_t num_nodes,
+ enum ipalloc_algorithm algorithm,
+ bool no_ip_takeover,
+ bool no_ip_failback,
+ bool no_ip_host_on_all_disabled,
+ uint32_t *force_rebalance_nodes)
+{
+ struct ipalloc_state *ipalloc_state =
+ talloc_zero(mem_ctx, struct ipalloc_state);
+ if (ipalloc_state == NULL) {
+ DEBUG(DEBUG_ERR, (__location__ " Out of memory\n"));
+ return NULL;
+ }
+
+ ipalloc_state->num = num_nodes;
+
+ ipalloc_state->noiphost = bitmap_talloc(ipalloc_state,
+ ipalloc_state->num);
+ if (ipalloc_state->noiphost == NULL) {
+ DEBUG(DEBUG_ERR, (__location__ " Out of memory\n"));
+ goto fail;
+ }
+
+ ipalloc_state->algorithm = algorithm;
+ ipalloc_state->no_ip_takeover = no_ip_takeover;
+ ipalloc_state->no_ip_failback = no_ip_failback;
+ ipalloc_state->no_ip_host_on_all_disabled = no_ip_host_on_all_disabled;
+ ipalloc_state->force_rebalance_nodes = force_rebalance_nodes;
+
+ return ipalloc_state;
+fail:
+ talloc_free(ipalloc_state);
+ return NULL;
+}
+
static void *add_ip_callback(void *parm, void *data)
{
struct public_ip_list *this_ip = parm;
* 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,
- struct ctdb_public_ip_list *known_ips)
+create_merged_ip_list(struct ipalloc_state *ipalloc_state)
{
int i, j;
struct public_ip_list *ip_list;
ip_tree = trbt_create(ipalloc_state, 0);
- if (known_ips == NULL) {
+ 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 = &known_ips[i];
+ public_ips = &ipalloc_state->known_public_ips[i];
for (j=0; j < public_ips->num; j++) {
struct public_ip_list *tmp_ip;
return ip_list;
}
-bool ipalloc_set_public_ips(struct ipalloc_state *ipalloc_state,
+static bool populate_bitmap(struct ipalloc_state *ipalloc_state)
+{
+ struct public_ip_list *ip = NULL;
+ int i, j;
+
+ for (ip = ipalloc_state->all_ips; ip != NULL; ip = ip->next) {
+
+ ip->known_on = bitmap_talloc(ip, ipalloc_state->num);
+ if (ip->known_on == NULL) {
+ return false;
+ }
+
+ ip->available_on = bitmap_talloc(ip, ipalloc_state->num);
+ if (ip->available_on == NULL) {
+ return false;
+ }
+
+ for (i = 0; i < ipalloc_state->num; i++) {
+ struct ctdb_public_ip_list *known =
+ &ipalloc_state->known_public_ips[i];
+ struct ctdb_public_ip_list *avail =
+ &ipalloc_state->available_public_ips[i];
+
+ /* Check to see if "ip" is available on node "i" */
+ for (j = 0; j < avail->num; j++) {
+ if (ctdb_sock_addr_same_ip(
+ &ip->addr, &avail->ip[j].addr)) {
+ bitmap_set(ip->available_on, i);
+ break;
+ }
+ }
+
+ /* Optimisation: available => known */
+ if (bitmap_query(ip->available_on, i)) {
+ bitmap_set(ip->known_on, i);
+ continue;
+ }
+
+ /* Check to see if "ip" is known on node "i" */
+ for (j = 0; j < known->num; j++) {
+ if (ctdb_sock_addr_same_ip(
+ &ip->addr, &known->ip[j].addr)) {
+ bitmap_set(ip->known_on, i);
+ break;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool all_nodes_are_disabled(struct ctdb_node_map *nodemap)
+{
+ int i;
+
+ for (i=0;i<nodemap->num;i++) {
+ if (!(nodemap->node[i].flags &
+ (NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED))) {
+ /* Found one completely healthy node */
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Set internal flags for IP allocation:
+ * Clear ip flags
+ * Set NOIPHOST ip flag for each INACTIVE node
+ * if all nodes are disabled:
+ * Set NOIPHOST ip flags from per-node NoIPHostOnAllDisabled tunable
+ * else
+ * Set NOIPHOST ip flags for disabled nodes
+ */
+void ipalloc_set_node_flags(struct ipalloc_state *ipalloc_state,
+ struct ctdb_node_map *nodemap)
+{
+ int i;
+ bool all_disabled = all_nodes_are_disabled(nodemap);
+
+ for (i=0;i<nodemap->num;i++) {
+ /* Can not host IPs on INACTIVE node */
+ if (nodemap->node[i].flags & NODE_FLAGS_INACTIVE) {
+ bitmap_set(ipalloc_state->noiphost, i);
+ }
+
+ /* If node is disabled then it can only host IPs if
+ * all nodes are disabled and NoIPHostOnAllDisabled is
+ * unset
+ */
+ if (nodemap->node[i].flags & NODE_FLAGS_DISABLED) {
+ if (!(all_disabled &&
+ ipalloc_state->no_ip_host_on_all_disabled == 0)) {
+
+ bitmap_set(ipalloc_state->noiphost, i);
+ }
+ }
+ }
+}
+
+void ipalloc_set_public_ips(struct ipalloc_state *ipalloc_state,
struct ctdb_public_ip_list *known_ips,
struct ctdb_public_ip_list *available_ips)
{
ipalloc_state->available_public_ips = available_ips;
-
- ipalloc_state->all_ips = create_merged_ip_list(ipalloc_state,
- known_ips);
-
- return (ipalloc_state->all_ips != NULL);
+ ipalloc_state->known_public_ips = known_ips;
}
/* This can only return false if there are no available IPs *and*
bool ipalloc_can_host_ips(struct ipalloc_state *ipalloc_state)
{
int i;
- struct public_ip_list *ip_list;
-
+ bool have_ips = false;
- for (ip_list = ipalloc_state->all_ips;
- ip_list != NULL;
- ip_list = ip_list->next) {
- if (ip_list->pnn != -1) {
- return true;
+ for (i=0; i < ipalloc_state->num; i++) {
+ struct ctdb_public_ip_list *ips =
+ ipalloc_state->known_public_ips;
+ if (ips[i].num != 0) {
+ int j;
+ have_ips = true;
+ /* Succeed if an address is hosted on node i */
+ for (j=0; j < ips[i].num; j++) {
+ if (ips[i].ip[j].pnn == i) {
+ return true;
+ }
+ }
}
}
+ if (! have_ips) {
+ return false;
+ }
+
+ /* At this point there are known addresses but none are
+ * hosted. Need to check if cluster can now host some
+ * addresses.
+ */
for (i=0; i < ipalloc_state->num; i++) {
if (ipalloc_state->available_public_ips[i].num != 0) {
return true;
}
/* The calculation part of the IP allocation algorithm. */
-bool ipalloc(struct ipalloc_state *ipalloc_state)
+struct public_ip_list *ipalloc(struct ipalloc_state *ipalloc_state)
{
bool ret = false;
+ ipalloc_state->all_ips = create_merged_ip_list(ipalloc_state);
+ if (ipalloc_state->all_ips == NULL) {
+ return NULL;
+ }
+
+ if (!populate_bitmap(ipalloc_state)) {
+ return NULL;
+ }
+
switch (ipalloc_state->algorithm) {
case IPALLOC_LCP2:
ret = ipalloc_lcp2(ipalloc_state);
or -1 if there is no node that can cover this ip
*/
- return ret;
+ return (ret ? ipalloc_state->all_ips : NULL);
}