ctdb: add/implement CTDB_CONTROL_TCP_CLIENT_PASSED
authorStefan Metzmacher <metze@samba.org>
Fri, 17 Nov 2023 14:59:57 +0000 (15:59 +0100)
committerJule Anger <janger@samba.org>
Sat, 16 Dec 2023 15:07:14 +0000 (15:07 +0000)
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>
(cherry picked from commit 037e8e449deb136ad5ed5e4de05439411b545b6d)

ctdb/include/ctdb_private.h
ctdb/protocol/protocol.h
ctdb/protocol/protocol_control.c
ctdb/protocol/protocol_debug.c
ctdb/server/ctdb_control.c
ctdb/server/ctdb_takeover.c

index ca350df2cf478068f47f76ff9a3e6d45f54455df..802781237781e907f9ea6671dfe7a8b443c2a3c7 100644 (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);
index 42b992ae6db0df531ff6d33e8fc95575aa1cae1c..3b66c403ab84547e1e8dfb36ad35e846aac585c7 100644 (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
index 5e2cf13c579be75965fe354a9cb68513bae88999..83ed6cb4ee189c6e021f1d1b694fe82f02c446fd 100644 (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;
index 2dc4a702eae1899ce3aabd69ff7408e91066abd2..ae091b04d321e96d44401d018f83195dc4884ccd 100644 (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, "" },
        };
 
index 3ea93f52cfe459babb87fdb3cb791576e45db2e4..422c4cf1e58eeead442df0e8e6b2ca0ba2d4a905 100644 (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;
index da3077e5140727e0bc1f7053af952c6b16a9ad09..1668e5697399bf058eab381d93c1b3189d4a6dd3 100644 (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
  */