[SCM] CTDB repository - branch master updated - ctdb-2.0-28-g1a5410e

Amitay Isaacs amitay at samba.org
Sun Jan 6 21:16:37 MST 2013


The branch, master has been updated
       via  1a5410e8349cdb96fdc51aa5ecd4f5734f6798a5 (commit)
       via  8164d9b29bf9080ccc76b1305fb6c07f1ed61d55 (commit)
       via  cc1a3ae911d3fee8b87fda5de5ab6d9499d7510a (commit)
      from  b849fb4923d6a34141fe19006a974de81508ceda (commit)

http://gitweb.samba.org/?p=ctdb.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 1a5410e8349cdb96fdc51aa5ecd4f5734f6798a5
Author: Martin Schwenke <martin at meltin.net>
Date:   Fri Nov 30 16:38:08 2012 +1100

    tests: new simple integration test for delip interface garbage collection
    
    Signed-off-by: Martin Schwenke <martin at meltin.net>

commit 8164d9b29bf9080ccc76b1305fb6c07f1ed61d55
Author: Martin Schwenke <martin at meltin.net>
Date:   Fri Nov 30 16:37:28 2012 +1100

    tests: new function ip2ipmask() for integration testing
    
    Signed-off-by: Martin Schwenke <martin at meltin.net>

commit cc1a3ae911d3fee8b87fda5de5ab6d9499d7510a
Author: Martin Schwenke <martin at meltin.net>
Date:   Fri Nov 23 20:09:07 2012 +1100

    ctdbd: Clean up orphaned interfaces when an IP is deleted
    
    Add a new function ctdb_remove_orphaned_ifaces() and call it in
    ctdb_control_del_public_address().
    
    ctdb_remove_orphaned_ifaces() uses a naive implementation that does
    things in a very obvious way.  There are many ways to improve the
    performance - some are mentioned in a comment in the code.  However, I
    doubt that this will be a bottleneck even with a large number of
    public IPs.  Running the eventscript is likely to outweigh the cost of
    this cleanup.
    
    Signed-off-by: Martin Schwenke <martin at meltin.net>
    Pair-programmed-with: Amitay Isaacs <amitay at gmail.com>

-----------------------------------------------------------------------

Summary of changes:
 server/ctdb_takeover.c            |   76 +++++++++++++++++++++++++++++++++++--
 tests/scripts/integration.bash    |    7 +++
 tests/simple/20_delip_iface_gc.sh |   62 ++++++++++++++++++++++++++++++
 3 files changed, 141 insertions(+), 4 deletions(-)
 create mode 100755 tests/simple/20_delip_iface_gc.sh


Changeset truncated at 500 lines:

diff --git a/server/ctdb_takeover.c b/server/ctdb_takeover.c
index 5345251..df543fe 100644
--- a/server/ctdb_takeover.c
+++ b/server/ctdb_takeover.c
@@ -85,6 +85,74 @@ static int ctdb_add_local_iface(struct ctdb_context *ctdb, const char *iface)
 	return 0;
 }
 
+static bool vnn_has_interface_with_name(struct ctdb_vnn *vnn,
+					const char *name)
+{
+	int n;
+
+	for (n = 0; vnn->ifaces[n] != NULL; n++) {
+		if (strcmp(name, vnn->ifaces[n]) == 0) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+/* If any interfaces now have no possible IPs then delete them.  This
+ * implementation is naive (i.e. simple) rather than clever
+ * (i.e. complex).  Given that this is run on delip and that operation
+ * is rare, this doesn't need to be efficient - it needs to be
+ * foolproof.  One alternative is reference counting, where the logic
+ * is distributed and can, therefore, be broken in multiple places.
+ * Another alternative is to build a red-black tree of interfaces that
+ * can have addresses (by walking ctdb->vnn and ctdb->single_ip_vnn
+ * once) and then walking ctdb->ifaces once and deleting those not in
+ * the tree.  Let's go to one of those if the naive implementation
+ * causes problems...  :-)
+ */
+static void ctdb_remove_orphaned_ifaces(struct ctdb_context *ctdb,
+					struct ctdb_vnn *vnn,
+					TALLOC_CTX *mem_ctx)
+{
+	struct ctdb_iface *i;
+
+	/* For each interface, check if there's an IP using it. */
+	for(i=ctdb->ifaces; i; i=i->next) {
+		struct ctdb_vnn *tv;
+		bool found;
+
+		/* Only consider interfaces named in the given VNN. */
+		if (!vnn_has_interface_with_name(vnn, i->name)) {
+			continue;
+		}
+
+		/* Is the "single IP" on this interface? */
+		if ((ctdb->single_ip_vnn != NULL) &&
+		    (ctdb->single_ip_vnn->ifaces[0] != NULL) &&
+		    (strcmp(i->name, ctdb->single_ip_vnn->ifaces[0]) == 0)) {
+			/* Found, next interface please... */
+			continue;
+		}
+		/* Search for a vnn with this interface. */
+		found = false;
+		for (tv=ctdb->vnn; tv; tv=tv->next) {
+			if (vnn_has_interface_with_name(tv, i->name)) {
+				found = true;
+				break;
+			}
+		}
+
+		if (!found) {
+			/* None of the VNNs are using this interface. */
+			DLIST_REMOVE(ctdb->ifaces, i);
+			/* Caller will free mem_ctx when convenient. */
+			talloc_steal(mem_ctx, i);
+		}
+	}
+}
+
+
 static struct ctdb_iface *ctdb_find_iface(struct ctdb_context *ctdb,
 					  const char *iface)
 {
@@ -3665,20 +3733,20 @@ int32_t ctdb_control_del_public_address(struct ctdb_context *ctdb, TDB_DATA inda
 	/* walk over all public addresses until we find a match */
 	for (vnn=ctdb->vnn;vnn;vnn=vnn->next) {
 		if (ctdb_same_ip(&vnn->public_address, &pub->addr)) {
-			TALLOC_CTX *mem_ctx;
+			TALLOC_CTX *mem_ctx = talloc_new(ctdb);
 
 			DLIST_REMOVE(ctdb->vnn, vnn);
+			talloc_steal(mem_ctx, vnn);
+			ctdb_remove_orphaned_ifaces(ctdb, vnn, mem_ctx);
 			if (vnn->pnn != ctdb->pnn) {
 				if (vnn->iface != NULL) {
 					ctdb_vnn_unassign_iface(ctdb, vnn);
 				}
-				talloc_free(vnn);
+				talloc_free(mem_ctx);
 				return 0;
 			}
 			vnn->pnn = -1;
 
-			mem_ctx = talloc_new(ctdb);
-			talloc_steal(mem_ctx, vnn);
 			ret = ctdb_event_script_callback(ctdb, 
 					 mem_ctx, delete_ip_callback, mem_ctx,
 					 false,
diff --git a/tests/scripts/integration.bash b/tests/scripts/integration.bash
index 8813499..07e764e 100644
--- a/tests/scripts/integration.bash
+++ b/tests/scripts/integration.bash
@@ -494,6 +494,13 @@ wait_until_node_has_some_ips ()
     wait_until 60 node_has_some_ips "$@"
 }
 
+ip2ipmask ()
+{
+    _ip="$1"
+
+    ip addr show to "$_ip" | awk '$1 == "inet" { print $2 }'
+}
+
 #######################################
 
 daemons_stop ()
diff --git a/tests/simple/20_delip_iface_gc.sh b/tests/simple/20_delip_iface_gc.sh
new file mode 100755
index 0000000..bc43567
--- /dev/null
+++ b/tests/simple/20_delip_iface_gc.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+test_info()
+{
+    cat <<EOF
+Verify that an interface is deleted when all IPs on it are deleted.
+EOF
+}
+
+. "${TEST_SCRIPTS_DIR}/integration.bash"
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+echo "Getting public IPs information..."
+try_command_on_node -v any "$CTDB ip -v -n all -Y | tail -n +2"
+ip_info="$out"
+
+# Select the first node and find out its interfaces
+test_node=$(awk -F: 'NR == 1 { print $3}' <<<"$ip_info")
+ifaces=$(awk -F: -v tn=$test_node '$3 == tn { print $6 }' <<<"$ip_info" | sed 's@, @ @g' | xargs -n 1 | sort -u)
+echo "Selected test node ${test_node} with interfaces: ${ifaces}"
+
+# Delete all IPs on each interface...  deleting IPs from one interface
+# can cause other interfaces to disappear, so we need to be careful...
+for i in $ifaces ; do
+    try_command_on_node $test_node "$CTDB ifaces -Y"
+    info=$(awk -F: -v iface="$i" '$2 == iface { print $0 }' <<<"$out")
+
+    if [ -z "$info" ] ; then
+	echo "Interface ${i} missing... assuming already deleted!"
+	continue
+    fi
+
+    echo "Deleting IPs on interface ${i}, with this information:"
+    echo " $info"
+
+    try_command_on_node $test_node "$CTDB ip -v -Y | tail -n +2"
+    awk -F: -v i="$i" \
+	'$6 == i { print $2 }' <<<"$out" |
+    while read ip ; do
+	echo "  $ip"
+	try_command_on_node $test_node "$CTDB delip $ip"
+    done
+
+    try_command_on_node $test_node "$CTDB ifaces -Y"
+    info=$(awk -F: -v iface="$i" '$2 == iface { print $0 }' <<<"$out")
+    
+    if [ -z "$info" ] ; then
+	echo "GOOD: Interface ${i} has been garbage collected"
+    else
+	echo "BAD: Interface ${i} still exists"
+	echo "$out"
+	exit 1
+    fi
+done


-- 
CTDB repository


More information about the samba-cvs mailing list