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;
+}
+
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);
#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
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;
+}
#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"
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];
};
/*
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
#include "cmdline.h"
#include "../include/ctdb.h"
#include "../include/ctdb_private.h"
+#include <arpa/inet.h>
static int timelimit = 3;
" 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"
);
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
*/
{ "getpid", control_getpid },
{ "shutdown", control_shutdown },
{ "recovery", control_recovery },
+ { "takeoverip", control_takeoverip },
+ { "releaseip", control_releaseip },
{ "freeze", control_freeze },
{ "thaw", control_thaw },
};