ctdbd: Clean up orphaned interfaces when an IP is deleted
authorMartin Schwenke <martin@meltin.net>
Fri, 23 Nov 2012 09:09:07 +0000 (20:09 +1100)
committerMartin Schwenke <martin@meltin.net>
Mon, 7 Jan 2013 01:19:33 +0000 (12:19 +1100)
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@meltin.net>
Pair-programmed-with: Amitay Isaacs <amitay@gmail.com>

(This used to be ctdb commit cc1a3ae911d3fee8b87fda5de5ab6d9499d7510a)

ctdb/server/ctdb_takeover.c

index 5345251a454663a84df888e98949e356364c8901..df543fedda200afd25245561d05c4c2cc5a3b255 100644 (file)
@@ -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,