Blob Blame History Raw
From 997074cc3e1ea425ca63e453b7e2181741bdcef0 Mon Sep 17 00:00:00 2001
From: Christine Caulfield <ccaulfie@redhat.com>
Date: Fri, 10 Apr 2015 14:22:07 +0100
Subject: [PATCH] totemconfig: Check for duplicate nodeids

Having duplicate nodeids in corosync.conf can play havoc with a cluster,
so (as suggested by someone on this list) here is some code to check
that all nodeids are unique. Even if a nodeid is not specified it will
check to be sure that the ID generated from the IP address (ipv4 only)
does not clash with one that is provided.

It logs all non-unique nodeids to syslog, but only the last is reported
on the command-line to the user which should be enough to get them to
check further. At startup this will cause corosync to fail to start.

Signed-off-by: Christine Caulfield <ccaulfie@redhat.com>
---
 exec/totemconfig.c |  118 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 118 insertions(+), 0 deletions(-)

diff --git a/exec/totemconfig.c b/exec/totemconfig.c
index b678752..f232ea8 100644
--- a/exec/totemconfig.c
+++ b/exec/totemconfig.c
@@ -481,6 +481,120 @@ static int get_cluster_mcast_addr (
 	return (err);
 }
 
+static unsigned int generate_nodeid_for_duplicate_test(
+	struct totem_config *totem_config,
+	char *addr)
+{
+	unsigned int nodeid;
+	struct totem_ip_address totemip;
+
+	/* AF_INET hard-coded here because auto-generated nodeids
+	   are only for IPv4 */
+	if (totemip_parse(&totemip, addr, AF_INET) != 0)
+		return -1;
+
+	memcpy (&nodeid, &totemip.addr, sizeof (unsigned int));
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+	nodeid = swab32 (nodeid);
+#endif
+
+	if (totem_config->clear_node_high_bit) {
+		nodeid &= 0x7FFFFFFF;
+	}
+	return nodeid;
+}
+
+static int check_for_duplicate_nodeids(
+	struct totem_config *totem_config,
+	const char **error_string)
+{
+	icmap_iter_t iter;
+	icmap_iter_t subiter;
+	const char *iter_key;
+	int res = 0;
+	int retval = 0;
+	char tmp_key[ICMAP_KEYNAME_MAXLEN];
+	char *ring0_addr=NULL;
+	char *ring0_addr1=NULL;
+	unsigned int node_pos;
+	unsigned int node_pos1;
+	unsigned int nodeid;
+	unsigned int nodeid1;
+	int autogenerated;
+
+	iter = icmap_iter_init("nodelist.node.");
+	while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
+		res = sscanf(iter_key, "nodelist.node.%u.%s", &node_pos, tmp_key);
+		if (res != 2) {
+			continue;
+		}
+
+		if (strcmp(tmp_key, "ring0_addr") != 0) {
+			continue;
+		}
+
+		snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.nodeid", node_pos);
+		autogenerated = 0;
+		if (icmap_get_uint32(tmp_key, &nodeid) != CS_OK) {
+
+			snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.ring0_addr", node_pos);
+			if (icmap_get_string(tmp_key, &ring0_addr) != CS_OK) {
+				continue;
+			}
+
+			/* Generate nodeid so we can check that auto-generated nodeids don't clash either */
+			nodeid = generate_nodeid_for_duplicate_test(totem_config, ring0_addr);
+			if (nodeid == -1) {
+				continue;
+			}
+			autogenerated = 1;
+		}
+
+		node_pos1 = 0;
+		subiter = icmap_iter_init("nodelist.node.");
+		while (((iter_key = icmap_iter_next(subiter, NULL, NULL)) != NULL) && (node_pos1 < node_pos)) {
+			res = sscanf(iter_key, "nodelist.node.%u.%s", &node_pos1, tmp_key);
+			if ((res != 2) || (node_pos1 >= node_pos)) {
+				continue;
+			}
+
+			if (strcmp(tmp_key, "ring0_addr") != 0) {
+				continue;
+			}
+
+			snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.nodeid", node_pos1);
+			if (icmap_get_uint32(tmp_key, &nodeid1) != CS_OK) {
+
+				snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.ring0_addr", node_pos1);
+				if (icmap_get_string(tmp_key, &ring0_addr1) != CS_OK) {
+					continue;
+				}
+				nodeid1 = generate_nodeid_for_duplicate_test(totem_config, ring0_addr1);
+				if (nodeid1 == -1) {
+					continue;
+				}
+			}
+
+			if (nodeid == nodeid1) {
+				retval = -1;
+				snprintf (error_string_response, sizeof(error_string_response),
+					  "Nodeid %u%s%s%s appears twice in corosync.conf", nodeid,
+					  autogenerated?"(autogenerated from ":"",
+					  autogenerated?ring0_addr:"",
+					  autogenerated?")":"");
+				log_printf (LOGSYS_LEVEL_ERROR, error_string_response);
+				*error_string = error_string_response;
+				break;
+			}
+		}
+		icmap_iter_finalize(subiter);
+	}
+	icmap_iter_finalize(iter);
+	return retval;
+}
+
+
 static int find_local_node_in_nodelist(struct totem_config *totem_config)
 {
 	icmap_iter_t iter;
@@ -1236,6 +1350,10 @@ int totem_config_validate (
 		return (-1);
 	}
 
+	if (check_for_duplicate_nodeids(totem_config, error_string) == -1) {
+		return (-1);
+	}
+
 	/*
 	 * RRP values validation
 	 */
-- 
1.7.1