1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-03 01:18:10 +03:00

ctdb: add/implement CTDB_CONTROL_TCP_CLIENT_PASSED

With multichannel a tcp connection is registered first with
a temporary smbd process, that calls CTDB_CONTROL_TCP_CLIENT
first and then passes the tcp connection to the longterm smbd
that already handles all connections belonging to the specific
client_guid. That smbd process calls CTDB_CONTROL_TCP_CLIENT
again, but the 'tickle' information is already there.
When the temporary smbd process exists/disconnects from ctdb
or calls CTDB_CONTROL_TCP_CLIENT_DISCONNECTED, the 'tickle'
information is removed, while the longterm smbd process
still serves the tcp connection.

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

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Martin Schwenke <martin@meltin.net>
This commit is contained in:
Stefan Metzmacher 2023-11-17 15:59:57 +01:00
parent c6602b686b
commit 037e8e449d
6 changed files with 73 additions and 0 deletions

View File

@ -895,6 +895,9 @@ int32_t ctdb_control_tcp_client(struct ctdb_context *ctdb, uint32_t client_id,
int32_t ctdb_control_tcp_client_disconnected(struct ctdb_context *ctdb,
uint32_t client_id,
TDB_DATA indata);
int32_t ctdb_control_tcp_client_passed(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);

View File

@ -382,6 +382,7 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS = 0,
CTDB_CONTROL_DISABLE_NODE = 157,
CTDB_CONTROL_ENABLE_NODE = 158,
CTDB_CONTROL_TCP_CLIENT_DISCONNECTED = 159,
CTDB_CONTROL_TCP_CLIENT_PASSED = 160,
};
#define MAX_COUNT_BUCKETS 16

View File

@ -414,6 +414,10 @@ static size_t ctdb_req_control_data_len(struct ctdb_req_control_data *cd)
case CTDB_CONTROL_TCP_CLIENT_DISCONNECTED:
len = ctdb_connection_len(cd->data.conn);
break;
case CTDB_CONTROL_TCP_CLIENT_PASSED:
len = ctdb_connection_len(cd->data.conn);
break;
}
return len;
@ -1028,6 +1032,14 @@ static int ctdb_req_control_data_pull(uint8_t *buf, size_t buflen,
&cd->data.conn,
&np);
break;
case CTDB_CONTROL_TCP_CLIENT_PASSED:
ret = ctdb_connection_pull(buf,
buflen,
mem_ctx,
&cd->data.conn,
&np);
break;
}
if (ret != 0) {
@ -1391,6 +1403,9 @@ static size_t ctdb_reply_control_data_len(struct ctdb_reply_control_data *cd)
case CTDB_CONTROL_TCP_CLIENT_DISCONNECTED:
break;
case CTDB_CONTROL_TCP_CLIENT_PASSED:
break;
}
return len;

View File

@ -246,6 +246,7 @@ static void ctdb_opcode_print(uint32_t opcode, FILE *fp)
{ CTDB_CONTROL_DISABLE_NODE, "DISABLE_NODE" },
{ CTDB_CONTROL_ENABLE_NODE, "ENABLE_NODE" },
{ CTDB_CONTROL_TCP_CLIENT_DISCONNECTED, "TCP_CLIENT_DISCONNECTED" },
{ CTDB_CONTROL_TCP_CLIENT_PASSED, "TCP_CLIENT_PASSED" },
{ MAP_END, "" },
};

View File

@ -872,6 +872,10 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
return ctdb_control_tcp_client_disconnected(ctdb, client_id, indata);
case CTDB_CONTROL_TCP_CLIENT_PASSED:
CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
return ctdb_control_tcp_client_passed(ctdb, client_id, indata);
default:
DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode));
return -1;

View File

@ -1463,6 +1463,55 @@ int32_t ctdb_control_tcp_client_disconnected(struct ctdb_context *ctdb,
return 0;
}
/*
called by a client to inform us of a TCP connection was passed to a different
"client" (typically with multichannel to another smbd process).
*/
int32_t ctdb_control_tcp_client_passed(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;
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 from %s not found "
"(client_id %u pid %u).\n",
conn_str, client_id, client->pid);
return 0;
}
D_INFO("TCP connection from %s "
"(client_id %u pid %u) passed to another client\n",
conn_str, client_id, client->pid);
/*
* We don't call CTDB_CONTROL_TCP_REMOVE
* nor ctdb_remove_connection() as the connection
* is still alive, but handled by another client
*/
return 0;
}
/*
find a tcp address on a list
*/