ctdb-daemon: Add AllowMixedVersions tunable
[samba.git] / ctdb / server / ctdb_keepalive.c
index b4899b746f471ce3f4cde40faa22455b98f6178f..a4569ec2502265af2d0ebed32e8a210339a24ad1 100644 (file)
    along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "lib/tevent/tevent.h"
+#include "replace.h"
 #include "system/filesys.h"
+#include "system/network.h"
+#include "system/time.h"
 #include "system/wait.h"
-#include "../include/ctdb_private.h"
 
+#include <talloc.h>
+#include <tevent.h>
+
+#include "lib/util/debug.h"
+#include "lib/util/samba_util.h"
+
+#include "ctdb_private.h"
+#include "version.h"
+
+#include "common/common.h"
+#include "common/logging.h"
+
+
+static uint32_t keepalive_version(void)
+{
+       return (SAMBA_VERSION_MAJOR << 16) | SAMBA_VERSION_MINOR;
+}
+
+static uint32_t keepalive_uptime(struct ctdb_context *ctdb)
+{
+       struct timeval current = tevent_timeval_current();
+
+       return current.tv_sec - ctdb->ctdbd_start_time.tv_sec;
+}
+
+/*
+   send a keepalive packet to the other node
+*/
+static void ctdb_send_keepalive(struct ctdb_context *ctdb, uint32_t destnode)
+{
+       struct ctdb_req_keepalive_old *r;
+
+       if (ctdb->methods == NULL) {
+               DEBUG(DEBUG_INFO,
+                     ("Failed to send keepalive. Transport is DOWN\n"));
+               return;
+       }
+
+       r = ctdb_transport_allocate(ctdb, ctdb, CTDB_REQ_KEEPALIVE,
+                                   sizeof(struct ctdb_req_keepalive_old),
+                                   struct ctdb_req_keepalive_old);
+       CTDB_NO_MEMORY_FATAL(ctdb, r);
+       r->hdr.destnode  = destnode;
+       r->hdr.reqid     = 0;
+
+       r->version = keepalive_version();
+       r->uptime = keepalive_uptime(ctdb);
+
+       CTDB_INCREMENT_STAT(ctdb, keepalive_packets_sent);
+
+       ctdb_queue_packet(ctdb, &r->hdr);
+
+       talloc_free(r);
+}
 
 /*
   see if any nodes are dead
  */
-static void ctdb_check_for_dead_nodes(struct event_context *ev, struct timed_event *te, 
+static void ctdb_check_for_dead_nodes(struct tevent_context *ev,
+                                     struct tevent_timer *te,
                                      struct timeval t, void *private_data)
 {
        struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
@@ -78,26 +133,31 @@ static void ctdb_check_for_dead_nodes(struct event_context *ev, struct timed_eve
 
                node->tx_cnt = 0;
        }
-       
-       event_add_timed(ctdb->ev, ctdb->keepalive_ctx,
-                       timeval_current_ofs(ctdb->tunable.keepalive_interval, 0), 
-                       ctdb_check_for_dead_nodes, ctdb);
+
+       tevent_add_timer(ctdb->ev, ctdb->keepalive_ctx,
+                        timeval_current_ofs(ctdb->tunable.keepalive_interval, 0),
+                        ctdb_check_for_dead_nodes, ctdb);
 }
 
 
 void ctdb_start_keepalive(struct ctdb_context *ctdb)
 {
-       struct timed_event *te;
+       struct tevent_timer *te;
 
        ctdb->keepalive_ctx = talloc_new(ctdb);
        CTDB_NO_MEMORY_FATAL(ctdb, ctdb->keepalive_ctx);
 
-       te = event_add_timed(ctdb->ev, ctdb->keepalive_ctx,
-                            timeval_current_ofs(ctdb->tunable.keepalive_interval, 0), 
-                            ctdb_check_for_dead_nodes, ctdb);
+       te = tevent_add_timer(ctdb->ev, ctdb->keepalive_ctx,
+                             timeval_current_ofs(ctdb->tunable.keepalive_interval, 0),
+                             ctdb_check_for_dead_nodes, ctdb);
        CTDB_NO_MEMORY_FATAL(ctdb, te);
 
        DEBUG(DEBUG_NOTICE,("Keepalive monitoring has been started\n"));
+
+       if (ctdb->tunable.allow_mixed_versions == 1) {
+               DEBUG(DEBUG_WARNING,
+                     ("CTDB cluster with mixed versions configured\n"));
+       }
 }
 
 void ctdb_stop_keepalive(struct ctdb_context *ctdb)
@@ -106,3 +166,49 @@ void ctdb_stop_keepalive(struct ctdb_context *ctdb)
        ctdb->keepalive_ctx = NULL;
 }
 
+void ctdb_request_keepalive(struct ctdb_context *ctdb,
+                           struct ctdb_req_header *hdr)
+{
+       struct ctdb_req_keepalive_old *c =
+               (struct ctdb_req_keepalive_old *)hdr;
+       uint32_t my_version = keepalive_version();
+       uint32_t my_uptime = keepalive_uptime(ctdb);
+
+       /* Don't check anything if mixed versions are allowed */
+       if (ctdb->tunable.allow_mixed_versions == 1) {
+               return;
+       }
+
+       if (hdr->length == sizeof(struct ctdb_req_header)) {
+               /* Old keepalive */
+               goto fail1;
+       }
+
+       if (c->version != my_version) {
+               if (c->uptime > my_uptime) {
+                       goto fail2;
+               } else if (c->uptime == my_uptime) {
+                       if (c->version > my_version) {
+                               goto fail2;
+                       }
+               }
+       }
+
+       return;
+
+fail1:
+       DEBUG(DEBUG_ERR,
+             ("Keepalive version missing from node %u\n", hdr->srcnode));
+       goto shutdown;
+
+fail2:
+       DEBUG(DEBUG_ERR,
+             ("Keepalive version mismatch 0x%08x != 0x%08x from node %u\n",
+              my_version, c->version, hdr->srcnode));
+       goto shutdown;
+
+shutdown:
+       DEBUG(DEBUG_ERR,
+             ("CTDB Cluster with mixed versions, cannot continue\n"));
+       ctdb_shutdown_sequence(ctdb, 0);
+}