mirror of
https://github.com/samba-team/samba.git
synced 2025-02-26 21:57:41 +03:00
updated ctdb tickle management
there is an array for each node/public address that contains tcp tickles we send a TCP_ADD as a broadcast to all nodes when a client is added if tcp tickles are removed, they are only removed immediately from the local node. once every 20 seconds a node will push/broadcast out the tickle list for all public addresses it manages. this will remove any deleted tickles from the remote nodes (This used to be ctdb commit e3c432a915222e1392d91835bc7a73a96ab61ac9)
This commit is contained in:
parent
7b17afdfcd
commit
fca90ce3c3
@ -2119,6 +2119,33 @@ int ctdb_ctrl_killtcp(struct ctdb_context *ctdb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
get a list of all tcp tickles that a node knows about for a particular vnn
|
||||
*/
|
||||
int ctdb_ctrl_get_tcp_tickles(struct ctdb_context *ctdb,
|
||||
struct timeval timeout, uint32_t destnode,
|
||||
TALLOC_CTX *mem_ctx, uint32_t vnn,
|
||||
struct ctdb_control_tcp_tickle_list **list)
|
||||
{
|
||||
int ret;
|
||||
TDB_DATA data, outdata;
|
||||
int32_t status;
|
||||
|
||||
data.dptr = (uint8_t*)&vnn;
|
||||
data.dsize = sizeof(vnn);
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_GET_TCP_TICKLE_LIST, 0, data,
|
||||
mem_ctx, &outdata, &status, NULL, NULL);
|
||||
if (ret != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for get tcp tickles failed\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
*list = (struct ctdb_control_tcp_tickle_list *)outdata.dptr;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
initialise the ctdb daemon for client applications
|
||||
|
@ -37,6 +37,35 @@
|
||||
#define CTDB_NULL_FUNC 0xFF000001
|
||||
#define CTDB_FETCH_FUNC 0xFF000002
|
||||
|
||||
/*
|
||||
a tcp connection description
|
||||
*/
|
||||
struct ctdb_tcp_connection {
|
||||
struct sockaddr_in saddr;
|
||||
struct sockaddr_in daddr;
|
||||
};
|
||||
|
||||
/* the wire representation for a tcp tickle array */
|
||||
struct ctdb_tcp_wire_array {
|
||||
uint32_t num;
|
||||
struct ctdb_tcp_connection connections[1];
|
||||
};
|
||||
|
||||
/* the list of tcp tickles used by get/set tcp tickle list */
|
||||
struct ctdb_control_tcp_tickle_list {
|
||||
uint32_t vnn;
|
||||
struct ctdb_tcp_wire_array tickles;
|
||||
};
|
||||
|
||||
/*
|
||||
array of tcp connections
|
||||
*/
|
||||
struct ctdb_tcp_array {
|
||||
uint32_t num;
|
||||
struct ctdb_tcp_connection *connections;
|
||||
};
|
||||
|
||||
|
||||
/* all tunable variables go in here */
|
||||
struct ctdb_tunable {
|
||||
uint32_t max_redirect_count;
|
||||
@ -51,6 +80,7 @@ struct ctdb_tunable {
|
||||
uint32_t election_timeout;
|
||||
uint32_t takeover_timeout;
|
||||
uint32_t monitor_interval;
|
||||
uint32_t tickle_update_interval;
|
||||
uint32_t script_timeout;
|
||||
uint32_t recovery_grace_period;
|
||||
uint32_t recovery_ban_period;
|
||||
@ -142,6 +172,10 @@ struct ctdb_node {
|
||||
|
||||
/* List of clients to tickle for this public address */
|
||||
struct ctdb_tcp_array *tcp_array;
|
||||
|
||||
/* whether we need to update the other nodes with changes to our list
|
||||
of connected clients */
|
||||
bool tcp_update_needed;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -277,6 +311,7 @@ struct ctdb_context {
|
||||
uint32_t recovery_mode;
|
||||
uint32_t monitoring_mode;
|
||||
TALLOC_CTX *monitor_context;
|
||||
TALLOC_CTX *tickle_update_context;
|
||||
struct ctdb_tunable tunable;
|
||||
enum ctdb_freeze_mode freeze_mode;
|
||||
struct ctdb_freeze_handle *freeze_handle;
|
||||
@ -412,7 +447,8 @@ 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,
|
||||
CTDB_CONTROL_GET_TCP_TICKLE_LIST = 55,
|
||||
CTDB_CONTROL_SET_TCP_TICKLE_LIST = 56,
|
||||
};
|
||||
|
||||
/*
|
||||
@ -946,6 +982,7 @@ uint32_t ctdb_get_num_active_nodes(struct ctdb_context *ctdb);
|
||||
|
||||
void ctdb_stop_monitoring(struct ctdb_context *ctdb);
|
||||
void ctdb_start_monitoring(struct ctdb_context *ctdb);
|
||||
void ctdb_start_tcp_tickle_update(struct ctdb_context *ctdb);
|
||||
void ctdb_send_keepalive(struct ctdb_context *ctdb, uint32_t destnode);
|
||||
|
||||
void ctdb_daemon_cancel_controls(struct ctdb_context *ctdb, struct ctdb_node *node);
|
||||
@ -1011,7 +1048,8 @@ 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);
|
||||
int32_t ctdb_control_get_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata);
|
||||
int32_t ctdb_control_set_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);
|
||||
@ -1059,5 +1097,11 @@ int ctdb_ctrl_killtcp(struct ctdb_context *ctdb,
|
||||
uint32_t destnode,
|
||||
struct ctdb_control_killtcp *killtcp);
|
||||
|
||||
int ctdb_ctrl_get_tcp_tickles(struct ctdb_context *ctdb,
|
||||
struct timeval timeout,
|
||||
uint32_t destnode,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint32_t vnn,
|
||||
struct ctdb_control_tcp_tickle_list **list);
|
||||
|
||||
#endif
|
||||
|
@ -269,10 +269,6 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
|
||||
CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_tcp_vnn));
|
||||
return ctdb_control_tcp_add(ctdb, indata);
|
||||
|
||||
case CTDB_CONTROL_TCP_REMOVE:
|
||||
CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_tcp_vnn));
|
||||
return ctdb_control_tcp_remove(ctdb, indata);
|
||||
|
||||
case CTDB_CONTROL_SET_TUNABLE:
|
||||
return ctdb_control_set_tunable(ctdb, indata);
|
||||
|
||||
@ -290,9 +286,13 @@ 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:
|
||||
case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
|
||||
CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
|
||||
return ctdb_control_get_tcp_tickle_list(ctdb, indata, outdata);
|
||||
|
||||
case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
|
||||
/* data size is verified in the called function */
|
||||
return ctdb_control_tcp_tickle_list(ctdb, indata);
|
||||
return ctdb_control_set_tcp_tickle_list(ctdb, indata);
|
||||
|
||||
default:
|
||||
DEBUG(0,(__location__ " Unknown CTDB control opcode %u\n", opcode));
|
||||
|
@ -87,6 +87,9 @@ static void ctdb_start_transport(struct ctdb_context *ctdb, int status, void *p)
|
||||
|
||||
/* start monitoring for dead nodes */
|
||||
ctdb_start_monitoring(ctdb);
|
||||
|
||||
/* start periodic update of tcp tickle lists */
|
||||
ctdb_start_tcp_tickle_update(ctdb);
|
||||
}
|
||||
|
||||
/* go into main ctdb loop */
|
||||
|
@ -40,33 +40,11 @@ struct ctdb_takeover_arp {
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
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 ctdb_tcp_connection connection;
|
||||
};
|
||||
|
||||
@ -132,7 +110,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;
|
||||
struct ctdb_node *node;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -168,7 +146,7 @@ static void takeover_ip_callback(struct ctdb_context *ctdb, int status,
|
||||
arp->ctdb = ctdb;
|
||||
arp->sin = *state->sin;
|
||||
|
||||
tcparray = ctdb->nodes[state->takeover_vnn]->tcp_array;
|
||||
tcparray = state->node->tcp_array;
|
||||
if (tcparray) {
|
||||
int i;
|
||||
|
||||
@ -177,7 +155,6 @@ static void takeover_ip_callback(struct ctdb_context *ctdb, int status,
|
||||
for (i=0;i<tcparray->num;i++) {
|
||||
struct ctdb_tcp_list *t2 = talloc(arp, struct ctdb_tcp_list);
|
||||
if (t2 == NULL) goto failed;
|
||||
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);
|
||||
@ -188,7 +165,7 @@ static void takeover_ip_callback(struct ctdb_context *ctdb, int status,
|
||||
anymore
|
||||
*/
|
||||
talloc_free(tcparray);
|
||||
ctdb->nodes[state->takeover_vnn]->tcp_array = NULL;
|
||||
state->node->tcp_array = NULL;
|
||||
|
||||
}
|
||||
|
||||
@ -238,10 +215,10 @@ int32_t ctdb_control_takeover_ip(struct ctdb_context *ctdb,
|
||||
struct takeover_callback_state *state;
|
||||
struct ctdb_public_ip *pip = (struct ctdb_public_ip *)indata.dptr;
|
||||
char *ip = inet_ntoa(pip->sin.sin_addr);
|
||||
|
||||
struct ctdb_node *node = ctdb->nodes[pip->vnn];
|
||||
|
||||
/* update out node table */
|
||||
ctdb->nodes[pip->vnn]->takeover_vnn = pip->takeover_vnn;
|
||||
node->takeover_vnn = pip->takeover_vnn;
|
||||
|
||||
/* if our kernel already has this IP, do nothing */
|
||||
if (ctdb_sys_have_ip(ip)) {
|
||||
@ -256,11 +233,7 @@ 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;
|
||||
}
|
||||
state->node = node;
|
||||
|
||||
DEBUG(0,("Takover of IP %s/%u on interface %s\n",
|
||||
ip, ctdb->nodes[ctdb->vnn]->public_netmask_bits,
|
||||
@ -320,7 +293,6 @@ 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_array *tcparray;
|
||||
|
||||
ctdb_start_monitoring(ctdb);
|
||||
|
||||
@ -335,30 +307,6 @@ static void release_ip_callback(struct ctdb_context *ctdb, int status,
|
||||
/* kill clients that have registered with this IP */
|
||||
release_kill_clients(ctdb, state->sin->sin_addr);
|
||||
|
||||
|
||||
/* tell other nodes about any tcp connections we were holding with this IP */
|
||||
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 = 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);
|
||||
}
|
||||
}
|
||||
|
||||
/* the control succeeded */
|
||||
ctdb_request_control_reply(ctdb, state->c, NULL, 0, NULL);
|
||||
talloc_free(state);
|
||||
@ -376,6 +324,7 @@ int32_t ctdb_control_release_ip(struct ctdb_context *ctdb,
|
||||
struct takeover_callback_state *state;
|
||||
struct ctdb_public_ip *pip = (struct ctdb_public_ip *)indata.dptr;
|
||||
char *ip = inet_ntoa(pip->sin.sin_addr);
|
||||
struct ctdb_node *node = ctdb->nodes[pip->vnn];
|
||||
|
||||
/* update out node table */
|
||||
ctdb->nodes[pip->vnn]->takeover_vnn = pip->takeover_vnn;
|
||||
@ -400,11 +349,7 @@ 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;
|
||||
}
|
||||
state->node = node;
|
||||
|
||||
ctdb_stop_monitoring(ctdb);
|
||||
|
||||
@ -707,11 +652,10 @@ int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id,
|
||||
|
||||
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));
|
||||
DEBUG(3,("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;
|
||||
|
||||
@ -795,6 +739,9 @@ int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata)
|
||||
ctdb->nodes[p->vnn]->tcp_array = tcparray;
|
||||
|
||||
tcparray->num = 0;
|
||||
tcparray->connections = talloc_size(tcparray, sizeof(struct ctdb_tcp_connection));
|
||||
CTDB_NO_MEMORY(ctdb, tcparray->connections);
|
||||
|
||||
tcparray->connections[tcparray->num].saddr = p->src;
|
||||
tcparray->connections[tcparray->num].daddr = p->dest;
|
||||
tcparray->num++;
|
||||
@ -814,11 +761,10 @@ int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata)
|
||||
}
|
||||
|
||||
/* 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);
|
||||
tcparray->connections = talloc_realloc(tcparray, tcparray->connections,
|
||||
struct ctdb_tcp_connection,
|
||||
tcparray->num+1);
|
||||
CTDB_NO_MEMORY(ctdb, tcparray->connections);
|
||||
|
||||
ctdb->nodes[p->vnn]->tcp_array = tcparray;
|
||||
tcparray->connections[tcparray->num].saddr = p->src;
|
||||
@ -839,66 +785,63 @@ int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata)
|
||||
clients managing that should tickled with an ACK when IP takeover is
|
||||
done
|
||||
*/
|
||||
int32_t ctdb_control_tcp_remove(struct ctdb_context *ctdb, TDB_DATA indata)
|
||||
static void ctdb_remove_tcp_connection(struct ctdb_context *ctdb, struct ctdb_tcp_connection *conn)
|
||||
{
|
||||
struct ctdb_control_tcp_vnn *p = (struct ctdb_control_tcp_vnn *)indata.dptr;
|
||||
struct ctdb_tcp_array *tcparray;
|
||||
struct ctdb_tcp_connection tcp, *tcpp;
|
||||
struct ctdb_tcp_connection *tcpp;
|
||||
int32_t vnn = find_public_ip_vnn(ctdb, inet_ntoa(conn->daddr.sin_addr));
|
||||
struct ctdb_node *node;
|
||||
|
||||
tcparray = ctdb->nodes[p->vnn]->tcp_array;
|
||||
if (vnn == -1) {
|
||||
DEBUG(0,(__location__ " unable to find public address %s\n", inet_ntoa(conn->daddr.sin_addr)));
|
||||
return;
|
||||
}
|
||||
|
||||
node = ctdb->nodes[vnn];
|
||||
|
||||
/* 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;
|
||||
if (node->tcp_array == NULL) {
|
||||
DEBUG(2,("Trying to remove tickle that doesnt exist (array is empty) %s:%u\n",
|
||||
inet_ntoa(conn->daddr.sin_addr),
|
||||
ntohs(conn->daddr.sin_port)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* 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);
|
||||
tcpp = ctdb_tcp_find(node->tcp_array, conn);
|
||||
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;
|
||||
DEBUG(2,("Trying to remove tickle that doesnt exist %s:%u\n",
|
||||
inet_ntoa(conn->daddr.sin_addr),
|
||||
ntohs(conn->daddr.sin_port)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 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--;
|
||||
*tcpp = node->tcp_array->connections[node->tcp_array->num - 1];
|
||||
node->tcp_array->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;
|
||||
if (node->tcp_array->num == 0) {
|
||||
talloc_free(node->tcp_array);
|
||||
node->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));
|
||||
node->tcp_update_needed = true;
|
||||
|
||||
return 0;
|
||||
DEBUG(2,("Removed tickle info for %s:%u\n",
|
||||
inet_ntoa(conn->saddr.sin_addr),
|
||||
ntohs(conn->saddr.sin_port)));
|
||||
}
|
||||
|
||||
|
||||
@ -920,22 +863,9 @@ int32_t ctdb_control_startup(struct ctdb_context *ctdb, uint32_t vnn)
|
||||
void ctdb_takeover_client_destructor_hook(struct ctdb_client *client)
|
||||
{
|
||||
while (client->tcp_list) {
|
||||
TDB_DATA data;
|
||||
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->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))) {
|
||||
ctdb_daemon_send_control(client->ctdb, CTDB_BROADCAST_CONNECTED, 0,
|
||||
CTDB_CONTROL_TCP_REMOVE,
|
||||
0, CTDB_CTRL_FLAG_NOREPLY, data, NULL, NULL);
|
||||
}
|
||||
talloc_free(tcp);
|
||||
ctdb_remove_tcp_connection(client->ctdb, &tcp->connection);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1232,19 +1162,17 @@ int32_t ctdb_control_kill_tcp(struct ctdb_context *ctdb, TDB_DATA indata)
|
||||
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)
|
||||
int32_t ctdb_control_set_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"));
|
||||
DEBUG(0,("Bad indata in ctdb_control_set_tcp_tickle_list. Not enough data for the tickle.num field\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1253,35 +1181,175 @@ int32_t ctdb_control_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA indata)
|
||||
tickles.connections)
|
||||
+ sizeof(struct ctdb_tcp_connection)
|
||||
* list->tickles.num) {
|
||||
DEBUG(0,("Bad indata in ctdb_control_tcp_tickle_list\n"));
|
||||
DEBUG(0,("Bad indata in ctdb_control_set_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));
|
||||
if (!ctdb_validate_vnn(ctdb, list->vnn)) {
|
||||
DEBUG(0,("Bad indata in ctdb_control_set_tcp_tickle_list. Invalid vnn: %u\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;
|
||||
}
|
||||
talloc_free(ctdb->nodes[list->vnn]->tcp_array);
|
||||
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);
|
||||
tcparray = talloc(ctdb->nodes, struct ctdb_tcp_array);
|
||||
CTDB_NO_MEMORY(ctdb, tcparray);
|
||||
|
||||
memcpy(tcparray, &list->tickles, size);
|
||||
tcparray->num = list->tickles.num;
|
||||
|
||||
tcparray->connections = talloc_array(tcparray, struct ctdb_tcp_connection, tcparray->num);
|
||||
CTDB_NO_MEMORY(ctdb, tcparray->connections);
|
||||
|
||||
memcpy(tcparray->connections, &list->tickles.connections[0],
|
||||
sizeof(struct ctdb_tcp_connection)*tcparray->num);
|
||||
|
||||
/* We now have a new fresh tickle list array for this vnn */
|
||||
ctdb->nodes[list->vnn]->tcp_array = tcparray;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
called to return the full list of tickles for the puclic address associated
|
||||
with the provided vnn
|
||||
*/
|
||||
int32_t ctdb_control_get_tcp_tickle_list(struct ctdb_context *ctdb, TDB_DATA indata, TDB_DATA *outdata)
|
||||
{
|
||||
uint32_t vnn = *(uint32_t *)indata.dptr;
|
||||
struct ctdb_control_tcp_tickle_list *list;
|
||||
struct ctdb_tcp_array *tcparray;
|
||||
int num;
|
||||
|
||||
|
||||
/* Make sure the vnn looks sane */
|
||||
if (!ctdb_validate_vnn(ctdb, vnn)) {
|
||||
DEBUG(0,("Bad indata in ctdb_control_get_tcp_tickle_list. Invalid vnn: %u\n", vnn));
|
||||
return -1;
|
||||
}
|
||||
|
||||
tcparray = ctdb->nodes[vnn]->tcp_array;
|
||||
if (tcparray) {
|
||||
num = tcparray->num;
|
||||
} else {
|
||||
num = 0;
|
||||
}
|
||||
|
||||
outdata->dsize = offsetof(struct ctdb_control_tcp_tickle_list,
|
||||
tickles.connections)
|
||||
+ sizeof(struct ctdb_tcp_connection) * num;
|
||||
|
||||
outdata->dptr = talloc_size(outdata, outdata->dsize);
|
||||
CTDB_NO_MEMORY(ctdb, outdata->dptr);
|
||||
list = (struct ctdb_control_tcp_tickle_list *)outdata->dptr;
|
||||
|
||||
list->vnn = vnn;
|
||||
list->tickles.num = num;
|
||||
if (num) {
|
||||
memcpy(&list->tickles.connections[0], tcparray->connections,
|
||||
sizeof(struct ctdb_tcp_connection) * num);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
set the list of all tcp tickles for a public address
|
||||
*/
|
||||
static int ctdb_ctrl_set_tcp_tickles(struct ctdb_context *ctdb,
|
||||
struct timeval timeout, uint32_t destnode,
|
||||
uint32_t vnn,
|
||||
struct ctdb_tcp_array *tcparray)
|
||||
{
|
||||
int ret, num;
|
||||
TDB_DATA data;
|
||||
struct ctdb_control_tcp_tickle_list *list;
|
||||
|
||||
if (tcparray) {
|
||||
num = tcparray->num;
|
||||
} else {
|
||||
num = 0;
|
||||
}
|
||||
|
||||
data.dsize = offsetof(struct ctdb_control_tcp_tickle_list,
|
||||
tickles.connections) +
|
||||
sizeof(struct ctdb_tcp_connection) * num;
|
||||
data.dptr = talloc_size(ctdb, data.dsize);
|
||||
CTDB_NO_MEMORY(ctdb, data.dptr);
|
||||
|
||||
list = (struct ctdb_control_tcp_tickle_list *)data.dptr;
|
||||
list->vnn = vnn;
|
||||
list->tickles.num = num;
|
||||
if (tcparray) {
|
||||
memcpy(&list->tickles.connections[0], tcparray->connections, sizeof(struct ctdb_tcp_connection) * num);
|
||||
}
|
||||
|
||||
ret = ctdb_daemon_send_control(ctdb, CTDB_BROADCAST_CONNECTED, 0,
|
||||
CTDB_CONTROL_SET_TCP_TICKLE_LIST,
|
||||
0, CTDB_CTRL_FLAG_NOREPLY, data, NULL, NULL);
|
||||
if (ret != 0) {
|
||||
DEBUG(0,(__location__ " ctdb_control for set tcp tickles failed\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
talloc_free(data.dptr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
perform tickle updates if required
|
||||
*/
|
||||
static void ctdb_update_tcp_tickles(struct event_context *ev,
|
||||
struct timed_event *te,
|
||||
struct timeval t, void *private_data)
|
||||
{
|
||||
struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
|
||||
int i, ret;
|
||||
|
||||
for (i=0;i<ctdb->num_nodes;i++) {
|
||||
struct ctdb_node *node = ctdb->nodes[i];
|
||||
|
||||
/* we only send out updates for public addresses that we
|
||||
have taken over
|
||||
*/
|
||||
if (ctdb->vnn != node->takeover_vnn) {
|
||||
continue;
|
||||
}
|
||||
/* We only send out the updates if we need to */
|
||||
if (!node->tcp_update_needed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = ctdb_ctrl_set_tcp_tickles(ctdb,
|
||||
TAKEOVER_TIMEOUT(),
|
||||
CTDB_BROADCAST_CONNECTED,
|
||||
node->takeover_vnn,
|
||||
node->tcp_array);
|
||||
if (ret != 0) {
|
||||
DEBUG(0,("Failed to send the tickle update for public address %s\n", node->public_address));
|
||||
}
|
||||
}
|
||||
|
||||
event_add_timed(ctdb->ev, ctdb->tickle_update_context,
|
||||
timeval_current_ofs(ctdb->tunable.tickle_update_interval, 0),
|
||||
ctdb_update_tcp_tickles, ctdb);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
start periodic update of tcp tickles
|
||||
*/
|
||||
void ctdb_start_tcp_tickle_update(struct ctdb_context *ctdb)
|
||||
{
|
||||
ctdb->tickle_update_context = talloc_new(ctdb);
|
||||
|
||||
event_add_timed(ctdb->ev, ctdb->tickle_update_context,
|
||||
timeval_current_ofs(ctdb->tunable.tickle_update_interval, 0),
|
||||
ctdb_update_tcp_tickles, ctdb);
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ static const struct {
|
||||
{ "ElectionTimeout", 3, offsetof(struct ctdb_tunable, election_timeout) },
|
||||
{ "TakeoverTimeout", 5, offsetof(struct ctdb_tunable, takeover_timeout) },
|
||||
{ "MonitorInterval", 15, offsetof(struct ctdb_tunable, monitor_interval) },
|
||||
{ "TickleUpdateInterval",20, offsetof(struct ctdb_tunable, tickle_update_interval) },
|
||||
{ "EventScriptTimeout", 20, offsetof(struct ctdb_tunable, script_timeout) },
|
||||
{ "RecoveryGracePeriod", 60, offsetof(struct ctdb_tunable, recovery_grace_period) },
|
||||
{ "RecoveryBanPeriod", 300, offsetof(struct ctdb_tunable, recovery_ban_period) },
|
||||
|
@ -302,6 +302,39 @@ static int control_status(struct ctdb_context *ctdb, int argc, const char **argv
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
get a list of all tickles for this vnn
|
||||
*/
|
||||
static int control_get_tickles(struct ctdb_context *ctdb, int argc, const char **argv)
|
||||
{
|
||||
struct ctdb_control_tcp_tickle_list *list;
|
||||
uint32_t vnn;
|
||||
int i, ret;
|
||||
|
||||
if (argc < 1) {
|
||||
usage();
|
||||
}
|
||||
|
||||
vnn = strtoul(argv[0], NULL, 0);
|
||||
|
||||
ret = ctdb_ctrl_get_tcp_tickles(ctdb, TIMELIMIT(), options.vnn, ctdb, vnn, &list);
|
||||
if (ret == -1) {
|
||||
printf("Unable to list tickles\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Tickles for vnn:%u\n", list->vnn);
|
||||
printf("Num tickles:%u\n", list->tickles.num);
|
||||
for (i=0;i<list->tickles.num;i++) {
|
||||
printf("SRC: %s:%u ", inet_ntoa(list->tickles.connections[i].saddr.sin_addr), ntohs(list->tickles.connections[i].saddr.sin_port));
|
||||
printf("DST: %s:%u\n", inet_ntoa(list->tickles.connections[i].daddr.sin_addr), ntohs(list->tickles.connections[i].daddr.sin_port));
|
||||
}
|
||||
|
||||
talloc_free(list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
kill a tcp connection
|
||||
*/
|
||||
@ -894,6 +927,7 @@ static const struct {
|
||||
{ "thaw", control_thaw, true, "thaw all databases" },
|
||||
{ "killtcp", kill_tcp, false, "kill a tcp connection.", "<srcip:port> <dstip:port>" },
|
||||
{ "tickle", tickle_tcp, false, "send a tcp tickle ack", "<srcip:port> <dstip:port>" },
|
||||
{ "gettickles", control_get_tickles, false, "get the list of tickles registered for this vnn", "<vnn>" },
|
||||
};
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user