Răsfoiți Sursa

qnetd: Validate tie-breaker, algo and node dup

If new client request tie-breaker or algo which differes from rest of
cluster, error message is sent back. Also it's checked if node is not
duplicate by comparing node id.

Signed-off-by: Jan Friesse <jfriesse@redhat.com>
Jan Friesse 10 ani în urmă
părinte
comite
55fddb8e65
3 a modificat fișierele cu 68 adăugiri și 1 ștergeri
  1. 51 0
      qdevices/qnetd-client-msg-received.c
  2. 11 0
      qdevices/tlv.c
  3. 6 1
      qdevices/tlv.h

+ 51 - 0
qdevices/qnetd-client-msg-received.c

@@ -246,6 +246,52 @@ qnetd_client_msg_received_server_error(struct qnetd_instance *instance, struct q
 	return (qnetd_client_msg_received_unexpected_msg(client, msg, "server error"));
 }
 
+/*
+ * Checks if new client send information are valid. It means:
+ * - in cluster is no duplicate node with same nodeid
+ * - it has same tie_breaker as other nodes in cluster
+ * - it has same algorithm as other nodes in cluster
+ */
+static enum tlv_reply_error_code
+qnetd_client_msg_received_init_check_new_client(struct qnetd_instance *instance,
+    struct qnetd_client *new_client)
+{
+	struct qnetd_cluster *cluster;
+	struct qnetd_client *client;
+
+	cluster = qnetd_cluster_list_find_by_name(&instance->clusters, new_client->cluster_name,
+	    new_client->cluster_name_len);
+
+	if (cluster == NULL) {
+		return (TLV_REPLY_ERROR_CODE_NO_ERROR);
+	}
+
+	TAILQ_FOREACH(client, &cluster->client_list, cluster_entries) {
+		if (!tlv_tie_breaker_eq(&new_client->tie_breaker, &client->tie_breaker)) {
+			qnetd_log(LOG_ERR, "Received init message contains tie-breaker which "
+			    "differs from rest of cluster. Sending error reply");
+
+			return (TLV_REPLY_ERROR_CODE_TIE_BREAKER_DIFFERS_FROM_OTHER_NODES);
+		}
+
+		if (new_client->decision_algorithm != client->decision_algorithm) {
+			qnetd_log(LOG_ERR, "Received init message contains algorithm which "
+			    "differs from rest of cluster. Sending error reply");
+
+			return (TLV_REPLY_ERROR_CODE_ALGORITHM_DIFFERS_FROM_OTHER_NODES);
+		}
+
+		if (new_client->node_id == client->node_id) {
+			qnetd_log(LOG_ERR, "Received init message contains node id which is "
+			    "duplicate of other node in cluster. Sending error reply");
+
+			return (TLV_REPLY_ERROR_CODE_DUPLICATE_NODE_ID);
+		}
+	}
+
+	return (TLV_REPLY_ERROR_CODE_NO_ERROR);
+}
+
 static int
 qnetd_client_msg_received_init(struct qnetd_instance *instance, struct qnetd_client *client,
     const struct msg_decoded *msg)
@@ -377,6 +423,11 @@ qnetd_client_msg_received_init(struct qnetd_instance *instance, struct qnetd_cli
 		client->decision_algorithm = msg->decision_algorithm;
 	}
 
+	if (reply_error_code == TLV_REPLY_ERROR_CODE_NO_ERROR) {
+		reply_error_code = qnetd_client_msg_received_init_check_new_client(instance,
+		    client);
+	}
+
 	if (reply_error_code == TLV_REPLY_ERROR_CODE_NO_ERROR) {
 		cluster = qnetd_cluster_list_add_client(&instance->clusters, client);
 		if (cluster == NULL) {

+ 11 - 0
qdevices/tlv.c

@@ -969,6 +969,17 @@ tlv_ring_id_eq(const struct tlv_ring_id *rid1, const struct tlv_ring_id *rid2)
 	return (rid1->node_id == rid2->node_id && rid1->seq == rid2->seq);
 }
 
+int
+tlv_tie_breaker_eq(const struct tlv_tie_breaker *tb1, const struct tlv_tie_breaker *tb2)
+{
+
+	if (tb1->mode == tb2->mode && tb1->mode == TLV_TIE_BREAKER_MODE_NODE_ID) {
+		return (tb1->node_id == tb2->node_id);
+	}
+
+	return (tb1->mode == tb2->mode);
+}
+
 const char *
 tlv_vote_to_str(enum tlv_vote vote)
 {

+ 6 - 1
qdevices/tlv.h

@@ -91,7 +91,9 @@ enum tlv_reply_error_code {
 	TLV_REPLY_ERROR_CODE_UNSUPPORTED_DECISION_ALGORITHM = 12,
 	TLV_REPLY_ERROR_CODE_INVALID_HEARTBEAT_INTERVAL = 13,
 	TLV_REPLY_ERROR_CODE_UNSUPPORTED_DECISION_ALGORITHM_MESSAGE = 14,
-	TLV_REPLY_ERROR_CODE_DECISION_ALGORITHM_ALREADY_REGISTERED = 15,
+	TLV_REPLY_ERROR_CODE_TIE_BREAKER_DIFFERS_FROM_OTHER_NODES = 15,
+	TLV_REPLY_ERROR_CODE_ALGORITHM_DIFFERS_FROM_OTHER_NODES = 16,
+	TLV_REPLY_ERROR_CODE_DUPLICATE_NODE_ID = 17,
 };
 
 enum tlv_decision_algorithm_type {
@@ -316,6 +318,9 @@ extern void			 tlv_get_supported_options(enum tlv_opt_type **supported_options,
 extern int			 tlv_ring_id_eq(const struct tlv_ring_id *rid1,
     const struct tlv_ring_id *rid2);
 
+extern int			 tlv_tie_breaker_eq(const struct tlv_tie_breaker *tb1,
+    const struct tlv_tie_breaker *tb2);
+
 extern const char *		 tlv_vote_to_str(enum tlv_vote vote);
 
 extern const char *		 tlv_node_state_to_str(enum tlv_node_state state);