From 613c6b9c4ce7e8dc9aba1a2f5f7866132952365f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 25 May 2007 17:16:50 +1000 Subject: [PATCH] new files for IP takeover (This used to be ctdb commit 9232501a6bb9ee5d67a3b7cc87752d82ede162a6) --- ctdb/takeover/ctdb_takeover.c | 178 ++++++++++++++++++++++++++++++++++ ctdb/takeover/system.c | 128 ++++++++++++++++++++++++ 2 files changed, 306 insertions(+) create mode 100644 ctdb/takeover/ctdb_takeover.c create mode 100644 ctdb/takeover/system.c diff --git a/ctdb/takeover/ctdb_takeover.c b/ctdb/takeover/ctdb_takeover.c new file mode 100644 index 00000000000..f2f51602b60 --- /dev/null +++ b/ctdb/takeover/ctdb_takeover.c @@ -0,0 +1,178 @@ +/* + ctdb recovery code + + Copyright (C) Ronnie Sahlberg 2007 + Copyright (C) Andrew Tridgell 2007 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include "includes.h" +#include "lib/events/events.h" +#include "lib/tdb/include/tdb.h" +#include "system/network.h" +#include "system/filesys.h" +#include "system/wait.h" +#include "../include/ctdb_private.h" + + +#define TAKEOVER_TIMEOUT() timeval_current_ofs(5,0) + +/* + take over an ip address + */ +int32_t ctdb_control_takeover_ip(struct ctdb_context *ctdb, TDB_DATA indata) +{ + int ret; + struct sockaddr_in *sin = (struct sockaddr_in *)indata.dptr; + char *cmdstr; + + cmdstr = talloc_asprintf(ctdb, "ip addr add %s/32 dev %s 2> /dev/null", + inet_ntoa(sin->sin_addr), ctdb->takeover.interface); + CTDB_NO_MEMORY(ctdb, cmdstr); + + DEBUG(0,("Taking over IP : %s\n", cmdstr)); + system(cmdstr); + talloc_free(cmdstr); + + ret = ctdb_sys_send_arp(sin, ctdb->takeover.interface); + if (ret != 0) { + DEBUG(0,(__location__ "sending of arp failed (%s)\n", strerror(errno))); + } + + return ret; +} + +/* + release an ip address + */ +int32_t ctdb_control_release_ip(struct ctdb_context *ctdb, TDB_DATA indata) +{ + struct sockaddr_in *sin = (struct sockaddr_in *)indata.dptr; + char *cmdstr; + + cmdstr = talloc_asprintf(ctdb, "ip addr del %s/32 dev %s 2> /dev/null", + inet_ntoa(sin->sin_addr), ctdb->takeover.interface); + + DEBUG(0,("Releasing IP : %s\n", cmdstr)); + system(cmdstr); + + talloc_free(cmdstr); + + return 0; +} + + +/* + setup the public address list from a file +*/ +int ctdb_set_public_addresses(struct ctdb_context *ctdb, const char *alist) +{ + char **lines; + int nlines; + int i; + + lines = file_lines_load(alist, &nlines, ctdb); + if (lines == NULL) { + ctdb_set_error(ctdb, "Failed to load public address list '%s'\n", alist); + return -1; + } + + if (nlines != ctdb->num_nodes) { + DEBUG(0,("Number of lines in %s does not match number of nodes!\n")); + talloc_free(lines); + return -1; + } + + for (i=0;inodes[i]->public_address = talloc_strdup(ctdb->nodes[i], lines[i]); + CTDB_NO_MEMORY(ctdb, ctdb->nodes[i]->public_address); + ctdb->nodes[i]->takeover_vnn = -1; + } + + talloc_free(lines); + return 0; +} + + +/* + make any IP alias changes for public addresses that are necessary + */ +int ctdb_takeover_run(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap) +{ + int i, j; + int ret; + + /* work out which node will look after each public IP */ + for (i=0;inum;i++) { + if (nodemap->nodes[i].flags & NODE_FLAGS_CONNECTED) { + ctdb->nodes[i]->takeover_vnn = nodemap->nodes[i].vnn; + } else { + /* assign this dead nodes IP to the next higher node */ + for (j=(i+1)%nodemap->num; + j != i; + j=(j+1)%nodemap->num) { + if (nodemap->nodes[j].flags & NODE_FLAGS_CONNECTED) { + ctdb->nodes[i]->takeover_vnn = nodemap->nodes[j].vnn; + break; + } + } + if (j == i) { + DEBUG(0,(__location__ " No node available to assign to??\n")); + return -1; + } + } + } + + /* at this point ctdb->nodes[i]->takeover_vnn is the vnn which will own each IP */ + + + /* now tell all nodes to delete any alias that they should not + have. This will be a NOOP on nodes that don't currently + hold the given alias */ + for (i=0;inum;i++) { + /* don't talk to unconnected nodes */ + if (!(nodemap->nodes[i].flags & NODE_FLAGS_CONNECTED)) continue; + + /* tell this node to delete all of the aliases that it should not have */ + for (j=0;jnum;j++) { + if (ctdb->nodes[j]->takeover_vnn != nodemap->nodes[i].vnn) { + ret = ctdb_ctrl_release_ip(ctdb, TAKEOVER_TIMEOUT(), + nodemap->nodes[i].vnn, + ctdb->nodes[j]->public_address); + if (ret != 0) { + DEBUG(0,("Failed to tell vnn %u to release IP %s\n", + nodemap->nodes[i].vnn, + ctdb->nodes[j]->public_address)); + return -1; + } + } + } + } + + /* tell all nodes to get their own IPs */ + for (i=0;inum;i++) { + ret = ctdb_ctrl_takeover_ip(ctdb, TAKEOVER_TIMEOUT(), + ctdb->nodes[i]->takeover_vnn, + ctdb->nodes[i]->public_address); + if (ret != 0) { + DEBUG(0,("Failed asking vnn %u to take over IP %s\n", + ctdb->nodes[i]->takeover_vnn, + ctdb->nodes[i]->public_address)); + return -1; + } + } + + return 0; +} diff --git a/ctdb/takeover/system.c b/ctdb/takeover/system.c new file mode 100644 index 00000000000..1d808b4c028 --- /dev/null +++ b/ctdb/takeover/system.c @@ -0,0 +1,128 @@ +/* + ctdb recovery code + + Copyright (C) Ronnie Sahlberg 2007 + Copyright (C) Andrew Tridgell 2007 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "includes.h" +#include "system/network.h" +#include "system/filesys.h" +#include "system/wait.h" +#include "../include/ctdb_private.h" +#include +#include + + +/* + send gratuitous arp reply after we have taken over an ip address + + saddr is the address we are trying to claim + iface is the interface name we will be using to claim the address + */ +int ctdb_sys_send_arp(const struct sockaddr_in *saddr, const 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 != AF_LOCAL) { + close(s); + DEBUG(0,(__location__ " not an ethernet 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; + + strncpy(sa.sa_data, iface, sizeof(sa.sa_data)); + 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; + + strncpy(sa.sa_data, iface, sizeof(sa.sa_data)); + ret = sendto(s, buffer, 64, 0, &sa, sizeof(sa)); + if (ret < 0 ){ + DEBUG(0,(__location__ " failed sendto\n")); + return -1; + } + + close(s); + return 0; +} -- 2.47.3