summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ctdb/server/ctdb_takeover.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/ctdb/server/ctdb_takeover.c b/ctdb/server/ctdb_takeover.c
index b75e3593a2..0d1088023a 100644
--- a/ctdb/server/ctdb_takeover.c
+++ b/ctdb/server/ctdb_takeover.c
@@ -409,6 +409,124 @@ static int32_t ctdb_do_takeip(struct ctdb_context *ctdb,
return 0;
}
+struct ctdb_do_updateip_state {
+ struct ctdb_req_control *c;
+ struct ctdb_iface *old;
+ struct ctdb_vnn *vnn;
+};
+
+/*
+ called when updateip event finishes
+ */
+static void ctdb_do_updateip_callback(struct ctdb_context *ctdb, int status,
+ void *private_data)
+{
+ struct ctdb_do_updateip_state *state =
+ talloc_get_type(private_data, struct ctdb_do_updateip_state);
+ int32_t ret;
+
+ if (status != 0) {
+ if (status == -ETIME) {
+ ctdb_ban_self(ctdb);
+ }
+ DEBUG(DEBUG_ERR,(__location__ " Failed to move IP %s from interface %s to %s\n",
+ ctdb_addr_to_str(&state->vnn->public_address),
+ state->old->name,
+ ctdb_vnn_iface_string(state->vnn)));
+
+ /*
+ * All we can do is reset the old interface
+ * and let the next run fix it
+ */
+ ctdb_vnn_unassign_iface(ctdb, state->vnn);
+ state->vnn->iface = state->old;
+ state->vnn->iface->references++;
+
+ ctdb_request_control_reply(ctdb, state->c, NULL, status, NULL);
+ talloc_free(state);
+ return;
+ }
+
+ ret = ctdb_announce_vnn_iface(ctdb, state->vnn);
+ if (ret != 0) {
+ ctdb_request_control_reply(ctdb, state->c, NULL, -1, NULL);
+ talloc_free(state);
+ return;
+ }
+
+ /* the control succeeded */
+ ctdb_request_control_reply(ctdb, state->c, NULL, 0, NULL);
+ talloc_free(state);
+ return;
+}
+
+/*
+ update (move) an ip address
+ */
+static int32_t ctdb_do_updateip(struct ctdb_context *ctdb,
+ struct ctdb_req_control *c,
+ struct ctdb_vnn *vnn)
+{
+ int ret;
+ struct ctdb_do_updateip_state *state;
+ struct ctdb_iface *old = vnn->iface;
+
+ ctdb_vnn_unassign_iface(ctdb, vnn);
+ ret = ctdb_vnn_assign_iface(ctdb, vnn);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR,("update of IP %s/%u failed to "
+ "assin a usable interface (old iface '%s')\n",
+ ctdb_addr_to_str(&vnn->public_address),
+ vnn->public_netmask_bits,
+ old->name));
+ return -1;
+ }
+
+ if (vnn->iface == old) {
+ DEBUG(DEBUG_ERR,("update of IP %s/%u trying to "
+ "assin a same interface '%s'\n",
+ ctdb_addr_to_str(&vnn->public_address),
+ vnn->public_netmask_bits,
+ old->name));
+ return -1;
+ }
+
+ state = talloc(vnn, struct ctdb_do_updateip_state);
+ CTDB_NO_MEMORY(ctdb, state);
+
+ state->c = talloc_steal(ctdb, c);
+ state->old = old;
+ state->vnn = vnn;
+
+ DEBUG(DEBUG_NOTICE,("Update of IP %s/%u from "
+ "interface %s to %s\n",
+ ctdb_addr_to_str(&vnn->public_address),
+ vnn->public_netmask_bits,
+ old->name,
+ ctdb_vnn_iface_string(vnn)));
+
+ ret = ctdb_event_script_callback(ctdb,
+ state,
+ ctdb_do_updateip_callback,
+ state,
+ false,
+ CTDB_EVENT_UPDATE_IP,
+ "%s %s %s %u",
+ state->old->name,
+ ctdb_vnn_iface_string(vnn),
+ ctdb_addr_to_str(&vnn->public_address),
+ vnn->public_netmask_bits);
+ if (ret != 0) {
+ DEBUG(DEBUG_ERR,(__location__ " Failed update IP %s from interface %s to %s\n",
+ ctdb_addr_to_str(&vnn->public_address),
+ old->name, ctdb_vnn_iface_string(vnn)));
+ talloc_free(state);
+ return -1;
+ }
+
+ return 0;
+}
+
/*
Find the vnn of the node that has a public ip address
returns -1 if the address is not known as a public address
@@ -438,6 +556,7 @@ int32_t ctdb_control_takeover_ip(struct ctdb_context *ctdb,
struct ctdb_public_ip *pip = (struct ctdb_public_ip *)indata.dptr;
struct ctdb_vnn *vnn;
bool have_ip = false;
+ bool do_updateip = false;
bool do_takeip = false;
/* update out vnn list */
@@ -450,7 +569,25 @@ int32_t ctdb_control_takeover_ip(struct ctdb_context *ctdb,
vnn->pnn = pip->pnn;
have_ip = ctdb_sys_have_ip(&pip->addr);
+
+ if (vnn->iface) {
+ if (vnn->iface->link_up) {
+ struct ctdb_iface *best;
+ best = ctdb_vnn_best_iface(ctdb, vnn);
+ /* only move when the rebalance gains something */
+ if (best && vnn->iface->references > (best->references + 1)) {
+ do_updateip = true;
+ }
+ } else if (vnn->iface != best_iface) {
+ do_updateip = true;
+ }
+ }
+
if (!have_ip) {
+ if (do_updateip) {
+ ctdb_vnn_unassign_iface(ctdb, vnn);
+ do_updateip = false;
+ }
do_takeip = true;
}
@@ -459,6 +596,11 @@ int32_t ctdb_control_takeover_ip(struct ctdb_context *ctdb,
if (ret != 0) {
return -1;
}
+ } else if (do_updateip) {
+ ret = ctdb_do_updateip(ctdb, c, vnn);
+ if (ret != 0) {
+ return -1;
+ }
} else {
/*
* The interface is up and the kernel known the ip