Просмотр исходного кода

config: Allow dynamic link configuration

Now we are using knet, it's possible to dynamically add, remove and
reconfigure links on the fly.

Also print 'n' for non-existant knet links. This will show up
only on loopback links >0. But it looks better than 'status ='

Signed-off-by: Christine Caulfield <ccaulfie@redhat.com>
Reviewed-by: Jan Friesse <jfriesse@redhat.com>
Christine Caulfield 8 лет назад
Родитель
Сommit
294a629fb5

+ 4 - 0
exec/cfg.c

@@ -759,6 +759,10 @@ static void message_handler_req_lib_cfg_ringstatusget (
 		totem_ip_string
 		  = (const char *)api->totem_ip_print (&interfaces[i]);
 
+		if (!totem_ip_string) {
+			totem_ip_string="";
+		}
+
 		if (strlen(totem_ip_string) >= CFG_INTERFACE_NAME_MAX_LEN) {
 			log_printf(LOGSYS_LEVEL_ERROR, "String representation of interface %u is too long", i);
 			res = CS_ERR_NAME_TOO_LONG;

+ 278 - 191
exec/totemconfig.c

@@ -178,7 +178,7 @@ static void totem_volatile_config_read (struct totem_config *totem_config, const
 
 	totem_volatile_config_set_value(totem_config, "totem.token", deleted_key, TOKEN_TIMEOUT, 0);
 
-	if (totem_config->interface_count > 0 && totem_config->interfaces[0].member_count > 2) {
+	if (totem_config->interfaces[0].member_count > 2) {
 		u32 = TOKEN_COEFFICIENT;
 		icmap_get_uint32("totem.token_coefficient", &u32);
 		totem_config->token_timeout += (totem_config->interfaces[0].member_count - 2) * u32;
@@ -609,8 +609,7 @@ static int find_local_node_in_nodelist(struct totem_config *totem_config)
  * (set to 0), and ips which are only in set1 or set2 remains untouched.
  * totempg_node_add/remove is called.
  */
-static void compute_interfaces_diff(int interface_count,
-	struct totem_interface *set1,
+static void compute_interfaces_diff(struct totem_interface *set1,
 	struct totem_interface *set2)
 {
 	int ring_no, set1_pos, set2_pos;
@@ -618,7 +617,11 @@ static void compute_interfaces_diff(int interface_count,
 
 	memset(&empty_ip_address, 0, sizeof(empty_ip_address));
 
-	for (ring_no = 0; ring_no < interface_count; ring_no++) {
+	for (ring_no = 0; ring_no < INTERFACE_MAX; ring_no++) {
+		if (!set1[ring_no].configured && !set2[ring_no].configured) {
+			continue;
+		}
+
 		for (set1_pos = 0; set1_pos < set1[ring_no].member_count; set1_pos++) {
 			for (set2_pos = 0; set2_pos < set2[ring_no].member_count; set2_pos++) {
 				/*
@@ -637,7 +640,7 @@ static void compute_interfaces_diff(int interface_count,
 		}
 	}
 
-	for (ring_no = 0; ring_no < interface_count; ring_no++) {
+	for (ring_no = 0; ring_no < INTERFACE_MAX; ring_no++) {
 		for (set1_pos = 0; set1_pos < set1[ring_no].member_count; set1_pos++) {
 			/*
 			 * All items which remained in set1 doesn't exists in set2 any longer so
@@ -652,6 +655,9 @@ static void compute_interfaces_diff(int interface_count,
 				totempg_member_remove(&set1[ring_no].member_list[set1_pos], ring_no);
 			}
 		}
+		if (!set2[ring_no].configured) {
+			continue;
+		}
 		for (set2_pos = 0; set2_pos < set2[ring_no].member_count; set2_pos++) {
 			/*
 			 * All items which remained in set2 doesn't existed in set1 so this is no node
@@ -669,6 +675,56 @@ static void compute_interfaces_diff(int interface_count,
 	}
 }
 
+/*
+ * Reconfigure links in totempg. Sets new local IP address and adds params for new links.
+ */
+static void reconfigure_links(struct totem_config *totem_config)
+{
+	int i;
+	char tmp_key[ICMAP_KEYNAME_MAXLEN];
+	char *addr_string;
+	struct totem_ip_address local_ip;
+	int err;
+	unsigned int local_node_pos = find_local_node_in_nodelist(totem_config);
+
+	for (i = 0; i<INTERFACE_MAX; i++) {
+		if (!totem_config->interfaces[i].configured) {
+			continue;
+		}
+
+		log_printf(LOGSYS_LEVEL_INFO, "Configuring link %d\n", i);
+
+		snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.ring%u_addr", local_node_pos, i);
+		if (icmap_get_string(tmp_key, &addr_string) != CS_OK) {
+			continue;
+		}
+
+		err = totemip_parse(&local_ip, addr_string, AF_UNSPEC);
+		if (err != 0) {
+			continue;
+		}
+		local_ip.nodeid = totem_config->node_id;
+
+		/* In case this is a new link, fill in the defaults if there was no interface{} section for it */
+		if (!totem_config->interfaces[i].knet_link_priority)
+			totem_config->interfaces[i].knet_link_priority = 1;
+		if (!totem_config->interfaces[i].knet_ping_interval)
+			totem_config->interfaces[i].knet_ping_interval = KNET_PING_INTERVAL;
+		if (!totem_config->interfaces[i].knet_ping_timeout)
+			totem_config->interfaces[i].knet_ping_timeout = KNET_PING_TIMEOUT;
+		if (!totem_config->interfaces[i].knet_ping_precision)
+			totem_config->interfaces[i].knet_ping_precision = KNET_PING_PRECISION;
+		if (!totem_config->interfaces[i].knet_pong_count)
+			totem_config->interfaces[i].knet_pong_count = KNET_PONG_COUNT;
+		if (!totem_config->interfaces[i].knet_transport)
+			totem_config->interfaces[i].knet_transport = KNET_TRANSPORT_UDP;
+		if (!totem_config->interfaces[i].ip_port)
+			totem_config->interfaces[i].ip_port = DEFAULT_PORT;
+
+		totempg_iface_set(&local_ip, totem_config->interfaces[i].ip_port, i);
+	}
+}
+
 static void put_nodelist_members_to_config(struct totem_config *totem_config, int reload)
 {
 	icmap_iter_t iter, iter2;
@@ -681,7 +737,6 @@ static void put_nodelist_members_to_config(struct totem_config *totem_config, in
 	int member_count;
 	unsigned int linknumber = 0;
 	int i, j;
-	struct totem_interface *orig_interfaces = NULL;
 	struct totem_interface *new_interfaces = NULL;
 
 	if (reload) {
@@ -690,16 +745,12 @@ static void put_nodelist_members_to_config(struct totem_config *totem_config, in
 		 * not all totem structures are initialized so corosync will crash during
 		 * member_add/remove
 		 */
-		orig_interfaces = malloc (sizeof (struct totem_interface) * INTERFACE_MAX);
-		assert(orig_interfaces != NULL);
 		new_interfaces = malloc (sizeof (struct totem_interface) * INTERFACE_MAX);
 		assert(new_interfaces != NULL);
-
-		memcpy(orig_interfaces, totem_config->interfaces, sizeof (struct totem_interface) * INTERFACE_MAX);
 	}
 
 	/* Clear out nodelist so we can put the new one in if needed */
-	for (i = 0; i < totem_config->interface_count; i++) {
+	for (i = 0; i < INTERFACE_MAX; i++) {
 		for (j = 0; j < PROCESSOR_COUNT_MAX; j++) {
 			memset(&totem_config->interfaces[i].member_list[j], 0, sizeof(struct totem_ip_address));
 		}
@@ -743,6 +794,8 @@ static void put_nodelist_members_to_config(struct totem_config *totem_config, in
 				totem_config->interfaces[linknumber].member_list[member_count].nodeid = nodeid;
 				totem_config->interfaces[linknumber].member_count++;
 			}
+
+			totem_config->interfaces[linknumber].configured = 1;
 			free(node_addr_str);
 		}
 
@@ -752,12 +805,14 @@ static void put_nodelist_members_to_config(struct totem_config *totem_config, in
 	icmap_iter_finalize(iter);
 
 	if (reload) {
+		log_printf(LOGSYS_LEVEL_DEBUG, "About to reconfigure links from nodelist.\n");
+		reconfigure_links(totem_config);
+
 		memcpy(new_interfaces, totem_config->interfaces, sizeof (struct totem_interface) * INTERFACE_MAX);
 
-		compute_interfaces_diff(totem_config->interface_count, orig_interfaces, new_interfaces);
+		compute_interfaces_diff(totem_config->orig_interfaces, new_interfaces);
 
 		free(new_interfaces);
-		free(orig_interfaces);
 	}
 }
 
@@ -932,108 +987,33 @@ static void config_convert_nodelist_to_interface(struct totem_config *totem_conf
 	}
 }
 
-
-extern int totem_config_read (
-	struct totem_config *totem_config,
-	const char **error_string,
-	uint64_t *warnings)
+static int get_interface_params(struct totem_config *totem_config,
+				const char **error_string, uint64_t *warnings,
+				int reload)
 {
 	int res = 0;
-	char *str, *ring0_addr_str;
 	unsigned int linknumber = 0;
 	int member_count = 0;
+	int i;
 	icmap_iter_t iter, member_iter;
 	const char *iter_key;
 	const char *member_iter_key;
 	char linknumber_key[ICMAP_KEYNAME_MAXLEN];
 	char tmp_key[ICMAP_KEYNAME_MAXLEN];
 	uint8_t u8;
-	uint16_t u16;
 	uint32_t u32;
+	char *str;
 	char *cluster_name = NULL;
-	int i;
-	int local_node_pos;
-	int nodeid_set;
-
-	*warnings = 0;
-
-	memset (totem_config, 0, sizeof (struct totem_config));
-	totem_config->interfaces = malloc (sizeof (struct totem_interface) * INTERFACE_MAX);
-	if (totem_config->interfaces == 0) {
-		*error_string = "Out of memory trying to allocate ethernet interface storage area";
-		return -1;
-	}
-
-	memset (totem_config->interfaces, 0,
-		sizeof (struct totem_interface) * INTERFACE_MAX);
-
-	strcpy (totem_config->link_mode, "passive");
-
-	icmap_get_uint32("totem.version", (uint32_t *)&totem_config->version);
-
-	if (totem_get_crypto(totem_config) != 0) {
-		*error_string = "crypto_cipher requires crypto_hash with value other than none";
-		return -1;
-	}
-
-	if (icmap_get_string("totem.link_mode", &str) == CS_OK) {
-		if (strlen(str) >= TOTEM_LINK_MODE_BYTES) {
-			*error_string = "totem.link_mode is too long";
-			free(str);
-
-			return -1;
-		}
-		strcpy (totem_config->link_mode, str);
-		free(str);
-	}
 
-	icmap_get_uint32("totem.nodeid", &totem_config->node_id);
-
-	totem_config->clear_node_high_bit = 0;
-	if (icmap_get_string("totem.clear_node_high_bit", &str) == CS_OK) {
-		if (strcmp (str, "yes") == 0) {
-			totem_config->clear_node_high_bit = 1;
+	if (reload) {
+		for (i=0; i<INTERFACE_MAX; i++) {
+			totem_config->interfaces[i].configured = 0;
 		}
-		free(str);
 	}
-
-	icmap_get_uint32("totem.threads", &totem_config->threads);
-
-	icmap_get_uint32("totem.netmtu", &totem_config->net_mtu);
-
 	if (icmap_get_string("totem.cluster_name", &cluster_name) != CS_OK) {
 		cluster_name = NULL;
 	}
 
-	totem_config->ip_version = totem_config_get_ip_version();
-
-	if (icmap_get_string("totem.interface.0.bindnetaddr", &str) != CS_OK) {
-		/*
-		 * We were not able to find ring 0 bindnet addr. Try to use nodelist informations
-		 */
-		config_convert_nodelist_to_interface(totem_config);
-	} else {
-		if (icmap_get_string("nodelist.node.0.ring0_addr", &ring0_addr_str) == CS_OK) {
-			/*
-			 * Both bindnetaddr and ring0_addr are set.
-			 * Log warning information, and use nodelist instead
-			 */
-			*warnings |= TOTEM_CONFIG_BINDNETADDR_NODELIST_SET;
-
-			config_convert_nodelist_to_interface(totem_config);
-
-			free(ring0_addr_str);
-		}
-
-		free(str);
-	}
-
-	/*
-	 * Broadcast option is global but set in interface section,
-	 * so reset before processing interfaces.
-	 */
-	totem_config->broadcast_use = 0;
-
 	iter = icmap_iter_init("totem.interface.");
 	while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
 		res = sscanf(iter_key, "totem.interface.%[^.].%s", linknumber_key, tmp_key);
@@ -1041,12 +1021,11 @@ extern int totem_config_read (
 			continue;
 		}
 
-		if (strcmp(tmp_key, "bindnetaddr") != 0) {
+		if (strcmp(tmp_key, "bindnetaddr") != 0 && totem_config->transport_number == TOTEM_TRANSPORT_UDP) {
 			continue;
 		}
 
 		member_count = 0;
-
 		linknumber = atoi(linknumber_key);
 
 		if (linknumber >= INTERFACE_MAX) {
@@ -1060,65 +1039,88 @@ extern int totem_config_read (
 			return -1;
 		}
 
-		/*
-		 * Get the bind net address
-		 */
-		if (icmap_get_string(iter_key, &str) == CS_OK) {
-			res = totemip_parse (&totem_config->interfaces[linknumber].bindnet, str,
-			    totem_config->ip_version);
-			free(str);
-		}
+		/* These things are only valid for the initial read */
+		if (!reload) {
+			/*
+			 * Get the bind net address
+			 */
+			if (icmap_get_string(iter_key, &str) == CS_OK) {
+				res = totemip_parse (&totem_config->interfaces[linknumber].bindnet, str,
+						     totem_config->ip_version);
+				free(str);
+			}
 
-		/*
-		 * Get interface multicast address
-		 */
-		snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastaddr", linknumber);
-		if (icmap_get_string(tmp_key, &str) == CS_OK) {
-			res = totemip_parse (&totem_config->interfaces[linknumber].mcast_addr, str, totem_config->ip_version);
-			free(str);
-		} else {
 			/*
-			 * User not specified address -> autogenerate one from cluster_name key
-			 * (if available). Return code is intentionally ignored, because
-			 * udpu doesn't need mcastaddr and validity of mcastaddr for udp is
-			 * checked later anyway.
+			 * Get interface multicast address
 			 */
-			(void)get_cluster_mcast_addr (cluster_name,
-					linknumber,
-					totem_config->ip_version,
-					&totem_config->interfaces[linknumber].mcast_addr);
-		}
+			snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastaddr", linknumber);
+			if (icmap_get_string(tmp_key, &str) == CS_OK) {
+				res = totemip_parse (&totem_config->interfaces[linknumber].mcast_addr, str, totem_config->ip_version);
+				free(str);
+			} else {
+				/*
+				 * User not specified address -> autogenerate one from cluster_name key
+				 * (if available). Return code is intentionally ignored, because
+				 * udpu doesn't need mcastaddr and validity of mcastaddr for udp is
+				 * checked later anyway.
+				 */
+				(void)get_cluster_mcast_addr (cluster_name,
+							      linknumber,
+							      totem_config->ip_version,
+							      &totem_config->interfaces[linknumber].mcast_addr);
+			}
 
-		snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.broadcast", linknumber);
-		if (icmap_get_string(tmp_key, &str) == CS_OK) {
-			if (strcmp (str, "yes") == 0) {
-				totem_config->broadcast_use = 1;
+			snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.broadcast", linknumber);
+			if (icmap_get_string(tmp_key, &str) == CS_OK) {
+				if (strcmp (str, "yes") == 0) {
+					totem_config->broadcast_use = 1;
+				}
+				free(str);
 			}
-			free(str);
 		}
 
-		/*
-		 * Get mcast port
-		 */
-		snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastport", linknumber);
-		if (icmap_get_uint16(tmp_key, &totem_config->interfaces[linknumber].ip_port) != CS_OK) {
-			if (totem_config->broadcast_use) {
-				totem_config->interfaces[linknumber].ip_port = DEFAULT_PORT + (2 * linknumber);
-			} else {
-				totem_config->interfaces[linknumber].ip_port = DEFAULT_PORT;
+		/* These things are only valid for the initial read OR a newly-defined link */
+		if (!reload || (totem_config->interfaces[linknumber].configured == 0)) {
+
+			/*
+			 * Get mcast port
+			 */
+			snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastport", linknumber);
+			if (icmap_get_uint16(tmp_key, &totem_config->interfaces[linknumber].ip_port) != CS_OK) {
+				if (totem_config->broadcast_use) {
+					totem_config->interfaces[linknumber].ip_port = DEFAULT_PORT + (2 * linknumber);
+				} else {
+					totem_config->interfaces[linknumber].ip_port = DEFAULT_PORT;
+				}
 			}
-		}
 
-		/*
-		 * Get the TTL
-		 */
-		totem_config->interfaces[linknumber].ttl = 1;
+			/*
+			 * Get the TTL
+			 */
+			totem_config->interfaces[linknumber].ttl = 1;
 
-		snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.ttl", linknumber);
+			snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.ttl", linknumber);
 
-		if (icmap_get_uint8(tmp_key, &u8) == CS_OK) {
-			totem_config->interfaces[linknumber].ttl = u8;
+			if (icmap_get_uint8(tmp_key, &u8) == CS_OK) {
+				totem_config->interfaces[linknumber].ttl = u8;
+			}
+
+			totem_config->interfaces[linknumber].knet_transport = KNET_DEFAULT_TRANSPORT;
+			snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.knet_transport", linknumber);
+			if (icmap_get_string(tmp_key, &str) == CS_OK) {
+				if (strcmp(str, "sctp") == 0) {
+					totem_config->interfaces[linknumber].knet_transport = KNET_TRANSPORT_SCTP;
+				}
+				else if (strcmp(str, "udp") == 0) {
+					totem_config->interfaces[linknumber].knet_transport = KNET_TRANSPORT_UDP;
+				}
+				else {
+					*error_string = "Unrecognised knet_transport. expected 'udp' or 'sctp'";
+					return -1;
+				}
+			}
 		}
+		totem_config->interfaces[linknumber].configured = 1;
 
 		/*
 		 * Get the knet link params
@@ -1151,21 +1153,6 @@ extern int totem_config_read (
 			totem_config->interfaces[linknumber].knet_pong_count = u32;
 		}
 
-		totem_config->interfaces[linknumber].knet_transport = KNET_DEFAULT_TRANSPORT;
-		snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.knet_transport", linknumber);
-		if (icmap_get_string(tmp_key, &str) == CS_OK) {
-			if (strcmp(str, "sctp") == 0) {
-				totem_config->interfaces[linknumber].knet_transport = KNET_TRANSPORT_SCTP;
-			}
-			else if (strcmp(str, "udp") == 0) {
-				totem_config->interfaces[linknumber].knet_transport = KNET_TRANSPORT_UDP;
-			}
-			else {
-				*error_string = "Unrecognised knet_transport. expected 'udp' or 'sctp'";
-				return -1;
-			}
-		}
-
 		snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.member.", linknumber);
 		member_iter = icmap_iter_init(tmp_key);
 		while ((member_iter_key = icmap_iter_next(member_iter, NULL, NULL)) != NULL) {
@@ -1187,24 +1174,122 @@ extern int totem_config_read (
 		icmap_iter_finalize(member_iter);
 
 		totem_config->interfaces[linknumber].member_count = member_count;
-		totem_config->interface_count++;
+
 	}
 	icmap_iter_finalize(iter);
 
+	return 0;
+}
+
+extern int totem_config_read (
+	struct totem_config *totem_config,
+	const char **error_string,
+	uint64_t *warnings)
+{
+	int res = 0;
+	char *str, *ring0_addr_str;
+	char tmp_key[ICMAP_KEYNAME_MAXLEN];
+	uint16_t u16;
+	int i;
+	int local_node_pos;
+	int nodeid_set;
+
+	*warnings = 0;
+
+	memset (totem_config, 0, sizeof (struct totem_config));
+	totem_config->interfaces = malloc (sizeof (struct totem_interface) * INTERFACE_MAX);
+	if (totem_config->interfaces == 0) {
+		*error_string = "Out of memory trying to allocate ethernet interface storage area";
+		return -1;
+	}
+
+	memset (totem_config->interfaces, 0,
+		sizeof (struct totem_interface) * INTERFACE_MAX);
+
+	strcpy (totem_config->link_mode, "passive");
+
+	icmap_get_uint32("totem.version", (uint32_t *)&totem_config->version);
+
+	if (totem_get_crypto(totem_config) != 0) {
+		*error_string = "crypto_cipher requires crypto_hash with value other than none";
+		return -1;
+	}
+
+	if (icmap_get_string("totem.link_mode", &str) == CS_OK) {
+		if (strlen(str) >= TOTEM_LINK_MODE_BYTES) {
+			*error_string = "totem.link_mode is too long";
+			free(str);
+
+			return -1;
+		}
+		strcpy (totem_config->link_mode, str);
+		free(str);
+	}
+
+	icmap_get_uint32("totem.nodeid", &totem_config->node_id);
+
+	totem_config->clear_node_high_bit = 0;
+	if (icmap_get_string("totem.clear_node_high_bit", &str) == CS_OK) {
+		if (strcmp (str, "yes") == 0) {
+			totem_config->clear_node_high_bit = 1;
+		}
+		free(str);
+	}
+
+	icmap_get_uint32("totem.threads", &totem_config->threads);
+
+	icmap_get_uint32("totem.netmtu", &totem_config->net_mtu);
+
+	totem_config->ip_version = totem_config_get_ip_version();
+
+	if (icmap_get_string("totem.interface.0.bindnetaddr", &str) != CS_OK) {
+		/*
+		 * We were not able to find ring 0 bindnet addr. Try to use nodelist informations
+		 */
+		config_convert_nodelist_to_interface(totem_config);
+	} else {
+		if (icmap_get_string("nodelist.node.0.ring0_addr", &ring0_addr_str) == CS_OK) {
+			/*
+			 * Both bindnetaddr and ring0_addr are set.
+			 * Log warning information, and use nodelist instead
+			 */
+			*warnings |= TOTEM_CONFIG_BINDNETADDR_NODELIST_SET;
+
+			config_convert_nodelist_to_interface(totem_config);
+
+			free(ring0_addr_str);
+		}
+
+		free(str);
+	}
+
+	/*
+	 * Broadcast option is global but set in interface section,
+	 * so reset before processing interfaces.
+	 */
+	totem_config->broadcast_use = 0;
+
+	res = get_interface_params(totem_config, error_string, warnings, 0);
+	if (res < 0) {
+		return res;
+	}
+
 	/*
 	 * Use broadcast is global, so if set, make sure to fill mcast addr correctly
+	 * broadcast is only supported for UDP so just do interface 0;
 	 */
 	if (totem_config->broadcast_use) {
-		for (linknumber = 0; linknumber < totem_config->interface_count; linknumber++) {
-			totemip_parse (&totem_config->interfaces[linknumber].mcast_addr,
-				"255.255.255.255", 0);
-		}
+		totemip_parse (&totem_config->interfaces[0].mcast_addr,
+			       "255.255.255.255", 0);
 	}
 
 	/*
 	 * Store automatically generated items back to icmap
 	 */
-	for (i = 0; i < totem_config->interface_count; i++) {
+	for (i = 0; i < INTERFACE_MAX; i++) {
+		if (!totem_config->interfaces[i].configured) {
+			continue;
+		}
 		snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "totem.interface.%u.mcastaddr", i);
 		if (icmap_get_string(tmp_key, &str) == CS_OK) {
 			free(str);
@@ -1236,8 +1321,6 @@ extern int totem_config_read (
 		free(str);
 	}
 
-	free(cluster_name);
-
 	/*
 	 * Check existence of nodelist
 	 */
@@ -1290,24 +1373,36 @@ int totem_config_validate (
 	static char local_error_reason[512];
 	char parse_error[512];
 	const char *error_reason = local_error_reason;
-	int i, j;
+	int i;
+	int num_configured = 0;
 	unsigned int interface_max = INTERFACE_MAX;
-	unsigned int port1, port2;
 
-	if (totem_config->interface_count == 0) {
+
+
+	for (i = 0; i < INTERFACE_MAX; i++) {
+		if (totem_config->interfaces[i].configured) {
+			num_configured++;
+		}
+	}
+	if (num_configured == 0) {
 		error_reason = "No interfaces defined";
 		goto parse_error;
 	}
 
-	for (i = 0; i < totem_config->interface_count; i++) {
+	for (i = 0; i < INTERFACE_MAX; i++) {
 		/*
 		 * Some error checking of parsed data to make sure its valid
 		 */
 
 		struct totem_ip_address null_addr;
+
+		if (!totem_config->interfaces[i].configured) {
+			continue;
+		}
+
 		memset (&null_addr, 0, sizeof (struct totem_ip_address));
 
-		if ((totem_config->transport_number == 0) &&
+		if ((totem_config->transport_number == TOTEM_TRANSPORT_UDP) &&
 			memcmp (&totem_config->interfaces[i].mcast_addr, &null_addr,
 				sizeof (struct totem_ip_address)) == 0) {
 			error_reason = "No multicast address specified";
@@ -1361,22 +1456,6 @@ int totem_config_validate (
 			error_reason =  "Not all bind address belong to the same IP family";
 			goto parse_error;
 		}
-
-		/*
-		 * Ensure mcast address/port differs
-		 */
-		if (totem_config->transport_number == TOTEM_TRANSPORT_UDP) {
-			for (j = i + 1; j < totem_config->interface_count; j++) {
-				port1 = totem_config->interfaces[i].ip_port;
-				port2 = totem_config->interfaces[j].ip_port;
-				if (totemip_equal(&totem_config->interfaces[i].mcast_addr,
-				    &totem_config->interfaces[j].mcast_addr) &&
-				    (((port1 > port2 ? port1 : port2)  - (port1 < port2 ? port1 : port2)) <= 1)) {
-					error_reason = "Interfaces multicast address/port pair must differ";
-					goto parse_error;
-				}
-			}
-		}
 	}
 
 	if (totem_config->version != 2) {
@@ -1408,10 +1487,10 @@ int totem_config_validate (
 		interface_max = 1;
 	}
 
-	if (interface_max < totem_config->interface_count) {
+	if (interface_max < num_configured) {
 		snprintf (parse_error, sizeof(parse_error),
 			  "%d is too many configured interfaces for non-Knet transport.",
-			  totem_config->interface_count);
+			  num_configured);
 		error_reason = parse_error;
 		goto parse_error;
 	}
@@ -1649,9 +1728,16 @@ static void totem_reload_notify(
 	struct totem_config *totem_config = (struct totem_config *)user_data;
 	uint32_t local_node_pos;
 	const char *error_string;
+	uint64_t warnings;
 
 	/* Reload has completed */
 	if (*(uint8_t *)new_val.data == 0) {
+
+		totem_config->orig_interfaces = malloc (sizeof (struct totem_interface) * INTERFACE_MAX);
+		assert(totem_config->orig_interfaces != NULL);
+		memcpy(totem_config->orig_interfaces, totem_config->interfaces, sizeof (struct totem_interface) * INTERFACE_MAX);
+
+		get_interface_params(totem_config, &error_string, &warnings, 1);
 		put_nodelist_members_to_config (totem_config, 1);
 		totem_volatile_config_read (totem_config, NULL);
 		log_printf(LOGSYS_LEVEL_DEBUG, "Configuration reloaded. Dumping actual totem config.");
@@ -1669,6 +1755,7 @@ static void totem_reload_notify(
 		if (local_node_pos != -1) {
 			icmap_set_uint32("nodelist.local_node_pos", local_node_pos);
 		}
+		free(totem_config->orig_interfaces);
 
 		icmap_set_uint8("config.totemconfig_reload_in_progress", 0);
 	} else {

+ 58 - 25
exec/totemknet.c

@@ -144,8 +144,6 @@ struct totemknet_instance {
 
 	char *link_status[INTERFACE_MAX];
 
-	int num_links;
-
 	struct totem_ip_address my_ids[INTERFACE_MAX];
 
 	uint16_t ip_port[INTERFACE_MAX];
@@ -417,6 +415,7 @@ int totemknet_ifaces_get (void *knet_context,
 	 * a count of interfaces.
 	 */
 	if (status) {
+
 		res = knet_host_get_host_list(instance->knet_handle,
 					      host_list, &num_hosts);
 		if (res) {
@@ -424,6 +423,11 @@ int totemknet_ifaces_get (void *knet_context,
 		}
 		qsort(host_list, num_hosts, sizeof(uint16_t), node_compare);
 
+		for (i=0; i<INTERFACE_MAX; i++) {
+			memset(instance->link_status[i], 'n', CFG_INTERFACE_STATUS_MAX_LEN-1);
+			instance->link_status[i][num_hosts] = '\0';
+		}
+
 		/* This is all a bit "inside-out" because "status" is a set of strings per link
 		 * and knet orders things by host
 		 */
@@ -434,18 +438,12 @@ int totemknet_ifaces_get (void *knet_context,
 				return (-1);
 			}
 
-			for (i=0; i <= instance->num_links; i++) {
-				ptr = instance->link_status[i];
-
-				/* Loopback link */
-				if (i >= num_links) {
-					ptr[j] = '-';
-					continue;
-				}
+			for (i=0; i < num_links; i++) {
+				ptr = instance->link_status[link_list[i]];
 
 				res = knet_link_get_status(instance->knet_handle,
 							   host_list[j],
-							   i,
+							   link_list[i],
 							   &link_status,
 							   sizeof(link_status));
 				if (res == 0) {
@@ -456,13 +454,12 @@ int totemknet_ifaces_get (void *knet_context,
 				else {
 					ptr[j] = '?';
 				}
-				ptr[num_hosts] = '\0';
 			}
 		}
 		*status = instance->link_status;
 	}
 
-	*iface_count = instance->num_links+1;
+	*iface_count = INTERFACE_MAX;
 
 	return (res);
 }
@@ -629,10 +626,14 @@ static void timer_function_netif_check_timeout (
 	struct totemknet_instance *instance = (struct totemknet_instance *)data;
 	int i;
 
-	for (i=0; i<instance->totem_config->interface_count; i++)
+	for (i=0; i < INTERFACE_MAX; i++) {
+		if (!instance->totem_config->interfaces[i].configured) {
+			continue;
+		}
 		instance->totemknet_iface_change_fn (instance->context,
 						     &instance->my_ids[i],
 						     i);
+	}
 }
 static void totemknet_refresh_config(
 	int32_t event,
@@ -672,7 +673,11 @@ static void totemknet_refresh_config(
 	}
 
 	/* Get link parameters */
-	for (i = 0; i <= instance->num_links; i++) {
+	for (i = 0; i < INTERFACE_MAX; i++) {
+		if (!instance->totem_config->interfaces[i].configured) {
+			continue;
+		}
+
 		sprintf(path, "totem.interface.%d.knet_link_priority", i);
 		if (icmap_get_uint32(path, &value) == CS_OK) {
 			instance->totem_config->interfaces[i].knet_link_priority = value;
@@ -710,7 +715,10 @@ static void totemknet_refresh_config(
 	}
 
 	for (i=0; i<num_nodes; i++) {
-		for (link_no = 0; link_no < instance->num_links; link_no++) {
+		for (link_no = 0; link_no < INTERFACE_MAX; link_no++) {
+			if (host_ids[i] == instance->our_nodeid || !instance->totem_config->interfaces[link_no].configured) {
+				continue;
+			}
 
 			err = knet_link_set_ping_timers(instance->knet_handle, host_ids[i], link_no,
 							instance->totem_config->interfaces[link_no].knet_ping_interval,
@@ -818,7 +826,7 @@ int totemknet_initialize (
 
 	instance->our_nodeid = instance->totem_config->node_id;
 
-	for (i=0; i< instance->totem_config->interface_count; i++) {
+	for (i=0; i< INTERFACE_MAX; i++) {
 		totemip_copy(&instance->my_ids[i], &totem_config->interfaces[i].bindnet);
 		instance->my_ids[i].nodeid = instance->our_nodeid;
 		instance->ip_port[i] = totem_config->interfaces[i].ip_port;
@@ -1107,6 +1115,23 @@ extern int totemknet_recv_mcast_empty (
 	return (msg_processed);
 }
 
+int totemknet_iface_set (void *knet_context,
+	const struct totem_ip_address *local_addr,
+	unsigned short ip_port,
+	unsigned int iface_no)
+{
+	struct totemknet_instance *instance = (struct totemknet_instance *)knet_context;
+
+	totemip_copy(&instance->my_ids[iface_no], local_addr);
+
+	knet_log_printf(LOG_INFO, "Configured link number %d: local addr: %s, port=%d", iface_no, totemip_print(local_addr), ip_port);
+
+	instance->ip_port[iface_no] = ip_port;
+
+	return 0;
+}
+
+
 int totemknet_member_add (
 	void *knet_context,
 	const struct totem_ip_address *local,
@@ -1120,11 +1145,6 @@ int totemknet_member_add (
 	struct sockaddr_storage local_ss;
 	int addrlen;
 
-	/* Keep track of the number of links */
-	if (link_no > instance->num_links) {
-		instance->num_links = link_no;
-	}
-
 	/* Only create 1 loopback link */
 	if (member->nodeid == instance->our_nodeid && link_no > 0) {
 		return 0;
@@ -1144,6 +1164,7 @@ int totemknet_member_add (
 		}
 	}
 
+	memset(&local_ss, 0, sizeof(local_ss));
 	/* Casts to remove const */
 	totemip_totemip_to_sockaddr_convert((struct totem_ip_address *)member, port+link_no, &remote_ss, &addrlen);
 	totemip_totemip_to_sockaddr_convert((struct totem_ip_address *)local, port+link_no, &local_ss, &addrlen);
@@ -1202,6 +1223,8 @@ int totemknet_member_remove (
 {
 	struct totemknet_instance *instance = (struct totemknet_instance *)knet_context;
 	int res;
+	uint8_t link_list[KNET_MAX_LINK];
+	size_t num_links;
 
 	knet_log_printf (LOGSYS_LEVEL_DEBUG, "knet: member_remove: %d, link=%d", token_target->nodeid, link_no);
 
@@ -1225,8 +1248,18 @@ int totemknet_member_remove (
 		KNET_LOGSYS_PERROR(errno, LOGSYS_LEVEL_ERROR, "knet_link_clear_config for nodeid %d, link %d failed", token_target->nodeid, link_no);
 		return res;
 	}
-	return knet_host_remove(instance->knet_handle, token_target->nodeid);
 
+	/* If this is the last link, then remove the node */
+	res = knet_link_get_link_list(instance->knet_handle,
+				      token_target->nodeid, link_list, &num_links);
+	if (res) {
+		return (0); /* not really  failure */
+	}
+
+	if (num_links == 0) {
+		res = knet_host_remove(instance->knet_handle, token_target->nodeid);
+	}
+	return res;
 }
 
 int totemknet_member_list_rebind_ip (
@@ -1248,8 +1281,8 @@ int totemknet_link_get_status (
 		return CS_ERR_NOT_EXIST;
 	}
 
-	if (link_no > global_instance->num_links) {
-		return -1; /* no more links */
+	if (link_no >= INTERFACE_MAX) {
+		return CS_ERR_NOT_EXIST; /* Invalid link number */
 	}
 
 	res = knet_link_get_status(global_instance->knet_handle, node, link_no, status, sizeof(struct knet_link_status));

+ 5 - 0
exec/totemknet.h

@@ -105,6 +105,11 @@ extern int totemknet_ifaces_get (void *net_context,
 	char ***status,
 	unsigned int *iface_count);
 
+extern int totemknet_iface_set (void *net_context,
+	const struct totem_ip_address *local_addr,
+	unsigned short ip_port,
+	unsigned int iface_no);
+
 extern int totemknet_token_target_set (
 	void *knet_context,
 	const struct totem_ip_address *token_target);

+ 22 - 0
exec/totemnet.c

@@ -129,6 +129,12 @@ struct transport {
 	int (*recv_mcast_empty) (
 		void *transport_context);
 
+	int (*iface_set) (
+		void *transport_context,
+		const struct totem_ip_address *local,
+		unsigned short ip_port,
+		unsigned int ring_no);
+
 	int (*member_add) (
 		void *transport_context,
 		const struct totem_ip_address *local,
@@ -158,6 +164,7 @@ struct transport transport_entries[] = {
 		.mcast_noflush_send = totemudp_mcast_noflush_send,
 		.recv_flush = totemudp_recv_flush,
 		.send_flush = totemudp_send_flush,
+		.iface_set = totemudp_iface_set,
 		.iface_check = totemudp_iface_check,
 		.finalize = totemudp_finalize,
 		.net_mtu_adjust = totemudp_net_mtu_adjust,
@@ -177,6 +184,7 @@ struct transport transport_entries[] = {
 		.mcast_noflush_send = totemudpu_mcast_noflush_send,
 		.recv_flush = totemudpu_recv_flush,
 		.send_flush = totemudpu_send_flush,
+		.iface_set = totemudpu_iface_set,
 		.iface_check = totemudpu_iface_check,
 		.finalize = totemudpu_finalize,
 		.net_mtu_adjust = totemudpu_net_mtu_adjust,
@@ -198,6 +206,7 @@ struct transport transport_entries[] = {
 		.mcast_noflush_send = totemknet_mcast_noflush_send,
 		.recv_flush = totemknet_recv_flush,
 		.send_flush = totemknet_send_flush,
+		.iface_set = totemknet_iface_set,
 		.iface_check = totemknet_iface_check,
 		.finalize = totemknet_finalize,
 		.net_mtu_adjust = totemknet_net_mtu_adjust,
@@ -432,6 +441,19 @@ extern int totemnet_net_mtu_adjust (void *net_context, struct totem_config *tote
 	return (res);
 }
 
+int totemnet_iface_set (void *net_context,
+	const struct totem_ip_address *interface_addr,
+	unsigned short ip_port,
+	unsigned int iface_no)
+{
+	struct totemnet_instance *instance = (struct totemnet_instance *)net_context;
+	int res;
+
+	res = instance->transport->iface_set (instance->transport_context, interface_addr, ip_port, iface_no);
+
+	return (res);
+}
+
 int totemnet_ifaces_get (
 	void *net_context,
 	char ***status,

+ 5 - 0
exec/totemnet.h

@@ -105,6 +105,11 @@ extern int totemnet_recv_flush (void *net_context);
 
 extern int totemnet_send_flush (void *net_context);
 
+extern int totemnet_iface_set (void *net_context,
+       const struct totem_ip_address *interface_addr,
+       unsigned short ip_port,
+       unsigned int iface_no);
+
 extern int totemnet_iface_check (void *net_context);
 
 extern int totemnet_finalize (void *net_context);

+ 16 - 0
exec/totempg.c

@@ -1402,6 +1402,22 @@ int totempg_groups_send_ok_groups (
 	return (res);
 }
 
+int totempg_iface_set (
+	struct totem_ip_address *interface_addr,
+	unsigned short ip_port,
+	unsigned int iface_no)
+{
+	int res;
+
+	res = totemsrp_iface_set (
+		totemsrp_context,
+		interface_addr,
+		ip_port,
+		iface_no);
+
+	return (res);
+}
+
 int totempg_ifaces_get (
 	unsigned int nodeid,
 	struct totem_ip_address *interfaces,

+ 46 - 43
exec/totemsrp.c

@@ -1037,50 +1037,23 @@ int totemsrp_ifaces_get (
 {
 	struct totemsrp_instance *instance = (struct totemsrp_instance *)srp_context;
 	int res = 0;
-	unsigned int found = 0;
-	unsigned int i;
-
-	for (i = 0; i < instance->my_memb_entries; i++) {
-		if (instance->my_memb_list[i].addr[0].nodeid == nodeid) {
-			found = 1;
-			break;
-		}
-	}
-
-	if (found) {
-		*iface_count = instance->totem_config->interface_count;
-
-		if (interfaces_size >= *iface_count) {
-			memcpy (interfaces, instance->my_memb_list[i].addr,
-				sizeof (struct totem_ip_address) * *iface_count);
-		} else {
-			res = -2;
-		}
-
-		goto finish;
-	}
-
-	for (i = 0; i < instance->my_left_memb_entries; i++) {
-		if (instance->my_left_memb_list[i].addr[0].nodeid == nodeid) {
-			found = 1;
-			break;
-		}
-	}
+	int i;
 
-	if (found) {
-		*iface_count = instance->totem_config->interface_count;
+	*iface_count = INTERFACE_MAX;
 
-		if (interfaces_size >= *iface_count) {
-			memcpy (interfaces, instance->my_left_memb_list[i].addr,
-				sizeof (struct totem_ip_address) * *iface_count);
-		} else {
-			res = -2;
+	if (interfaces_size >= *iface_count) {
+		for (i=0; i<INTERFACE_MAX; i++) {
+			if (instance->totem_config->interfaces[i].configured) {
+				memcpy (&interfaces[i], &instance->my_id.addr[i],
+					sizeof (struct totem_ip_address));
+			} else {
+				memset (&interfaces[i], 0, sizeof (struct totem_ip_address));
+			}
 		}
 	} else {
-		res = -1;
+		res = -2;
 	}
 
-finish:
 	totemnet_ifaces_get(instance->totemnet_context, status, iface_count);
 	return (res);
 }
@@ -4682,12 +4655,34 @@ printf ("wrong message type\n");
 		message_header->endian_detector != ENDIAN_LOCAL);
 }
 
+int totemsrp_iface_set (
+	void *context,
+	const struct totem_ip_address *interface_addr,
+	unsigned short ip_port,
+	unsigned int iface_no)
+{
+	struct totemsrp_instance *instance = context;
+	int res;
+
+	totemip_copy(&instance->my_id.addr[iface_no], interface_addr);
+
+	res = totemnet_iface_set (
+		instance->totemnet_context,
+		interface_addr,
+		ip_port,
+		iface_no);
+
+	return (res);
+}
+
+
 void main_iface_change_fn (
 	void *context,
 	const struct totem_ip_address *iface_addr,
 	unsigned int iface_no)
 {
 	struct totemsrp_instance *instance = context;
+	int num_interfaces;
 	int i;
 
 	totemip_copy (&instance->my_id.addr[iface_no], iface_addr);
@@ -4717,7 +4712,15 @@ void main_iface_change_fn (
 			iface_no);
 	}
 
-	if (instance->iface_changes >= instance->totem_config->interface_count) {
+	num_interfaces = 0;
+	for (i = 0; i < INTERFACE_MAX; i++) {
+		if (instance->totem_config->interfaces[i].configured) {
+			num_interfaces++;
+		}
+	}
+
+
+	if (instance->iface_changes >= num_interfaces) {
 		memb_state_gather_enter (instance, TOTEMSRP_GSFROM_INTERFACE_CHANGE);
 	}
 }
@@ -4738,12 +4741,12 @@ void totemsrp_service_ready_register (
 int totemsrp_member_add (
         void *context,
         const struct totem_ip_address *member,
-        int link_no)
+        int iface_no)
 {
 	struct totemsrp_instance *instance = (struct totemsrp_instance *)context;
 	int res;
 
-	res = totemnet_member_add (instance->totemnet_context, &instance->my_id.addr[link_no], member, link_no);
+	res = totemnet_member_add (instance->totemnet_context, &instance->my_id.addr[iface_no], member, iface_no);
 
 	return (res);
 }
@@ -4751,12 +4754,12 @@ int totemsrp_member_add (
 int totemsrp_member_remove (
         void *context,
         const struct totem_ip_address *member,
-        int link_no)
+        int iface_no)
 {
 	struct totemsrp_instance *instance = (struct totemsrp_instance *)context;
 	int res;
 
-	res = totemnet_member_remove (instance->totemnet_context, member, link_no);
+	res = totemnet_member_remove (instance->totemnet_context, member, iface_no);
 
 	return (res);
 }

+ 8 - 2
exec/totemsrp.h

@@ -124,16 +124,22 @@ void totemsrp_service_ready_register (
 	void *srp_context,
 	void (*totem_service_ready) (void));
 
+extern int totemsrp_iface_set (
+	void *srp_context,
+	const struct totem_ip_address *interface_addr,
+	unsigned short ip_port,
+	unsigned int iface_no);
+
 extern int totemsrp_member_add (
 	void *srp_context,
 	const struct totem_ip_address *member,
 	int ring_no);
-	
+
 extern int totemsrp_member_remove (
 	void *srp_context,
 	const struct totem_ip_address *member,
 	int ring_no);
-	
+
 void totemsrp_threaded_mode_enable (
 	void *srp_context);
 

+ 8 - 3
exec/totemudp.c

@@ -1332,9 +1332,6 @@ int totemudp_ifaces_get (
 
 extern void totemudp_net_mtu_adjust (void *udp_context, struct totem_config *totem_config)
 {
-
-	assert(totem_config->interface_count > 0);
-
 	totem_config->net_mtu -= totemip_udpip_header_size(totem_config->interfaces[0].bindnet.family);
 }
 
@@ -1417,3 +1414,11 @@ extern int totemudp_recv_mcast_empty (
 	return (msg_processed);
 }
 
+int totemudp_iface_set (void *net_context,
+	const struct totem_ip_address *local_addr,
+	unsigned short ip_port,
+	unsigned int iface_no)
+{
+	/* Not supported */
+	return (-1);
+}

+ 5 - 0
exec/totemudp.h

@@ -99,6 +99,11 @@ extern int totemudp_recv_flush (void *udp_context);
 
 extern int totemudp_send_flush (void *udp_context);
 
+extern int totemudp_iface_set (void *net_context,
+       const struct totem_ip_address *local_addr,
+       unsigned short ip_port,
+       unsigned int iface_no);
+
 extern int totemudp_iface_check (void *udp_context);
 
 extern int totemudp_finalize (void *udp_context);

+ 9 - 3
exec/totemudpu.c

@@ -932,9 +932,6 @@ extern int totemudpu_iface_check (void *udpu_context)
 
 extern void totemudpu_net_mtu_adjust (void *udpu_context, struct totem_config *totem_config)
 {
-
-	assert(totem_config->interface_count > 0);
-
 	totem_config->net_mtu -= totemip_udpip_header_size(totem_config->interfaces[0].bindnet.family);
 }
 
@@ -1064,6 +1061,15 @@ error_close_fd:
 	return (-1);
 }
 
+int totemudpu_iface_set (void *net_context,
+	const struct totem_ip_address *local_addr,
+	unsigned short ip_port,
+	unsigned int iface_no)
+{
+	/* Not supported */
+	return (-1);
+}
+
 int totemudpu_member_add (
 	void *udpu_context,
 	const struct totem_ip_address *local,

+ 5 - 0
exec/totemudpu.h

@@ -99,6 +99,11 @@ extern int totemudpu_recv_flush (void *udpu_context);
 
 extern int totemudpu_send_flush (void *udpu_context);
 
+extern int totemudpu_iface_set (void *net_context,
+	const struct totem_ip_address *local_addr,
+	unsigned short ip_port,
+	unsigned int iface_no);
+
 extern int totemudpu_iface_check (void *udpu_context);
 
 extern int totemudpu_finalize (void *udpu_context);

+ 2 - 1
include/corosync/totem/totem.h

@@ -74,6 +74,7 @@ struct totem_interface {
 	struct totem_ip_address mcast_addr;
 	uint16_t ip_port;
 	uint16_t ttl;
+	uint8_t  configured;
 	int member_count;
 	int knet_link_priority;
 	int knet_ping_interval;
@@ -137,7 +138,7 @@ struct totem_config {
 	 * network
 	 */
 	struct totem_interface *interfaces;
-	unsigned int interface_count;
+	struct totem_interface *orig_interfaces; /* for reload */
 	unsigned int node_id;
 	unsigned int clear_node_high_bit;
 	unsigned int knet_pmtud_interval;

+ 5 - 0
include/corosync/totem/totempg.h

@@ -160,6 +160,11 @@ extern int totempg_crypto_set (const char *cipher_type, const char *hash_type);
 extern void totempg_service_ready_register (
 	void (*totem_service_ready) (void));
 
+extern int totempg_iface_set (
+	struct totem_ip_address *interface_addr,
+	unsigned short ip_port,
+	unsigned int iface_no);
+
 extern int totempg_member_add (
 	const struct totem_ip_address *member,
 	int ring_no);

+ 3 - 2
tools/corosync-cfgtool.c

@@ -100,8 +100,9 @@ linkstatusget_do (char *interface_name)
 		printf ("Could not get the link status, the error is: %d\n", result);
 	} else {
 		for (i = 0; i < interface_count; i++) {
-			if ( (interface_name && 
-			     	(interface_name[0]=='\0' || 
+			if ( (interface_name &&
+			      interface_names[i][0] != '\0' &&
+			      (interface_name[0]=='\0' ||
 				strcasecmp (interface_name, interface_names[i]) == 0)) ||
 				!interface_name ) {