]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
added IP takeover logic for public IPs to ctdb
authorAndrew Tridgell <tridge@samba.org>
Fri, 25 May 2007 07:04:13 +0000 (17:04 +1000)
committerAndrew Tridgell <tridge@samba.org>
Fri, 25 May 2007 07:04:13 +0000 (17:04 +1000)
(This used to be ctdb commit 374adb729472670f35cef41269b8719f49c0de0e)

ctdb/Makefile.in
ctdb/common/cmdline.c
ctdb/common/ctdb.c
ctdb/common/ctdb_client.c
ctdb/common/ctdb_control.c
ctdb/common/ctdb_recover.c
ctdb/common/ctdb_recoverd.c
ctdb/include/ctdb_private.h
ctdb/tools/ctdb_control.c

index cdc9b3abc74176187c243a017d5f8a6cbad7e51a..a4a26c0b6789006d9eda4a2c764d3a91a728b0b7 100644 (file)
@@ -32,9 +32,11 @@ CTDB_COMMON_OBJ = common/ctdb.o common/ctdb_daemon.o common/ctdb_client.o \
        lib/util/debug.o common/ctdb_recover.o common/ctdb_recoverd.o \
        common/ctdb_freeze.o common/ctdb_traverse.o common/ctdb_monitor.o
 
+CTDB_TAKEOVER_OBJ = takeover/system.o takeover/ctdb_takeover.o
+
 CTDB_TCP_OBJ = tcp/tcp_connect.o tcp/tcp_io.o tcp/tcp_init.o
 
-CTDB_OBJ = $(CTDB_COMMON_OBJ) $(CTDB_TCP_OBJ) $(POPT_OBJ)
+CTDB_OBJ = $(CTDB_COMMON_OBJ) $(CTDB_TAKEOVER_OBJ) $(CTDB_TCP_OBJ) $(POPT_OBJ)
 
 OBJS = @TDB_OBJ@ @TALLOC_OBJ@ @LIBREPLACEOBJ@ @INFINIBAND_WRAPPER_OBJ@ $(EXTRA_OBJ) @EVENTS_OBJ@ $(CTDB_OBJ) $(UTIL_OBJ)
 
index 19a31514aef128931f74bb8128fc26932d6c49be..7eb15d567404af5a1055337c1aaffe492164f7b7 100644 (file)
@@ -30,6 +30,8 @@
 
 static struct {
        const char *nlist;
+       const char *public_address_list;
+       const char *public_interface;
        const char *transport;
        const char *myaddress;
        const char *socketname;
@@ -40,6 +42,8 @@ static struct {
        const char *events;
 } ctdb_cmdline = {
        .nlist = NULL,
+       .public_address_list = NULL,
+       .public_interface = NULL,
        .transport = "tcp",
        .myaddress = NULL,
        .socketname = CTDB_PATH,
@@ -76,6 +80,8 @@ struct poptOption popt_ctdb_cmdline[] = {
        { "torture", 0, POPT_ARG_NONE, &ctdb_cmdline.torture, 0, "enable nastiness in library", NULL },
        { "logfile", 0, POPT_ARG_STRING, &ctdb_cmdline.logfile, 0, "log file location", "filename" },
        { "events", 0, POPT_ARG_STRING, NULL, OPT_EVENTSYSTEM, "event system", NULL },
+       { "public-addresses", 0, POPT_ARG_STRING, &ctdb_cmdline.public_address_list, 0, "public address list file", "filename" },
+       { "public-interface", 0, POPT_ARG_STRING, &ctdb_cmdline.public_interface, 0, "public interface", "interface"},
        { NULL }
 };
 
@@ -142,6 +148,20 @@ struct ctdb_context *ctdb_cmdline_init(struct event_context *ev)
                exit(1);
        }
 
+       if (ctdb_cmdline.public_interface) {
+               ctdb->takeover.interface = talloc_strdup(ctdb, ctdb_cmdline.public_interface);
+               CTDB_NO_MEMORY_NULL(ctdb, ctdb->takeover.interface);
+       }
+
+       if (ctdb_cmdline.public_address_list) {
+               ret = ctdb_set_public_addresses(ctdb, ctdb_cmdline.public_address_list);
+               if (ret == -1) {
+                       printf("Unable to setup public address list\n");
+                       exit(1);
+               }
+               ctdb->takeover.enabled = true;
+       }
+
        if (ctdb_cmdline.db_dir) {
                ret = ctdb_set_tdb_dir(ctdb, ctdb_cmdline.db_dir);
                if (ret == -1) {
index 7719c2984cc367fcb09ec8ab618e19b0360c5407..4f03fe1dff1dcbb57756872eeed2ac1dd8a98bc7 100644 (file)
@@ -180,6 +180,7 @@ XXX table for the daemons.
        return 0;
 }
 
+
 /*
   setup the local node address
 */
index ebf811e646d9e495a4c9ef318a40339140c4646a..ada67fc06540d1caa16a3aa501539c9d024e2bba 100644 (file)
@@ -1831,25 +1831,26 @@ int ctdb_ctrl_delete_low_rsn(struct ctdb_context *ctdb, struct timeval timeout,
   sent to a node to make it take over an ip address
 */
 int ctdb_ctrl_takeover_ip(struct ctdb_context *ctdb, struct timeval timeout, 
-                         uint32_t destnode, struct sockaddr *sa, const char *iface)
+                         uint32_t destnode, const char *ip)
 {
        TDB_DATA data;
        int ret;
        int32_t res;
-       struct ctdb_control_takeover_ip *ip;
+       struct sockaddr sa;
+       struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
 
-       data.dsize = offsetof(struct ctdb_control_takeover_ip, iface) + strlen(iface)+1;
-       data.dptr  = talloc_size(ctdb, data.dsize);
+       ZERO_STRUCT(sa);
+#ifdef HAVE_SOCK_SIN_LEN
+       sin->sin_len = sizeof(*sin);
+#endif
+       sin->sin_family = AF_INET;
+       inet_aton(ip, &sin->sin_addr);
 
-       ip = (struct ctdb_control_takeover_ip *)data.dptr;
-
-       memcpy(&ip->sa, sa, sizeof(struct sockaddr));
-       ip->iflen = strlen(iface);
-       memcpy(&ip->iface[0], iface, strlen(iface)+1);
+       data.dsize = sizeof(sa);
+       data.dptr  = (uint8_t *)&sa;
 
        ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_TAKEOVER_IP, 0, data, NULL,
                           NULL, &res, &timeout, NULL);
-       talloc_free(data.dptr);
 
        if (ret != 0 || res != 0) {
                DEBUG(0,(__location__ " ctdb_control for takeover_ip failed\n"));
@@ -1864,25 +1865,26 @@ int ctdb_ctrl_takeover_ip(struct ctdb_context *ctdb, struct timeval timeout,
   sent to a node to make it release an ip address
 */
 int ctdb_ctrl_release_ip(struct ctdb_context *ctdb, struct timeval timeout, 
-                         uint32_t destnode, struct sockaddr *sa, const char *iface)
+                        uint32_t destnode, const char *ip)
 {
        TDB_DATA data;
        int ret;
        int32_t res;
-       struct ctdb_control_takeover_ip *ip;
+       struct sockaddr sa;
+       struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
 
-       data.dsize = offsetof(struct ctdb_control_takeover_ip, iface) + strlen(iface)+1;
-       data.dptr  = talloc_size(ctdb, data.dsize);
+       ZERO_STRUCT(sa);
+#ifdef HAVE_SOCK_SIN_LEN
+       sin->sin_len = sizeof(*sin);
+#endif
+       sin->sin_family = AF_INET;
+       inet_aton(ip, &sin->sin_addr);
 
-       ip = (struct ctdb_control_takeover_ip *)data.dptr;
-
-       memcpy(&ip->sa, sa, sizeof(struct sockaddr));
-       ip->iflen = strlen(iface);
-       memcpy(&ip->iface[0], iface, strlen(iface)+1);
+       data.dsize = sizeof(sa);
+       data.dptr  = (uint8_t *)&sa;
 
        ret = ctdb_control(ctdb, destnode, 0, CTDB_CONTROL_RELEASE_IP, 0, data, NULL,
                           NULL, &res, &timeout, NULL);
-       talloc_free(data.dptr);
 
        if (ret != 0 || res != 0) {
                DEBUG(0,(__location__ " ctdb_control for release_ip failed\n"));
index 155d8d01717f88d3ec6afb6c067d03f12b0b5371..cb990d52c2bfeb3f7f292c20126a33d67b18088d 100644 (file)
@@ -261,12 +261,12 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
                return ctdb_control_set_rsn_nonempty(ctdb, indata, outdata);
 
        case CTDB_CONTROL_TAKEOVER_IP:
-               CHECK_CONTROL_DATA_SIZE(offsetof(struct ctdb_control_takeover_ip, iface) + ((struct ctdb_control_takeover_ip *)indata.dptr)->iflen + 1);
-               return ctdb_control_takeover_ip(ctdb, indata, outdata);
+               CHECK_CONTROL_DATA_SIZE(sizeof(struct sockaddr));
+               return ctdb_control_takeover_ip(ctdb, indata);
 
        case CTDB_CONTROL_RELEASE_IP:
-               CHECK_CONTROL_DATA_SIZE(offsetof(struct ctdb_control_takeover_ip, iface) + ((struct ctdb_control_takeover_ip *)indata.dptr)->iflen + 1);
-               return ctdb_control_release_ip(ctdb, indata, outdata);
+               CHECK_CONTROL_DATA_SIZE(sizeof(struct sockaddr));
+               return ctdb_control_release_ip(ctdb, indata);
 
        case CTDB_CONTROL_DELETE_LOW_RSN: 
                CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_delete_low_rsn));
index 79c17016fce027b7ef4175381b83fe1952ea5efc..604ba1fa2dac329e29aad4b9d54472ecfc652dea 100644 (file)
@@ -27,8 +27,6 @@
 #include "../include/ctdb_private.h"
 #include "lib/util/dlinklist.h"
 #include "db_wrap.h"
-#include <net/ethernet.h>
-#include <net/if_arp.h>
 
 /*
   lock all databases - mark only
@@ -617,145 +615,3 @@ int32_t ctdb_control_delete_low_rsn(struct ctdb_context *ctdb, TDB_DATA indata,
        return 0;
 }
 
-
-/*
-  send grat arp after we have taken over an ip address
- */
-static int send_arp(struct sockaddr_in *saddr, char *iface)
-{
-       int s, ret;
-       struct sockaddr sa;
-       struct ether_header *eh;
-       struct arphdr *ah;
-       struct ifreq if_hwaddr;
-       unsigned char buffer[64]; /*minimum eth frame size */
-       char *ptr;
-
-
-       /* for now, we only handle AF_INET addresses */
-       if (saddr->sin_family != AF_INET) {
-               DEBUG(0,(__location__ " not an ipv4 address\n"));
-               return -1;
-       }
-
-       s = socket(AF_INET, SOCK_PACKET, htons(ETHERTYPE_ARP));
-       if (s == -1){
-               DEBUG(0,(__location__ "failed to open raw socket\n"));
-               return -1;
-       }
-
-       /* get the mac address */
-       strcpy(if_hwaddr.ifr_name, iface);
-       ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
-       if ( ret < 0 ) {
-               close(s);
-               DEBUG(0,(__location__ " ioctl failed\n"));
-               return -1;
-       }
-       if(if_hwaddr.ifr_hwaddr.sa_family != 1){
-               close(s);
-               DEBUG(0,(__location__ " not an ehternet address\n"));
-               return -1;
-       }
-
-
-       memset(buffer, 0 , 64);
-       eh = (struct ether_header *)buffer;
-       memset(eh->ether_dhost, 0xff, ETH_ALEN);
-       memcpy(eh->ether_shost, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
-       eh->ether_type=htons(ETHERTYPE_ARP);
-
-       ah = (struct arphdr *)&buffer[sizeof(struct ether_header)];
-       ah->ar_hrd = htons(ARPHRD_ETHER);
-       ah->ar_pro = htons(ETH_P_IP);
-       ah->ar_hln = ETH_ALEN;
-       ah->ar_pln = 4;
-
-       /* send a gratious arp */
-       ah->ar_op  = htons(ARPOP_REQUEST);
-       ptr = (char *)&ah[1];
-       memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
-       ptr+=ETH_ALEN;
-       memcpy(ptr, &saddr->sin_addr, 4);         
-       ptr+=4;
-       memset(ptr, 0, ETH_ALEN); 
-       ptr+=ETH_ALEN;
-       memcpy(ptr, &saddr->sin_addr, 4);         
-       ptr+=4;
-
-       strcpy(sa.sa_data, iface);
-       ret = sendto(s, buffer, 64, 0, &sa, sizeof(sa));
-       if (ret < 0 ){
-               close(s);
-               DEBUG(0,(__location__ " failed sendto\n"));
-               return -1;
-       }
-
-       /* send unsolicited arp reply broadcast */
-       ah->ar_op  = htons(ARPOP_REPLY);
-       ptr = (char *)&ah[1];
-       memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
-       ptr+=ETH_ALEN;
-       memcpy(ptr, &saddr->sin_addr, 4);         
-       ptr+=4;
-       memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
-       ptr+=ETH_ALEN;
-       memcpy(ptr, &saddr->sin_addr, 4);         
-       ptr+=4;
-
-       strcpy(sa.sa_data, iface);
-       ret = sendto(s, buffer, 64, 0, &sa, sizeof(sa));
-       if (ret < 0 ){
-               DEBUG(0,(__location__ " failed sendto\n"));
-               return -1;
-       }
-
-       close(s);
-       return 0;
-}
-
-/*
-  take over an ip address
- */
-int32_t ctdb_control_takeover_ip(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata)
-{
-       int ret;
-       struct ctdb_control_takeover_ip *ip = 
-               (struct ctdb_control_takeover_ip *)indata.dptr;
-       struct sockaddr_in *sin = (struct sockaddr_in *)&ip->sa;
-       char cmdstr[256];
-
-       sprintf(cmdstr, "ip addr add %s/32 dev %s",
-               inet_ntoa(sin->sin_addr),
-               ip->iface);
-               
-       DEBUG(0,("Taking over IP : %s\n",cmdstr));
-       system(cmdstr);
-
-       ret = send_arp(sin, ip->iface);
-       if (ret != 0) {
-               DEBUG(0,(__location__ "sending of arp failed\n"));
-       }
-
-       return ret;
-}
-
-/*
-  release an ip address
- */
-int32_t ctdb_control_release_ip(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata)
-{
-       struct ctdb_control_takeover_ip *ip = 
-               (struct ctdb_control_takeover_ip *)indata.dptr;
-       struct sockaddr_in *sin = (struct sockaddr_in *)&ip->sa;
-       char cmdstr[256];
-
-       sprintf(cmdstr, "ip addr del %s/32 dev %s",
-               inet_ntoa(sin->sin_addr),
-               ip->iface);
-               
-       DEBUG(0,("Releasing IP : %s\n",cmdstr));
-       system(cmdstr);
-
-       return 0;
-}
index 0e5411e16700d2ecae67a6a715e5d80c20051ebc..ad847c614b94038910620b9ba4e6f39dc4e31cea 100644 (file)
@@ -376,8 +376,8 @@ static int update_vnnmap_on_all_nodes(struct ctdb_context *ctdb, struct ctdb_nod
 
 
 static int do_recovery(struct ctdb_context *ctdb, 
-       TALLOC_CTX *mem_ctx, uint32_t vnn, uint32_t num_active,
-       struct ctdb_node_map *nodemap, struct ctdb_vnn_map *vnnmap)
+                      TALLOC_CTX *mem_ctx, uint32_t vnn, uint32_t num_active,
+                      struct ctdb_node_map *nodemap, struct ctdb_vnn_map *vnnmap)
 {
        int i, j, ret;
        uint32_t generation;
@@ -499,7 +499,7 @@ static int do_recovery(struct ctdb_context *ctdb,
        vnnmap->map = talloc_array(vnnmap, uint32_t, vnnmap->size);
        for (i=j=0;i<nodemap->num;i++) {
                if (nodemap->nodes[i].flags&NODE_FLAGS_CONNECTED) {
-                       vnnmap->map[j++]=nodemap->nodes[i].vnn;
+                       vnnmap->map[j++] = nodemap->nodes[i].vnn;
                }
        }
 
@@ -539,6 +539,16 @@ static int do_recovery(struct ctdb_context *ctdb,
                return -1;
        }
 
+       /*
+         if enabled, tell nodes to takeover their public IPs
+        */
+       if (ctdb->takeover.enabled) {
+               ret = ctdb_takeover_run(ctdb, nodemap);
+               if (ret != 0) {
+                       DEBUG(0, (__location__, " Unable to setup public takeover addresses\n"));
+                       return -1;
+               }
+       }
 
        /* disable recovery mode */
        ret = set_recovery_mode(ctdb, nodemap, CTDB_RECOVERY_NORMAL);
index a11e874ae3c765d33bb0f3dd74502ac809d01160..3c26145d3e23d3c32c50686c231cd27c70ff3230 100644 (file)
@@ -100,6 +100,13 @@ struct ctdb_node {
        /* a list of controls pending to this node, so we can time them out quickly
           if the node becomes disconnected */
        struct daemon_control_state *pending_controls;
+
+       /* the public address of this node, if known */
+       const char *public_address;
+
+       /* the node number that has taken over this nodes public address, if any. 
+          If not taken over, then set to -1 */
+       int32_t takeover_vnn;
 };
 
 /*
@@ -239,6 +246,13 @@ enum ctdb_freeze_mode {CTDB_FREEZE_NONE, CTDB_FREEZE_PENDING, CTDB_FREEZE_FROZEN
 #define CTDB_MONITORING_ACTIVE         0
 #define CTDB_MONITORING_DISABLED       1
 
+/* information about IP takeover */
+struct ctdb_takeover {
+       bool enabled;
+       const char *interface;
+};
+
+
 /* main state of the ctdb daemon */
 struct ctdb_context {
        struct event_context *ev;
@@ -275,6 +289,7 @@ struct ctdb_context {
        uint32_t seqnum_frequency;
        uint32_t recovery_master;
        struct ctdb_call_state *pending_calls;
+       struct ctdb_takeover takeover;
 };
 
 struct ctdb_db_context {
@@ -384,15 +399,6 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS,
                    CTDB_CONTROL_RELEASE_IP,
 };
 
-/* 
-  structure passed in ctdb_control_takeover_ip and ctdb_control_release_ip
- */
-struct ctdb_control_takeover_ip {
-       struct sockaddr sa;
-       uint8_t iflen;
-       char iface[1];
-};
-
 /*
   structure passed in ctdb_control_set_rsn_nonempty
  */
@@ -878,11 +884,18 @@ int ctdb_ctrl_set_rsn_nonempty(struct ctdb_context *ctdb, struct timeval timeout
 int ctdb_ctrl_delete_low_rsn(struct ctdb_context *ctdb, struct timeval timeout, 
                             uint32_t destnode, uint32_t db_id, uint64_t rsn);
 void ctdb_set_realtime(void);
-int32_t ctdb_control_takeover_ip(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata);
+int32_t ctdb_control_takeover_ip(struct ctdb_context *ctdb, TDB_DATA indata);
 int ctdb_ctrl_takeover_ip(struct ctdb_context *ctdb, struct timeval timeout, 
-                         uint32_t destnode, struct sockaddr *sa, const char *iface);
-int32_t ctdb_control_release_ip(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata);
+                         uint32_t destnode, const char *ip);
+int32_t ctdb_control_release_ip(struct ctdb_context *ctdb, TDB_DATA indata);
 int ctdb_ctrl_release_ip(struct ctdb_context *ctdb, struct timeval timeout, 
-                         uint32_t destnode, struct sockaddr *sa, const char *iface);
+                        uint32_t destnode, const char *ip);
+
+/* from takeover/system.c */
+int ctdb_sys_send_arp(const struct sockaddr_in *saddr, const char *iface);
+
+int ctdb_set_public_addresses(struct ctdb_context *ctdb, const char *alist);
+
+int ctdb_takeover_run(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap);
 
 #endif
index 21d85cb4630c6b7259d582a9bcb7c58fe143a3fa..0a6580985df7e63eb7266ea6d31120450883d055 100644 (file)
@@ -383,22 +383,19 @@ static int control_shutdown(struct ctdb_context *ctdb, int argc, const char **ar
 static int control_takeoverip(struct ctdb_context *ctdb, int argc, const char **argv)
 {
        uint32_t vnn;
-       struct sockaddr_in sin;
        int ret;
+       const char *ip;
 
-
-       if (argc < 3) {
+       if (argc < 2) {
                usage();
        }
 
-       vnn     = strtoul(argv[0], NULL, 0);
-
-       sin.sin_family = AF_INET;
-       inet_aton(argv[1], &sin.sin_addr);
+       vnn  = strtoul(argv[0], NULL, 0);
+       ip   = argv[1];
 
-       ret = ctdb_ctrl_takeover_ip(ctdb, timeval_current_ofs(1, 0), vnn, (struct sockaddr *)&sin, argv[2]);
+       ret = ctdb_ctrl_takeover_ip(ctdb, timeval_current_ofs(1, 0), vnn, ip);
        if (ret != 0) {
-               printf("Unable to takeoverip node %u ip %s iface %s\n", vnn, argv[1], argv[2]);
+               printf("Unable to takeoverip node %u ip %s\n", vnn, ip);
                return ret;
        }
 
@@ -411,22 +408,19 @@ static int control_takeoverip(struct ctdb_context *ctdb, int argc, const char **
 static int control_releaseip(struct ctdb_context *ctdb, int argc, const char **argv)
 {
        uint32_t vnn;
-       struct sockaddr_in sin;
        int ret;
+       const char *ip;
 
-
-       if (argc < 3) {
+       if (argc < 2) {
                usage();
        }
 
        vnn     = strtoul(argv[0], NULL, 0);
+       ip      = argv[1];
 
-       sin.sin_family = AF_INET;
-       inet_aton(argv[1], &sin.sin_addr);
-
-       ret = ctdb_ctrl_release_ip(ctdb, timeval_current_ofs(1, 0), vnn, (struct sockaddr *)&sin, argv[2]);
+       ret = ctdb_ctrl_release_ip(ctdb, timeval_current_ofs(1, 0), vnn, ip);
        if (ret != 0) {
-               printf("Unable to releaseip node %u ip %s iface %s\n", vnn, argv[1], argv[2]);
+               printf("Unable to releaseip node %u ip %s\n", vnn, ip);
                return ret;
        }