1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

new files for IP takeover

(This used to be ctdb commit 9232501a6bb9ee5d67a3b7cc87752d82ede162a6)
This commit is contained in:
Andrew Tridgell 2007-05-25 17:16:50 +10:00
parent 56e3eed3d1
commit 613c6b9c4c
2 changed files with 306 additions and 0 deletions

View File

@ -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;i<nlines;i++) {
ctdb->nodes[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;i<nodemap->num;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;i<nodemap->num;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;j<nodemap->num;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;i<nodemap->num;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;
}

128
ctdb/takeover/system.c Normal file
View File

@ -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 <net/ethernet.h>
#include <net/if_arp.h>
/*
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;
}