ctdb: add/implement CTDB_CONTROL_TCP_CLIENT_DISCONNECTED
authorStefan Metzmacher <metze@samba.org>
Wed, 15 Nov 2023 15:31:53 +0000 (16:31 +0100)
committerStefan Metzmacher <metze@samba.org>
Fri, 15 Dec 2023 11:06:34 +0000 (11:06 +0000)
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 <metze@samba.org>
Reviewed-by: Martin Schwenke <martin@meltin.net>
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 37842a151d68c11e5c36f944ff6dc68266569e62..ca350df2cf478068f47f76ff9a3e6d45f54455df 100644 (file)
@@ -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);
index fb6e39f33b55142602ee8642ef2ae56b7e86e709..42b992ae6db0df531ff6d33e8fc95575aa1cae1c 100644 (file)
@@ -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
index a7c797f5dbca2d818d2cf91cab6417b0302860bb..5e2cf13c579be75965fe354a9cb68513bae88999 100644 (file)
@@ -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;
@@ -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) {
@@ -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;
index d94cb548d68b66f17efe315526d114b87a6b8526..2dc4a702eae1899ce3aabd69ff7408e91066abd2 100644 (file)
@@ -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, "" },
        };
 
index 08268512bfa0d5b5426e8afabdb2b5aa98e539b1..3ea93f52cfe459babb87fdb3cb791576e45db2e4 100644 (file)
@@ -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;
index ac7f461ac0267851897d848cbfb2ccd735752653..da3077e5140727e0bc1f7053af952c6b16a9ad09 100644 (file)
@@ -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
  */