Add two new controls to add/delete public ip address from a node at runtime.
authorRonnie Sahlberg <sahlberg@samba.org>
Wed, 26 Mar 2008 22:23:27 +0000 (09:23 +1100)
committerRonnie Sahlberg <sahlberg@samba.org>
Wed, 26 Mar 2008 22:23:27 +0000 (09:23 +1100)
The controls only modify the runtime setting of which public addresses a node
can server and does not modify /etc/ctdb/public_addresses.
To make the change permanent you also need to edit /etc/ctdb/public_addresses
manually.

After ip addresses have been added/deleted you need to invoke a recovery
for the ip addresses to be redistributed.

client/ctdb_client.c
include/ctdb_private.h
server/ctdb_control.c
server/ctdb_takeover.c
tools/ctdb.c

index 6aed24c1bb65206758d191ef7152c3510b4718c5..f852e5f99b677755b5068855b7d85ffcfc66eaf3 100644 (file)
@@ -2290,6 +2290,55 @@ int ctdb_ctrl_get_all_tunables(struct ctdb_context *ctdb,
        return 0;
 }
 
+/*
+  add a public address to a node
+ */
+int ctdb_ctrl_add_public_ip(struct ctdb_context *ctdb, 
+                     struct timeval timeout, 
+                     uint32_t destnode,
+                     struct ctdb_control_ip_iface *pub)
+{
+       TDB_DATA data;
+       int32_t res;
+       int ret;
+
+       data.dsize = offsetof(struct ctdb_control_ip_iface, iface) + pub->len;
+       data.dptr  = (unsigned char *)pub;
+
+       ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_ADD_PUBLIC_IP, 0, data, NULL,
+                          NULL, &res, &timeout, NULL);
+       if (ret != 0 || res != 0) {
+               DEBUG(DEBUG_ERR,(__location__ " ctdb_control for add_public_ip failed\n"));
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+  delete a public address from a node
+ */
+int ctdb_ctrl_del_public_ip(struct ctdb_context *ctdb, 
+                     struct timeval timeout, 
+                     uint32_t destnode,
+                     struct ctdb_control_ip_iface *pub)
+{
+       TDB_DATA data;
+       int32_t res;
+       int ret;
+
+       data.dsize = offsetof(struct ctdb_control_ip_iface, iface) + pub->len;
+       data.dptr  = (unsigned char *)pub;
+
+       ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_DEL_PUBLIC_IP, 0, data, NULL,
+                          NULL, &res, &timeout, NULL);
+       if (ret != 0 || res != 0) {
+               DEBUG(DEBUG_ERR,(__location__ " ctdb_control for del_public_ip failed\n"));
+               return -1;
+       }
+
+       return 0;
+}
 
 /*
   kill a tcp connection
@@ -2328,13 +2377,13 @@ int ctdb_ctrl_gratious_arp(struct ctdb_context *ctdb,
        TDB_DATA data;
        int32_t res;
        int ret, len;
-       struct ctdb_control_gratious_arp *gratious_arp;
+       struct ctdb_control_ip_iface *gratious_arp;
        TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
 
 
        len = strlen(ifname)+1;
        gratious_arp = talloc_size(tmp_ctx, 
-               offsetof(struct ctdb_control_gratious_arp, iface) + len);
+               offsetof(struct ctdb_control_ip_iface, iface) + len);
        CTDB_NO_MEMORY(ctdb, gratious_arp);
 
        gratious_arp->sin = *sin;
@@ -2342,7 +2391,7 @@ int ctdb_ctrl_gratious_arp(struct ctdb_context *ctdb,
        memcpy(&gratious_arp->iface[0], ifname, len);
 
 
-       data.dsize = offsetof(struct ctdb_control_gratious_arp, iface) + len;
+       data.dsize = offsetof(struct ctdb_control_ip_iface, iface) + len;
        data.dptr  = (unsigned char *)gratious_arp;
 
        ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_SEND_GRATIOUS_ARP, 0, data, NULL,
index 24183e4795b0086591dbc8d6e39322a7aa2ff62f..fcb31205e4b2d24361314a2f18c963e62edec119 100644 (file)
@@ -37,6 +37,7 @@
 #define CTDB_NULL_FUNC      0xFF000001
 #define CTDB_FETCH_FUNC     0xFF000002
 
+
 /*
   a tcp connection description
  */
@@ -499,6 +500,8 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS          = 0,
                    CTDB_CONTROL_TRY_DELETE_RECORDS      = 74,
                    CTDB_CONTROL_ENABLE_MONITOR          = 75,
                    CTDB_CONTROL_DISABLE_MONITOR         = 76,
+                   CTDB_CONTROL_ADD_PUBLIC_IP           = 77,
+                   CTDB_CONTROL_DEL_PUBLIC_IP           = 78,
 };     
 
 /*
@@ -527,10 +530,13 @@ struct ctdb_control_killtcp {
 };
 
 /*
-  struct for send_gratious_arp
+  struct holding a sockaddr_in and an interface name,
+  used for send_gratious_arp and also add/remove public addresses
  */
-struct ctdb_control_gratious_arp {
+//struct ctdb_control_gratious_arp {
+struct ctdb_control_ip_iface {
        struct sockaddr_in sin;
+       uint32_t mask;
        uint32_t len;
        char iface[1];
 };
@@ -1165,6 +1171,8 @@ int32_t ctdb_control_set_tunable(struct ctdb_context *ctdb, TDB_DATA indata);
 int32_t ctdb_control_list_tunables(struct ctdb_context *ctdb, TDB_DATA *outdata);
 int32_t ctdb_control_get_reclock_file(struct ctdb_context *ctdb, TDB_DATA *outdata);
 int32_t ctdb_control_try_delete_records(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata);
+int32_t ctdb_control_add_public_address(struct ctdb_context *ctdb, TDB_DATA indata);
+int32_t ctdb_control_del_public_address(struct ctdb_context *ctdb, TDB_DATA indata);
 
 void ctdb_tunables_set_defaults(struct ctdb_context *ctdb);
 
@@ -1190,6 +1198,16 @@ int ctdb_ctrl_killtcp(struct ctdb_context *ctdb,
                      uint32_t destnode,
                      struct ctdb_control_killtcp *killtcp);
 
+int ctdb_ctrl_add_public_ip(struct ctdb_context *ctdb, 
+                     struct timeval timeout, 
+                     uint32_t destnode,
+                     struct ctdb_control_ip_iface *pub);
+
+int ctdb_ctrl_del_public_ip(struct ctdb_context *ctdb, 
+                     struct timeval timeout, 
+                     uint32_t destnode,
+                     struct ctdb_control_ip_iface *pub);
+
 int ctdb_ctrl_gratious_arp(struct ctdb_context *ctdb, 
                      struct timeval timeout, 
                      uint32_t destnode,
index aa6f3b4756971ae99f5e6a80b926a7dae57327b6..522e11bf0c1e6bf45b11a606c50516cc7695ac45 100644 (file)
@@ -380,6 +380,12 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
        case CTDB_CONTROL_TRY_DELETE_RECORDS:
                return ctdb_control_try_delete_records(ctdb, indata, outdata);
 
+       case CTDB_CONTROL_ADD_PUBLIC_IP:
+               return ctdb_control_add_public_address(ctdb, indata);
+
+       case CTDB_CONTROL_DEL_PUBLIC_IP:
+               return ctdb_control_del_public_address(ctdb, indata);
+
        default:
                DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode));
                return -1;
index d8c4350cb09bd2d5337bb1c9eba08d975721cdbc..26f75bf922876a1e1f67defd1f9109008c3a2f3c 100644 (file)
@@ -391,7 +391,7 @@ int32_t ctdb_control_release_ip(struct ctdb_context *ctdb,
 
 
 
-static int add_public_address(struct ctdb_context *ctdb, struct sockaddr_in addr, unsigned mask, const char *iface)
+static int ctdb_add_public_address(struct ctdb_context *ctdb, struct sockaddr_in addr, unsigned mask, const char *iface)
 {
        struct ctdb_vnn      *vnn;
 
@@ -400,7 +400,7 @@ static int add_public_address(struct ctdb_context *ctdb, struct sockaddr_in addr
                if (ctdb_same_sockaddr(&addr, &vnn->public_address)) {
                        DEBUG(DEBUG_CRIT,("Same ip '%s' specified multiple times in the public address list \n", 
                                 inet_ntoa(addr.sin_addr)));
-                       exit(1);
+                       return -1;
                }               
        }
 
@@ -471,7 +471,7 @@ int ctdb_set_public_addresses(struct ctdb_context *ctdb, const char *alist)
                        iface = tok;
                }
 
-               if (add_public_address(ctdb, addr, mask, iface)) {
+               if (ctdb_add_public_address(ctdb, addr, mask, iface)) {
                        DEBUG(DEBUG_CRIT,("Failed to add line %u to the public address list\n", i+1));
                        talloc_free(lines);
                        return -1;
@@ -1781,23 +1781,23 @@ static void send_gratious_arp(struct event_context *ev, struct timed_event *te,
  */
 int32_t ctdb_control_send_gratious_arp(struct ctdb_context *ctdb, TDB_DATA indata)
 {
-       struct ctdb_control_gratious_arp *gratious_arp = (struct ctdb_control_gratious_arp *)indata.dptr;
+       struct ctdb_control_ip_iface *gratious_arp = (struct ctdb_control_ip_iface *)indata.dptr;
        struct control_gratious_arp *arp;
 
 
        /* verify the size of indata */
-       if (indata.dsize < offsetof(struct ctdb_control_gratious_arp, iface)) {
-               DEBUG(DEBUG_ERR,(__location__ " Too small indata to hold a ctdb_control_gratious_arp structure\n"));
+       if (indata.dsize < offsetof(struct ctdb_control_ip_iface, iface)) {
+               DEBUG(DEBUG_ERR,(__location__ " Too small indata to hold a ctdb_control_ip_iface structure\n"));
                return -1;
        }
        if (indata.dsize != 
-               ( offsetof(struct ctdb_control_gratious_arp, iface)
+               ( offsetof(struct ctdb_control_ip_iface, iface)
                + gratious_arp->len ) ){
 
                DEBUG(DEBUG_ERR,(__location__ " Wrong size of indata. Was %u bytes "
                        "but should be %u bytes\n", 
                         (unsigned)indata.dsize, 
-                        (unsigned)(offsetof(struct ctdb_control_gratious_arp, iface)+gratious_arp->len)));
+                        (unsigned)(offsetof(struct ctdb_control_ip_iface, iface)+gratious_arp->len)));
                return -1;
        }
 
@@ -1817,3 +1817,83 @@ int32_t ctdb_control_send_gratious_arp(struct ctdb_context *ctdb, TDB_DATA indat
        return 0;
 }
 
+int32_t ctdb_control_add_public_address(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+       struct ctdb_control_ip_iface *pub = (struct ctdb_control_ip_iface *)indata.dptr;
+
+
+       /* verify the size of indata */
+       if (indata.dsize < offsetof(struct ctdb_control_ip_iface, iface)) {
+               DEBUG(DEBUG_ERR,(__location__ " Too small indata to hold a ctdb_control_ip_iface structure\n"));
+               return -1;
+       }
+       if (indata.dsize != 
+               ( offsetof(struct ctdb_control_ip_iface, iface)
+               + pub->len ) ){
+
+               DEBUG(DEBUG_ERR,(__location__ " Wrong size of indata. Was %u bytes "
+                       "but should be %u bytes\n", 
+                        (unsigned)indata.dsize, 
+                        (unsigned)(offsetof(struct ctdb_control_ip_iface, iface)+pub->len)));
+               return -1;
+       }
+
+       return ctdb_add_public_address(ctdb, pub->sin, pub->mask, &pub->iface[0]);
+}
+
+/*
+  called when releaseip event finishes for del_public_address
+ */
+static void delete_ip_callback(struct ctdb_context *ctdb, int status, 
+                               void *private_data)
+{
+       talloc_free(private_data);
+}
+
+int32_t ctdb_control_del_public_address(struct ctdb_context *ctdb, TDB_DATA indata)
+{
+       struct ctdb_control_ip_iface *pub = (struct ctdb_control_ip_iface *)indata.dptr;
+       struct ctdb_vnn *vnn;
+       int ret;
+
+       /* verify the size of indata */
+       if (indata.dsize < offsetof(struct ctdb_control_ip_iface, iface)) {
+               DEBUG(DEBUG_ERR,(__location__ " Too small indata to hold a ctdb_control_ip_iface structure\n"));
+               return -1;
+       }
+       if (indata.dsize != 
+               ( offsetof(struct ctdb_control_ip_iface, iface)
+               + pub->len ) ){
+
+               DEBUG(DEBUG_ERR,(__location__ " Wrong size of indata. Was %u bytes "
+                       "but should be %u bytes\n", 
+                        (unsigned)indata.dsize, 
+                        (unsigned)(offsetof(struct ctdb_control_ip_iface, iface)+pub->len)));
+               return -1;
+       }
+
+       /* 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->sin)) {
+                       TALLOC_CTX *mem_ctx = talloc_new(ctdb);
+
+                       DLIST_REMOVE(ctdb->vnn, vnn);
+
+                       ret = ctdb_event_script_callback(ctdb, 
+                                        timeval_current_ofs(ctdb->tunable.script_timeout, 0),
+                                        mem_ctx, delete_ip_callback, mem_ctx,
+                                        "releaseip %s %s %u",
+                                        vnn->iface, 
+                                        inet_ntoa(vnn->public_address.sin_addr),
+                                        vnn->public_netmask_bits);
+                       talloc_free(vnn);
+                       if (ret != 0) {
+                               return -1;
+                       }
+                       return 0;
+               }
+       }
+
+       return -1;
+}
+
index dd83f88409c90476ed5623b7b6eb50c8b251ba18..01a98650bf1826e26019bb1c925b71e30271faf3 100644 (file)
@@ -504,6 +504,76 @@ static int control_moveip(struct ctdb_context *ctdb, int argc, const char **argv
        return 0;
 }
 
+/*
+  add a public ip address to a node
+ */
+static int control_addip(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       int ret;
+       int len;
+       unsigned mask;
+       struct sockaddr_in addr;
+       struct ctdb_control_ip_iface *pub;
+
+       if (argc != 2) {
+               usage();
+       }
+
+       if (!parse_ip_mask(argv[0], &addr, &mask)) {
+               DEBUG(DEBUG_ERR, ("Badly formed ip/mask : %s\n", argv[0]));
+               return -1;
+       }
+
+       len = offsetof(struct ctdb_control_ip_iface, iface) + strlen(argv[1]);
+       pub = talloc_size(ctdb, len); 
+       CTDB_NO_MEMORY(ctdb, pub);
+
+       pub->sin   = addr;
+       pub->mask  = mask;
+       pub->len   = strlen(argv[1]);
+       memcpy(&pub->iface[0], argv[1], strlen(argv[1]));
+
+       ret = ctdb_ctrl_add_public_ip(ctdb, TIMELIMIT(), options.pnn, pub);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to add public ip to node %u\n", options.pnn));
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+  delete a public ip address from a node
+ */
+static int control_delip(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       int ret;
+       struct sockaddr_in addr;
+       struct ctdb_control_ip_iface pub;
+
+       if (argc != 1) {
+               usage();
+       }
+
+       addr.sin_family = AF_INET;
+       if (inet_aton(argv[0], &addr.sin_addr) == 0) {
+               DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0]));
+               return -1;
+       }
+
+       pub.sin   = addr;
+       pub.mask  = 0;
+       pub.len   = 0;
+
+       ret = ctdb_ctrl_del_public_ip(ctdb, TIMELIMIT(), options.pnn, &pub);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to del public ip from node %u\n", options.pnn));
+               return ret;
+       }
+
+       return 0;
+}
+
 /*
   kill a tcp connection
  */
@@ -1454,6 +1524,8 @@ static const struct {
        { "reloadnodes",     control_reload_nodes_file,         false, "reload the nodes file and restart the transport on all nodes"},
        { "getreclock",      control_getreclock,        false,  "get the path to the reclock file" },
        { "moveip",          control_moveip,            false, "move/failover an ip address to another node", "<ip> <node>"},
+       { "addip",           control_addip,             false, "add a ip address to a node", "<ip/mask> <iface>"},
+       { "delip",           control_delip,             false, "delete an ip address from a node", "<ip>"},
 };
 
 /*