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

change the tickle list from one global list into an array per public

ip/node

once we have started sending all tickles for a specific ip   delete the 
entire array   so that the tickles dont remain forever in the ctdb 
server

add a control to send the full list of every tickle that is registered 
for a particular public ip/node

(This used to be ctdb commit d0eee33e44d3f8e26debbec21d41e2cbdbb520e6)
This commit is contained in:
Ronnie Sahlberg 2007-07-20 10:06:41 +10:00
parent 865e68db2b
commit 7b17afdfcd
3 changed files with 298 additions and 97 deletions

View File

@ -139,6 +139,9 @@ struct ctdb_node {
/* 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;
/* List of clients to tickle for this public address */
struct ctdb_tcp_array *tcp_array;
};
/*
@ -305,7 +308,6 @@ struct ctdb_context {
uint32_t recovery_master;
struct ctdb_call_state *pending_calls;
struct ctdb_takeover takeover;
struct ctdb_tcp_list *tcp_list;
struct ctdb_client_ip *client_ip_list;
bool do_setsched;
void *saved_scheduler_param;
@ -410,6 +412,7 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS = 0,
CTDB_CONTROL_MODIFY_FLAGS = 52,
CTDB_CONTROL_GET_ALL_TUNABLES = 53,
CTDB_CONTROL_KILL_TCP = 54,
CTDB_CONTROL_TCP_TICKLE_LIST = 55,
};
/*
@ -1003,11 +1006,12 @@ int ctdb_set_event_script(struct ctdb_context *ctdb, const char *script);
int ctdb_takeover_run(struct ctdb_context *ctdb, struct ctdb_node_map *nodemap);
int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id,
uint32_t srcnode, TDB_DATA indata);
TDB_DATA indata);
int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata);
int32_t ctdb_control_tcp_remove(struct ctdb_context *ctdb, TDB_DATA indata);
int32_t ctdb_control_startup(struct ctdb_context *ctdb, uint32_t vnn);
int32_t ctdb_control_kill_tcp(struct ctdb_context *ctdb, TDB_DATA indata);
int32_t ctdb_control_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA indata);
void ctdb_takeover_client_destructor_hook(struct ctdb_client *client);
int ctdb_event_script(struct ctdb_context *ctdb, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);

View File

@ -259,7 +259,7 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
case CTDB_CONTROL_TCP_CLIENT:
CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_tcp));
return ctdb_control_tcp_client(ctdb, client_id, srcnode, indata);
return ctdb_control_tcp_client(ctdb, client_id, indata);
case CTDB_CONTROL_STARTUP:
CHECK_CONTROL_DATA_SIZE(0);
@ -290,6 +290,10 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_killtcp));
return ctdb_control_kill_tcp(ctdb, indata);
case CTDB_CONTROL_TCP_TICKLE_LIST:
/* data size is verified in the called function */
return ctdb_control_tcp_tickle_list(ctdb, indata);
default:
DEBUG(0,(__location__ " Unknown CTDB control opcode %u\n", opcode));
return -1;

View File

@ -39,17 +39,37 @@ struct ctdb_takeover_arp {
struct ctdb_tcp_list *tcp_list;
};
/*
a tcp connection description
*/
struct ctdb_tcp_connection {
struct sockaddr_in saddr;
struct sockaddr_in daddr;
};
/*
array of tcp connections
*/
struct ctdb_tcp_array {
uint32_t num;
struct ctdb_tcp_connection connections[1];
};
struct ctdb_control_tcp_tickle_list {
int32_t vnn;
struct ctdb_tcp_array tickles;
};
/*
lists of tcp endpoints
*/
struct ctdb_tcp_list {
struct ctdb_tcp_list *prev, *next;
uint32_t vnn;
struct sockaddr_in saddr;
struct sockaddr_in daddr;
struct ctdb_tcp_connection connection;
};
/*
list of clients to kill on IP release
*/
@ -85,13 +105,14 @@ static void ctdb_control_send_arp(struct event_context *ev, struct timed_event *
for (tcp=arp->tcp_list;tcp;tcp=tcp->next) {
DEBUG(2,("sending tcp tickle ack for %u->%s:%u\n",
(unsigned)ntohs(tcp->daddr.sin_port),
inet_ntoa(tcp->saddr.sin_addr),
(unsigned)ntohs(tcp->saddr.sin_port)));
ret = ctdb_sys_send_tcp(s, &tcp->saddr, &tcp->daddr, 0, 0, 0);
(unsigned)ntohs(tcp->connection.daddr.sin_port),
inet_ntoa(tcp->connection.saddr.sin_addr),
(unsigned)ntohs(tcp->connection.saddr.sin_port)));
ret = ctdb_sys_send_tcp(s, &tcp->connection.saddr,
&tcp->connection.daddr, 0, 0, 0);
if (ret != 0) {
DEBUG(0,(__location__ " Failed to send tcp tickle ack for %s\n",
inet_ntoa(tcp->saddr.sin_addr)));
inet_ntoa(tcp->connection.saddr.sin_addr)));
}
}
@ -111,6 +132,7 @@ static void ctdb_control_send_arp(struct event_context *ev, struct timed_event *
struct takeover_callback_state {
struct ctdb_req_control *c;
struct sockaddr_in *sin;
int32_t takeover_vnn;
};
/*
@ -123,7 +145,7 @@ static void takeover_ip_callback(struct ctdb_context *ctdb, int status,
talloc_get_type(private_data, struct takeover_callback_state);
struct ctdb_takeover_arp *arp;
char *ip = inet_ntoa(state->sin->sin_addr);
struct ctdb_tcp_list *tcp;
struct ctdb_tcp_array *tcparray;
ctdb_start_monitoring(ctdb);
@ -146,15 +168,28 @@ static void takeover_ip_callback(struct ctdb_context *ctdb, int status,
arp->ctdb = ctdb;
arp->sin = *state->sin;
/* add all of the known tcp connections for this IP to the
list of tcp connections to send tickle acks for */
for (tcp=ctdb->tcp_list;tcp;tcp=tcp->next) {
if (state->sin->sin_addr.s_addr == tcp->daddr.sin_addr.s_addr) {
tcparray = ctdb->nodes[state->takeover_vnn]->tcp_array;
if (tcparray) {
int i;
/* add all of the known tcp connections for this IP to the
list of tcp connections to send tickle acks for */
for (i=0;i<tcparray->num;i++) {
struct ctdb_tcp_list *t2 = talloc(arp, struct ctdb_tcp_list);
if (t2 == NULL) goto failed;
*t2 = *tcp;
t2->vnn = state->takeover_vnn;
t2->connection.saddr = tcparray->connections[i].saddr;
t2->connection.daddr = tcparray->connections[i].daddr;
DLIST_ADD(arp->tcp_list, t2);
}
/* Delete the entire tickle array for this public address
We have tickled them now so we dont need them
anymore
*/
talloc_free(tcparray);
ctdb->nodes[state->takeover_vnn]->tcp_array = NULL;
}
event_add_timed(arp->ctdb->ev, arp->ctdb->takeover.last_ctx,
@ -171,6 +206,26 @@ failed:
return;
}
/*
Find the vnn of the node that has a public ip address
returns -1 if the address is not known as a public address
*/
static int32_t find_public_ip_vnn(struct ctdb_context *ctdb, char *ip)
{
int32_t vnn = -1;
int i;
for (i=0;i<ctdb->num_nodes;i++) {
if (!strcmp(ip, ctdb->nodes[i]->public_address)) {
vnn = i;
break;
}
}
return vnn;
}
/*
take over an ip address
*/
@ -201,6 +256,12 @@ int32_t ctdb_control_takeover_ip(struct ctdb_context *ctdb,
CTDB_NO_MEMORY(ctdb, state->sin);
*state->sin = pip->sin;
state->takeover_vnn = find_public_ip_vnn(ctdb, ip);
if (state->takeover_vnn == -1) {
DEBUG(0,("Could not takover of IP %s. It is not a public address.\n", ip));
return -1;
}
DEBUG(0,("Takover of IP %s/%u on interface %s\n",
ip, ctdb->nodes[ctdb->vnn]->public_netmask_bits,
ctdb->takeover.interface));
@ -259,7 +320,7 @@ static void release_ip_callback(struct ctdb_context *ctdb, int status,
talloc_get_type(private_data, struct takeover_callback_state);
char *ip = inet_ntoa(state->sin->sin_addr);
TDB_DATA data;
struct ctdb_tcp_list *tcp;
struct ctdb_tcp_array *tcparray;
ctdb_start_monitoring(ctdb);
@ -276,21 +337,25 @@ static void release_ip_callback(struct ctdb_context *ctdb, int status,
/* tell other nodes about any tcp connections we were holding with this IP */
for (tcp=ctdb->tcp_list;tcp;tcp=tcp->next) {
if (tcp->vnn == ctdb->vnn &&
state->sin->sin_addr.s_addr == tcp->daddr.sin_addr.s_addr) {
tcparray = ctdb->nodes[state->takeover_vnn]->tcp_array;
if (tcparray) {
int i;
for (i=0;i<tcparray->num;i++) {
struct ctdb_control_tcp_vnn t;
t.vnn = ctdb->vnn;
t.src = tcp->saddr;
t.dest = tcp->daddr;
t.vnn = state->takeover_vnn;
t.src = tcparray->connections[i].saddr;
t.dest = tcparray->connections[i].daddr;
data.dptr = (uint8_t *)&t;
data.dsize = sizeof(t);
ctdb_daemon_send_control(ctdb, CTDB_BROADCAST_CONNECTED, 0,
CTDB_CONTROL_TCP_ADD,
0, CTDB_CTRL_FLAG_NOREPLY, data, NULL, NULL);
ctdb_daemon_send_control(ctdb,
CTDB_BROADCAST_CONNECTED, 0,
CTDB_CONTROL_TCP_ADD, 0,
CTDB_CTRL_FLAG_NOREPLY, data,
NULL, NULL);
}
}
@ -299,7 +364,6 @@ static void release_ip_callback(struct ctdb_context *ctdb, int status,
talloc_free(state);
}
/*
release an ip address
*/
@ -336,6 +400,12 @@ int32_t ctdb_control_release_ip(struct ctdb_context *ctdb,
CTDB_NO_MEMORY(ctdb, state->sin);
*state->sin = pip->sin;
state->takeover_vnn = find_public_ip_vnn(ctdb, ip);
if (state->takeover_vnn == -1) {
DEBUG(0,("Could not release IP %s. It is not a public address.\n", ip));
return -1;
}
ctdb_stop_monitoring(ctdb);
ret = ctdb_event_script_callback(ctdb,
@ -608,7 +678,7 @@ static int ctdb_client_ip_destructor(struct ctdb_client_ip *ip)
called by a client to inform us of a TCP connection that it is managing
that should tickled with an ACK when IP takeover is done
*/
int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id, uint32_t vnn,
int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id,
TDB_DATA indata)
{
struct ctdb_client *client = ctdb_reqid_find(ctdb, client_id, struct ctdb_client);
@ -618,6 +688,8 @@ int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id, u
int ret;
TDB_DATA data;
struct ctdb_client_ip *ip;
char *addr;
int32_t takeover_vnn;
ip = talloc(client, struct ctdb_client_ip);
CTDB_NO_MEMORY(ctdb, ip);
@ -631,13 +703,21 @@ int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id, u
tcp = talloc(client, struct ctdb_tcp_list);
CTDB_NO_MEMORY(ctdb, tcp);
tcp->vnn = vnn;
tcp->saddr = p->src;
tcp->daddr = p->dest;
addr = inet_ntoa(p->src.sin_addr);
takeover_vnn = find_public_ip_vnn(ctdb, addr);
if (takeover_vnn == -1) {
DEBUG(0,("Could not add client IP %s. It is not a public address.\n", addr));
return -1;
}
tcp->vnn = takeover_vnn;
tcp->connection.saddr = p->src;
tcp->connection.daddr = p->dest;
DLIST_ADD(client->tcp_list, tcp);
t.vnn = vnn;
t.vnn = takeover_vnn;
t.src = p->src;
t.dest = p->dest;
@ -646,7 +726,7 @@ int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id, u
DEBUG(2,("registered tcp client for %u->%s:%u\n",
(unsigned)ntohs(p->dest.sin_port),
inet_ntoa(p->src.sin_addr),
addr,
(unsigned)ntohs(p->src.sin_port)));
/* tell all nodes about this tcp connection */
@ -674,15 +754,20 @@ static bool same_sockaddr_in(struct sockaddr_in *in1, struct sockaddr_in *in2)
/*
find a tcp address on a list
*/
static struct ctdb_tcp_list *ctdb_tcp_find(struct ctdb_tcp_list *list,
struct ctdb_tcp_list *tcp)
static struct ctdb_tcp_connection *ctdb_tcp_find(struct ctdb_tcp_array *array,
struct ctdb_tcp_connection *tcp)
{
while (list) {
if (same_sockaddr_in(&list->saddr, &tcp->saddr) &&
same_sockaddr_in(&list->daddr, &tcp->daddr)) {
return list;
int i;
if (array == NULL) {
return NULL;
}
for (i=0;i<array->num;i++) {
if (same_sockaddr_in(&array->connections[i].saddr, &tcp->saddr) &&
same_sockaddr_in(&array->connections[i].daddr, &tcp->daddr)) {
return &array->connections[i];
}
list = list->next;
}
return NULL;
}
@ -695,26 +780,56 @@ static struct ctdb_tcp_list *ctdb_tcp_find(struct ctdb_tcp_list *list,
int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata)
{
struct ctdb_control_tcp_vnn *p = (struct ctdb_control_tcp_vnn *)indata.dptr;
struct ctdb_tcp_list *tcp;
struct ctdb_tcp_array *tcparray;
struct ctdb_tcp_connection tcp;
tcp = talloc(ctdb, struct ctdb_tcp_list);
CTDB_NO_MEMORY(ctdb, tcp);
tcp->vnn = p->vnn;
tcp->saddr = p->src;
tcp->daddr = p->dest;
tcparray = ctdb->nodes[p->vnn]->tcp_array;
if (NULL == ctdb_tcp_find(ctdb->tcp_list, tcp)) {
DLIST_ADD(ctdb->tcp_list, tcp);
DEBUG(2,("Added tickle info for %s:%u from vnn %u\n",
inet_ntoa(tcp->daddr.sin_addr), ntohs(tcp->daddr.sin_port),
tcp->vnn));
} else {
DEBUG(4,("Already had tickle info for %s:%u from vnn %u\n",
inet_ntoa(tcp->daddr.sin_addr), ntohs(tcp->daddr.sin_port),
tcp->vnn));
/* If this is the first tickle */
if (tcparray == NULL) {
tcparray = talloc_size(ctdb->nodes,
offsetof(struct ctdb_tcp_array, connections) +
sizeof(struct ctdb_tcp_connection) * 1);
CTDB_NO_MEMORY(ctdb, tcparray);
ctdb->nodes[p->vnn]->tcp_array = tcparray;
tcparray->num = 0;
tcparray->connections[tcparray->num].saddr = p->src;
tcparray->connections[tcparray->num].daddr = p->dest;
tcparray->num++;
return 0;
}
/* Do we already have this tickle ?*/
tcp.saddr = p->src;
tcp.daddr = p->dest;
if (ctdb_tcp_find(ctdb->nodes[p->vnn]->tcp_array, &tcp) != NULL) {
DEBUG(4,("Already had tickle info for %s:%u from vnn %u\n",
inet_ntoa(tcp.daddr.sin_addr),
ntohs(tcp.daddr.sin_port),
p->vnn));
return 0;
}
/* A new tickle, we must add it to the array */
tcparray = talloc_realloc(ctdb->nodes, tcparray,
struct ctdb_tcp_array,
offsetof(struct ctdb_tcp_array, connections) +
sizeof(struct ctdb_tcp_connection) * (tcparray->num+1) );
CTDB_NO_MEMORY(ctdb, tcparray);
ctdb->nodes[p->vnn]->tcp_array = tcparray;
tcparray->connections[tcparray->num].saddr = p->src;
tcparray->connections[tcparray->num].daddr = p->dest;
tcparray->num++;
DEBUG(2,("Added tickle info for %s:%u from vnn %u\n",
inet_ntoa(tcp.daddr.sin_addr),
ntohs(tcp.daddr.sin_port),
p->vnn));
return 0;
}
@ -727,56 +842,73 @@ int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata)
int32_t ctdb_control_tcp_remove(struct ctdb_context *ctdb, TDB_DATA indata)
{
struct ctdb_control_tcp_vnn *p = (struct ctdb_control_tcp_vnn *)indata.dptr;
struct ctdb_tcp_list t, *tcp;
struct ctdb_tcp_array *tcparray;
struct ctdb_tcp_connection tcp, *tcpp;
t.vnn = p->vnn;
t.saddr = p->src;
t.daddr = p->dest;
tcparray = ctdb->nodes[p->vnn]->tcp_array;
tcp = ctdb_tcp_find(ctdb->tcp_list, &t);
if (tcp) {
DEBUG(2,("Removed tickle info for %s:%u from vnn %u\n",
inet_ntoa(tcp->daddr.sin_addr), ntohs(tcp->daddr.sin_port),
tcp->vnn));
DLIST_REMOVE(ctdb->tcp_list, tcp);
talloc_free(tcp);
/* if the array is empty we cant remove it
and we dont need to do anything
*/
if (tcparray == NULL) {
DEBUG(2,("Trying to remove tickle that doesnt exist (array is empty) %s:%u from vnn %u\n",
inet_ntoa(p->dest.sin_addr),
ntohs(p->dest.sin_port),
p->vnn));
return 0;
}
/* See if we know this connection
if we dont know this connection then we dont need to do anything
*/
tcp.saddr = p->src;
tcp.daddr = p->dest;
tcpp = ctdb_tcp_find(ctdb->nodes[p->vnn]->tcp_array, &tcp);
if (tcpp == NULL) {
DEBUG(2,("Trying to remove tickle that doesnt exist %s:%u from vnn %u\n",
inet_ntoa(p->dest.sin_addr),
ntohs(p->dest.sin_port),
p->vnn));
return 0;
}
/* We need to remove this entry from the array.
Instead of allocating a new array and copying data to it
we cheat and just copy the last entry in the existing array
to the entry that is to be removed and just shring the
->num field
*/
tcpp->saddr = tcparray->connections[tcparray->num-1].saddr;
tcpp->daddr = tcparray->connections[tcparray->num-1].daddr;
tcparray->num--;
/* If we deleted the last entry we also need to remove the entire array
*/
if (tcparray->num == 0) {
talloc_free(tcparray);
ctdb->nodes[p->vnn]->tcp_array = NULL;
}
DEBUG(2,("Removed tickle info for %s:%u from vnn %u\n",
inet_ntoa(p->src.sin_addr),
ntohs(p->src.sin_port),
p->vnn));
return 0;
}
/*
called when a daemon restarts - wipes all tcp entries from that vnn
called when a daemon restarts - send all tickes for all public addresses
we are serving immediately to the new node.
*/
int32_t ctdb_control_startup(struct ctdb_context *ctdb, uint32_t vnn)
{
struct ctdb_tcp_list *tcp, *next;
for (tcp=ctdb->tcp_list;tcp;tcp=next) {
next = tcp->next;
if (tcp->vnn == vnn) {
DLIST_REMOVE(ctdb->tcp_list, tcp);
talloc_free(tcp);
}
/* and tell the new guy about any that he should have
from us */
if (tcp->vnn == ctdb->vnn) {
struct ctdb_control_tcp_vnn t;
TDB_DATA data;
t.vnn = tcp->vnn;
t.src = tcp->saddr;
t.dest = tcp->daddr;
data.dptr = (uint8_t *)&t;
data.dsize = sizeof(t);
ctdb_daemon_send_control(ctdb, vnn, 0,
CTDB_CONTROL_TCP_ADD,
0, CTDB_CTRL_FLAG_NOREPLY, data, NULL, NULL);
}
}
/*XXX here we should send all tickes we are serving to the new node */
return 0;
}
@ -792,9 +924,10 @@ void ctdb_takeover_client_destructor_hook(struct ctdb_client *client)
struct ctdb_control_tcp_vnn p;
struct ctdb_tcp_list *tcp = client->tcp_list;
DLIST_REMOVE(client->tcp_list, tcp);
p.vnn = tcp->vnn;
p.src = tcp->saddr;
p.dest = tcp->daddr;
p.vnn = tcp->vnn;
p.src = tcp->connection.saddr;
p.dest = tcp->connection.daddr;
data.dptr = (uint8_t *)&p;
data.dsize = sizeof(p);
if (ctdb_sys_have_ip(inet_ntoa(p.dest.sin_addr))) {
@ -1092,3 +1225,63 @@ int32_t ctdb_control_kill_tcp(struct ctdb_context *ctdb, TDB_DATA indata)
return 0;
}
/*
called by a daemon to inform us of the entire list of TCP tickles for
a particular public address.
this control should only be sent by the node that is currently serving
that public address.
*/
int32_t ctdb_control_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA indata)
{
struct ctdb_control_tcp_tickle_list *list = (struct ctdb_control_tcp_tickle_list *)indata.dptr;
struct ctdb_tcp_array *tcparray;
int size;
/* We must at least have tickles.num or else we cant verify the size
of the received data blob
*/
if (indata.dsize < offsetof(struct ctdb_control_tcp_tickle_list,
tickles.connections)) {
DEBUG(0,("Bad indata in ctdb_control_tcp_tickle_list. Not enough data for the tickle.num field\n"));
return -1;
}
/* verify that the size of data matches what we expect */
if (indata.dsize < offsetof(struct ctdb_control_tcp_tickle_list,
tickles.connections)
+ sizeof(struct ctdb_tcp_connection)
* list->tickles.num) {
DEBUG(0,("Bad indata in ctdb_control_tcp_tickle_list\n"));
return -1;
}
/* Make sure the vnn looks sane */
if ( (list->vnn < 0) || (list->vnn >= ctdb->num_nodes) ) {
DEBUG(0,("Bad indata in ctdb_control_tcp_tickle_list. Invalid vnn:%d\n", list->vnn));
return -1;
}
/* remove any old ticklelist we might have */
tcparray = ctdb->nodes[list->vnn]->tcp_array;
if (tcparray) {
talloc_free(tcparray);
ctdb->nodes[list->vnn]->tcp_array = NULL;
}
/* allocate a new tcparray and copy all data that was sent to us */
size = offsetof(struct ctdb_tcp_array, connections) +
sizeof(struct ctdb_tcp_connection) * list->tickles.num;
tcparray = talloc_size(ctdb->nodes, size);
CTDB_NO_MEMORY(ctdb, tcparray);
memcpy(tcparray, &list->tickles, size);
/* We now have a new fresh tickle list array for this vnn */
ctdb->nodes[list->vnn]->tcp_array = tcparray;
return 0;
}