mirror of
https://github.com/samba-team/samba.git
synced 2025-02-02 09:47:23 +03:00
add controls to take over and release an ip address
add sending of grat arp both normal grat arp (request) and also unsolicited grat arp replies (This used to be ctdb commit 7305c00c21c30bdbafc3722a018513378bd307e6)
This commit is contained in:
parent
ec25710fc0
commit
2b6c39a0af
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 },
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user