Skip to content

Commit

Permalink
ctdb: add/implement CTDB_CONTROL_TCP_CLIENT_DISCONNECTED
Browse files Browse the repository at this point in the history
With multichannel a ctdb connection from smbd may hold multiple
tcp connections, which can be disconnected before the smbd
process terminates the whole ctdb connection, so we a
way to remove undo 'CTDB_CONTROL_TCP_CLIENT' again.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15523

Signed-off-by: Stefan Metzmacher <[email protected]>
Reviewed-by: Martin Schwenke <[email protected]>
  • Loading branch information
metze-samba committed Dec 15, 2023
1 parent 8395fd3 commit c6602b6
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 0 deletions.
3 changes: 3 additions & 0 deletions ctdb/include/ctdb_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,9 @@ int ctdb_set_public_addresses(struct ctdb_context *ctdb, bool check_addresses);

int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id,
TDB_DATA indata);
int32_t ctdb_control_tcp_client_disconnected(struct ctdb_context *ctdb,
uint32_t client_id,
TDB_DATA indata);
int32_t ctdb_control_tcp_add(struct ctdb_context *ctdb, TDB_DATA indata,
bool tcp_update_needed);
int32_t ctdb_control_tcp_remove(struct ctdb_context *ctdb, TDB_DATA indata);
Expand Down
1 change: 1 addition & 0 deletions ctdb/protocol/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS = 0,
CTDB_CONTROL_ECHO_DATA = 156,
CTDB_CONTROL_DISABLE_NODE = 157,
CTDB_CONTROL_ENABLE_NODE = 158,
CTDB_CONTROL_TCP_CLIENT_DISCONNECTED = 159,
};

#define MAX_COUNT_BUCKETS 16
Expand Down
15 changes: 15 additions & 0 deletions ctdb/protocol/protocol_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,10 @@ static size_t ctdb_req_control_data_len(struct ctdb_req_control_data *cd)

case CTDB_CONTROL_ENABLE_NODE:
break;

case CTDB_CONTROL_TCP_CLIENT_DISCONNECTED:
len = ctdb_connection_len(cd->data.conn);
break;
}

return len;
Expand Down Expand Up @@ -1016,6 +1020,14 @@ static int ctdb_req_control_data_pull(uint8_t *buf, size_t buflen,
&cd->data.echo_data,
&np);
break;

case CTDB_CONTROL_TCP_CLIENT_DISCONNECTED:
ret = ctdb_connection_pull(buf,
buflen,
mem_ctx,
&cd->data.conn,
&np);
break;
}

if (ret != 0) {
Expand Down Expand Up @@ -1376,6 +1388,9 @@ static size_t ctdb_reply_control_data_len(struct ctdb_reply_control_data *cd)

case CTDB_CONTROL_ENABLE_NODE:
break;

case CTDB_CONTROL_TCP_CLIENT_DISCONNECTED:
break;
}

return len;
Expand Down
1 change: 1 addition & 0 deletions ctdb/protocol/protocol_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ static void ctdb_opcode_print(uint32_t opcode, FILE *fp)
{ CTDB_CONTROL_ECHO_DATA, "ECHO_DATA" },
{ CTDB_CONTROL_DISABLE_NODE, "DISABLE_NODE" },
{ CTDB_CONTROL_ENABLE_NODE, "ENABLE_NODE" },
{ CTDB_CONTROL_TCP_CLIENT_DISCONNECTED, "TCP_CLIENT_DISCONNECTED" },
{ MAP_END, "" },
};

Expand Down
4 changes: 4 additions & 0 deletions ctdb/server/ctdb_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,10 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
CHECK_CONTROL_DATA_SIZE(0);
return ctdb_control_enable_node(ctdb);

case CTDB_CONTROL_TCP_CLIENT_DISCONNECTED:
CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
return ctdb_control_tcp_client_disconnected(ctdb, client_id, indata);

default:
DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode));
return -1;
Expand Down
86 changes: 86 additions & 0 deletions ctdb/server/ctdb_takeover.c
Original file line number Diff line number Diff line change
Expand Up @@ -1377,6 +1377,92 @@ int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id,
return 0;
}

static bool ctdb_client_remove_tcp(struct ctdb_client *client,
const struct ctdb_connection *conn)
{
struct ctdb_tcp_list *tcp = NULL;
struct ctdb_tcp_list *tcp_next = NULL;
bool found = false;

for (tcp = client->tcp_list; tcp != NULL; tcp = tcp_next) {
bool same;

tcp_next = tcp->next;

same = ctdb_connection_same(conn, &tcp->connection);
if (!same) {
continue;
}

TALLOC_FREE(tcp);
found = true;
}

return found;
}

/*
called by a client to inform us of a TCP connection that was disconnected
*/
int32_t ctdb_control_tcp_client_disconnected(struct ctdb_context *ctdb,
uint32_t client_id,
TDB_DATA indata)
{
struct ctdb_client *client = reqid_find(ctdb->idr, client_id, struct ctdb_client);
struct ctdb_connection *tcp_sock = NULL;
int ret;
TDB_DATA data;
char conn_str[132] = { 0, };
bool found = false;

tcp_sock = (struct ctdb_connection *)indata.dptr;

ctdb_canonicalize_ip_inplace(&tcp_sock->src);
ctdb_canonicalize_ip_inplace(&tcp_sock->dst);

ret = ctdb_connection_to_buf(conn_str,
sizeof(conn_str),
tcp_sock,
false,
" -> ");
if (ret != 0) {
strlcpy(conn_str, "UNKNOWN", sizeof(conn_str));
}

found = ctdb_client_remove_tcp(client, tcp_sock);
if (!found) {
DBG_DEBUG("TCP connection %s not found "
"(client_id %u pid %u).\n",
conn_str, client_id, client->pid);
return 0;
}

D_INFO("deregistered TCP connection %s "
"(client_id %u pid %u)\n",
conn_str, client_id, client->pid);

data.dptr = (uint8_t *)tcp_sock;
data.dsize = sizeof(*tcp_sock);

/* tell all nodes about this tcp connection is gone */
ret = ctdb_daemon_send_control(ctdb,
CTDB_BROADCAST_CONNECTED,
0,
CTDB_CONTROL_TCP_REMOVE,
0,
CTDB_CTRL_FLAG_NOREPLY,
data,
NULL,
NULL);
if (ret != 0) {
DBG_ERR("Failed to send CTDB_CONTROL_TCP_REMOVE: %s\n",
conn_str);
return -1;
}

return 0;
}

/*
find a tcp address on a list
*/
Expand Down

0 comments on commit c6602b6

Please sign in to comment.