]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
add controls to take over and release an ip address
authorRonnie Sahlberg <sahlberg@ronnie>
Fri, 25 May 2007 03:05:25 +0000 (13:05 +1000)
committerRonnie Sahlberg <sahlberg@ronnie>
Fri, 25 May 2007 03:05:25 +0000 (13:05 +1000)
add sending of grat arp     both normal grat arp (request) and also
unsolicited grat arp replies

(This used to be ctdb commit 7305c00c21c30bdbafc3722a018513378bd307e6)

ctdb/common/ctdb_client.c
ctdb/common/ctdb_control.c
ctdb/common/ctdb_recover.c
ctdb/include/ctdb_private.h
ctdb/tools/ctdb_control.c

index c4531cb2d9f53f5eb6aed20d48c3c85be48f2e6f..ebf811e646d9e495a4c9ef318a40339140c4646a 100644 (file)
@@ -1826,3 +1826,69 @@ int ctdb_ctrl_delete_low_rsn(struct ctdb_context *ctdb, struct timeval timeout,
 
        return 0;       
 }
+
+/* 
+  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)
+{
+       TDB_DATA data;
+       int ret;
+       int32_t res;
+       struct ctdb_control_takeover_ip *ip;
+
+       data.dsize = offsetof(struct ctdb_control_takeover_ip, iface) + strlen(iface)+1;
+       data.dptr  = talloc_size(ctdb, data.dsize);
+
+       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);
+
+       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"));
+               return -1;
+       }
+
+       return 0;       
+}
+
+
+/* 
+  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)
+{
+       TDB_DATA data;
+       int ret;
+       int32_t res;
+       struct ctdb_control_takeover_ip *ip;
+
+       data.dsize = offsetof(struct ctdb_control_takeover_ip, iface) + strlen(iface)+1;
+       data.dptr  = talloc_size(ctdb, data.dsize);
+
+       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);
+
+       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"));
+               return -1;
+       }
+
+       return 0;       
+}
+
index 17c4a3536c6b0704cf34c622e8ed603fcc289e89..155d8d01717f88d3ec6afb6c067d03f12b0b5371 100644 (file)
@@ -260,6 +260,14 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
                CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_set_rsn_nonempty));
                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);
+
+       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);
+
        case CTDB_CONTROL_DELETE_LOW_RSN: 
                CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_delete_low_rsn));
                return ctdb_control_delete_low_rsn(ctdb, indata, outdata);
index 4b466f9ae27c76ce4d7532deb4e3ddaa8a1bc8ca..79c17016fce027b7ef4175381b83fe1952ea5efc 100644 (file)
@@ -27,6 +27,8 @@
 #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
@@ -614,3 +616,146 @@ 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 f12c4b4ca523648b20e9b7516ebf8bcba66e5f1e..a11e874ae3c765d33bb0f3dd74502ac809d01160 100644 (file)
@@ -22,6 +22,8 @@
 #define _CTDB_PRIVATE_H
 
 #include "ctdb.h"
+#include <sys/socket.h>
+#include <netinet/in.h>
 
 /* location of daemon socket */
 #define CTDB_PATH      "/tmp/ctdb.socket"
@@ -378,6 +380,17 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS,
                    CTDB_CONTROL_MAX_RSN,
                    CTDB_CONTROL_SET_RSN_NONEMPTY,
                    CTDB_CONTROL_DELETE_LOW_RSN,
+                   CTDB_CONTROL_TAKEOVER_IP,
+                   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];
 };
 
 /*
@@ -865,5 +878,11 @@ 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);
+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);
+int ctdb_ctrl_release_ip(struct ctdb_context *ctdb, struct timeval timeout, 
+                         uint32_t destnode, struct sockaddr *sa, const char *iface);
 
 #endif
index 8b765fe12197678e593770884a15318cc8968aac..21d85cb4630c6b7259d582a9bcb7c58fe143a3fa 100644 (file)
@@ -25,6 +25,7 @@
 #include "cmdline.h"
 #include "../include/ctdb.h"
 #include "../include/ctdb_private.h"
+#include <arpa/inet.h>
 
 static int timelimit = 3;
 
@@ -62,6 +63,8 @@ static void usage(void)
                "  dumpmemory <vnn|all>               dump memory map to log\n"
                "  shutdown <vnn>                     shutdown a remote ctdb\n"
                "  recovery <vnn>                     trigger a recovery\n"
+               "  takeoverip <vnn> <ip> <iface>      take over an ip address\n"
+               "  releaseip <vnn> <ip> <iface>       release an ip address\n"
                "  freeze <vnn|all>                   freeze a node\n"
                "  thaw <vnn|all>                     thaw a node\n"
        );
@@ -374,6 +377,62 @@ static int control_shutdown(struct ctdb_context *ctdb, int argc, const char **ar
        return 0;
 }
 
+/*
+  take over an ip address
+ */
+static int control_takeoverip(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       uint32_t vnn;
+       struct sockaddr_in sin;
+       int ret;
+
+
+       if (argc < 3) {
+               usage();
+       }
+
+       vnn     = strtoul(argv[0], NULL, 0);
+
+       sin.sin_family = AF_INET;
+       inet_aton(argv[1], &sin.sin_addr);
+
+       ret = ctdb_ctrl_takeover_ip(ctdb, timeval_current_ofs(1, 0), vnn, (struct sockaddr *)&sin, argv[2]);
+       if (ret != 0) {
+               printf("Unable to takeoverip node %u ip %s iface %s\n", vnn, argv[1], argv[2]);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+  release an ip address
+ */
+static int control_releaseip(struct ctdb_context *ctdb, int argc, const char **argv)
+{
+       uint32_t vnn;
+       struct sockaddr_in sin;
+       int ret;
+
+
+       if (argc < 3) {
+               usage();
+       }
+
+       vnn     = strtoul(argv[0], NULL, 0);
+
+       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]);
+       if (ret != 0) {
+               printf("Unable to releaseip node %u ip %s iface %s\n", vnn, argv[1], argv[2]);
+               return ret;
+       }
+
+       return 0;
+}
+
 /*
   trigger a recovery
  */
@@ -1080,6 +1139,8 @@ int main(int argc, const char *argv[])
                { "getpid", control_getpid },
                { "shutdown", control_shutdown },
                { "recovery", control_recovery },
+               { "takeoverip", control_takeoverip },
+               { "releaseip", control_releaseip },
                { "freeze", control_freeze },
                { "thaw", control_thaw },
        };