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)
static struct {
const char *nlist;
+ const char *public_address_list;
+ const char *public_interface;
const char *transport;
const char *myaddress;
const char *socketname;
const char *events;
} ctdb_cmdline = {
.nlist = NULL,
+ .public_address_list = NULL,
+ .public_interface = NULL,
.transport = "tcp",
.myaddress = NULL,
.socketname = CTDB_PATH,
{ "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 }
};
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) {
return 0;
}
+
/*
setup the local node address
*/
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"));
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"));
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));
#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;
-}
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;
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;
}
}
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);
/* 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;
};
/*
#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;
uint32_t seqnum_frequency;
uint32_t recovery_master;
struct ctdb_call_state *pending_calls;
+ struct ctdb_takeover takeover;
};
struct ctdb_db_context {
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
*/
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
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;
}
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;
}