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

totemconfig: Enhance totem.ip_version

Originally totem.ip_version was used to force ip version used by totem.
With Knet this variable didn't make too much sense so it was not used.

Sadly rely only on DNS resolver order doesn't always work (RFC is quite
complicated, but if IPv6 is not configured then IPv4 is preferred), what
we tried to solve by forcing IPv6 and only if that fails, use IPv4.

Sadly this collides with nss_myhostname which is able to return every
local address and today system usually have at least one autogenerated
link-local IPv6 address so it is able to "overwrite" /etc/hosts.

Solution is to enhance totem.ip_version and use it also for Knet.
totem.ip_version is now just a flag for resolver and can have four
states: ipv4 (only IPv4 is used), ipv6 (only IPv6 is used), ipv4-6 (ask
IPv4 first and if it fails ask for IPv6) and ipv6-4 (ask IPv6 first and
if it fails ask for IPv4). Default for Knet and UDPU transports is
ipv6-4, for UDP it's ipv4, because autogenerated mcast addr doesn't play
too well with ipv6-4.

So everywhere where nss_myhostname becomes problem, it's just possible
to set totem.ip_version to ipv4-6.

Signed-off-by: Jan Friesse <jfriesse@redhat.com>
Reviewed-by: Jan Friesse <jfriesse@redhat.com>
Jan Friesse 7 лет назад
Родитель
Сommit
a84ade701c
7 измененных файлов с 90 добавлено и 50 удалено
  1. 3 1
      exec/coroparse.c
  2. 0 4
      exec/main.c
  3. 30 21
      exec/totemconfig.c
  4. 30 14
      exec/totemip.c
  5. 1 1
      include/corosync/totem/totem.h
  6. 8 1
      include/corosync/totem/totemip.h
  7. 18 8
      man/corosync.conf.5

+ 3 - 1
exec/coroparse.c

@@ -739,7 +739,9 @@ static int main_config_parser_cb(const char *path,
 			}
 			if (strcmp(path, "totem.ip_version") == 0) {
 				if ((strcmp(value, "ipv4") != 0) &&
-				    (strcmp(value, "ipv6") != 0)) {
+				    (strcmp(value, "ipv6") != 0) &&
+				    (strcmp(value, "ipv6-4") != 0) &&
+				    (strcmp(value, "ipv4-6") != 0)) {
 					*error_string = "Invalid ip_version type";
 
 					return (0);

+ 0 - 4
exec/main.c

@@ -165,8 +165,6 @@ static corosync_timer_handle_t corosync_stats_timer_handle;
 
 static const char *corosync_lock_file = LOCALSTATEDIR"/run/corosync.pid";
 
-static int ip_version = AF_INET;
-
 static char corosync_config_file[PATH_MAX + 1] = COROSYSCONFDIR "/corosync.conf";
 
 qb_loop_t *cs_poll_handle_get (void)
@@ -1454,8 +1452,6 @@ int main (int argc, char **argv, char **envp)
 		}
 	}
 
-	ip_version = totem_config.ip_version;
-
 	totem_config.totem_memb_ring_id_create_or_load = corosync_ring_id_create_or_load;
 	totem_config.totem_memb_ring_id_store = corosync_ring_id_store;
 

+ 30 - 21
exec/totemconfig.c

@@ -778,24 +778,31 @@ ret_found:
 	return node_pos;
 }
 
-static int totem_config_get_ip_version(struct totem_config *totem_config)
+static enum totem_ip_version_enum totem_config_get_ip_version(struct totem_config *totem_config)
 {
-	int res;
+	enum totem_ip_version_enum res;
 	char *str;
 
-	res = AF_INET;
-	if (totem_config->transport_number == TOTEM_TRANSPORT_KNET) {
-		res = AF_UNSPEC;
-	} else {
-		if (icmap_get_string("totem.ip_version", &str) == CS_OK) {
-			if (strcmp(str, "ipv4") == 0) {
-				res = AF_INET;
-			}
-			if (strcmp(str, "ipv6") == 0) {
-				res = AF_INET6;
-			}
-			free(str);
+	res = TOTEM_IP_VERSION_6_4;
+
+	if (totem_config->transport_number == TOTEM_TRANSPORT_UDP) {
+		res = TOTEM_IP_VERSION_4;
+	}
+
+	if (icmap_get_string("totem.ip_version", &str) == CS_OK) {
+		if (strcmp(str, "ipv4") == 0) {
+			res = TOTEM_IP_VERSION_4;
+		}
+		if (strcmp(str, "ipv6") == 0) {
+			res = TOTEM_IP_VERSION_6;
+		}
+		if (strcmp(str, "ipv6-4") == 0) {
+			res = TOTEM_IP_VERSION_6_4;
 		}
+		if (strcmp(str, "ipv4-6") == 0) {
+			res = TOTEM_IP_VERSION_4_6;
+		}
+		free(str);
 	}
 
 	return (res);
@@ -817,7 +824,7 @@ static uint16_t generate_cluster_id (const char *cluster_name)
 static int get_cluster_mcast_addr (
 		const char *cluster_name,
 		unsigned int linknumber,
-		int ip_version,
+		enum totem_ip_version_enum ip_version,
 		struct totem_ip_address *res)
 {
 	uint16_t clusterid;
@@ -832,10 +839,12 @@ static int get_cluster_mcast_addr (
 	memset (res, 0, sizeof(*res));
 
 	switch (ip_version) {
-	case AF_INET:
+	case TOTEM_IP_VERSION_4:
+	case TOTEM_IP_VERSION_4_6:
 		snprintf(addr, sizeof(addr), "239.192.%d.%d", clusterid >> 8, clusterid % 0xFF);
 		break;
-	case AF_INET6:
+	case TOTEM_IP_VERSION_6:
+	case TOTEM_IP_VERSION_6_4:
 		snprintf(addr, sizeof(addr), "ff15::%x", clusterid);
 		break;
 	default:
@@ -859,7 +868,7 @@ static unsigned int generate_nodeid(
 
 	/* AF_INET hard-coded here because auto-generated nodeids
 	   are only for IPv4 */
-	if (totemip_parse(&totemip, addr, AF_INET) != 0)
+	if (totemip_parse(&totemip, addr, TOTEM_IP_VERSION_4) != 0)
 		return -1;
 
 	memcpy (&nodeid, &totemip.addr, sizeof (unsigned int));
@@ -1104,7 +1113,7 @@ static void reconfigure_links(struct totem_config *totem_config)
 			continue;
 		}
 
-		err = totemip_parse(&local_ip, addr_string, AF_UNSPEC);
+		err = totemip_parse(&local_ip, addr_string, totem_config->ip_version);
 		if (err != 0) {
 			continue;
 		}
@@ -1429,7 +1438,7 @@ static int get_interface_params(struct totem_config *totem_config,
 				}
 
 				free(str);
-			} else {
+			} else if (totem_config->transport_number == TOTEM_TRANSPORT_UDP) {
 				/*
 				 * User not specified address -> autogenerate one from cluster_name key
 				 * (if available). Return code is intentionally ignored, because
@@ -1679,7 +1688,7 @@ extern int totem_config_read (
 	 */
 	if (totem_config->broadcast_use) {
 		totemip_parse (&totem_config->interfaces[0].mcast_addr,
-			       "255.255.255.255", 0);
+			       "255.255.255.255", TOTEM_IP_VERSION_4);
 	}
 
 

+ 30 - 14
exec/totemip.c

@@ -280,10 +280,12 @@ int totemip_totemip_to_sockaddr_convert(struct totem_ip_address *ip_addr,
 	return ret;
 }
 
-/* Converts an address string string into a totem_ip_address.
-   family can be AF_INET, AF_INET6 or 0 ("for "don't care")
-*/
-int totemip_parse(struct totem_ip_address *totemip, const char *addr, int family)
+/*
+ * Converts an address string string into a totem_ip_address. ip_version enum
+ * defines order.
+ */
+int totemip_parse(struct totem_ip_address *totemip, const char *addr,
+    enum totem_ip_version_enum ip_version)
 {
 	struct addrinfo *ainfo;
 	struct addrinfo ahints;
@@ -291,21 +293,35 @@ int totemip_parse(struct totem_ip_address *totemip, const char *addr, int family
 	struct sockaddr_in6 *sa6;
 	int ret;
 	int debug_ip_family;
+	int ai_family1, ai_family2;
 
 	memset(&ahints, 0, sizeof(ahints));
 	ahints.ai_socktype = SOCK_DGRAM;
 	ahints.ai_protocol = IPPROTO_UDP;
-	ahints.ai_family   = family;
 
-	/* If no address family specified then try IPv6 first then IPv4 */
-	if (family == AF_UNSPEC) {
-		ahints.ai_family = AF_INET6;
-		ret = getaddrinfo(addr, NULL, &ahints, &ainfo);
-		if (ret) {
-			ahints.ai_family = AF_INET;
-			ret = getaddrinfo(addr, NULL, &ahints, &ainfo);
-		}
-	} else {
+	ai_family1 = ai_family2 = -1;
+
+	switch (ip_version) {
+	case TOTEM_IP_VERSION_4:
+		ai_family1 = AF_INET;
+		break;
+	case TOTEM_IP_VERSION_6:
+		ai_family1 = AF_INET6;
+		break;
+	case TOTEM_IP_VERSION_4_6:
+		ai_family1 = AF_INET;
+		ai_family2 = AF_INET6;
+		break;
+	case TOTEM_IP_VERSION_6_4:
+		ai_family1 = AF_INET6;
+		ai_family2 = AF_INET;
+		break;
+	}
+
+	ahints.ai_family = ai_family1;
+	ret = getaddrinfo(addr, NULL, &ahints, &ainfo);
+	if (ret && ai_family2 != -1) {
+		ahints.ai_family = ai_family2;
 		ret = getaddrinfo(addr, NULL, &ahints, &ainfo);
 	}
 

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

@@ -231,7 +231,7 @@ struct totem_config {
 
 	unsigned int miss_count_const;
 
-	int ip_version;
+	enum totem_ip_version_enum ip_version;
 
 	void (*totem_memb_ring_id_create_or_load) (
 	    struct memb_ring_id *memb_ring_id,

+ 8 - 1
include/corosync/totem/totemip.h

@@ -67,6 +67,13 @@ struct totem_ip_address
 	unsigned char  addr[TOTEMIP_ADDRLEN];
 } __attribute__((packed));
 
+enum totem_ip_version_enum {
+	TOTEM_IP_VERSION_4,		/* Use only AF_INET */
+	TOTEM_IP_VERSION_6,		/* Use only AF_INET6 */
+	TOTEM_IP_VERSION_4_6,		/* Use AF_INET and if it fails, use AF_INET6 */
+	TOTEM_IP_VERSION_6_4		/* Use AF_INET6 and if it fails, use AF_INET */
+};
+
 struct totem_ip_if_address
 {
 	struct totem_ip_address ip_addr;
@@ -94,7 +101,7 @@ extern int totemip_sockaddr_to_totemip_convert(const struct sockaddr_storage *sa
 extern int totemip_totemip_to_sockaddr_convert(struct totem_ip_address *ip_addr,
 					       uint16_t port, struct sockaddr_storage *saddr, int *addrlen);
 extern int totemip_parse(struct totem_ip_address *totemip, const char *addr,
-			 int family);
+			 enum totem_ip_version_enum ip_version);
 extern int totemip_iface_check(struct totem_ip_address *bindnet,
 			       struct totem_ip_address *boundto,
 			       int *interface_up,

+ 18 - 8
man/corosync.conf.5

@@ -305,9 +305,22 @@ equal to highest of collected versions, corosync is terminated.
 
 .TP
 ip_version
-For udp or udpu, this specifies version of IP to use for communication.
-The value can be one of ipv4 or ipv6. Default (if unspecified) is ipv4.
-This does not apply to knet where both ipv4 and ipv6 address can be used,
+This specifies version of IP to ask DNS resolver for.
+The value can be one of
+.B ipv4
+(look only for an IPv4 address)
+,
+.B ipv6
+(check only IPv6 address)
+,
+.B ipv4-6
+(first check IPv4 address, if that fails then look for an IPv6 address) and
+.B ipv6-4
+(first check IPv6 address, if that fails then look for an IPv4 address).
+
+Default (if unspecified) is ipv6-4 for knet and udpu transports and ipv4 for udp.
+
+Knet transport allows to have a both ipv4 and ipv6 address,
 provided they are consistent on each link.
 
 Within the
@@ -865,8 +878,8 @@ corosync-cfgtool -R
 on one of them.
 
 .SH "ADDRESS RESOLUTION"
-corosync resolves ringX_addr names/IP addresses using the getaddrinfo(3) call in two passes.
-First it will check for an IPv6 address, if that fails then it will look for an IPv4 address.
+corosync resolves ringX_addr names/IP addresses using the getaddrinfo(3) call with respect
+of totem.ip_version setting.
 
 getaddrinfo() function uses a sophisticated algorithm to sort node addresses into a preferred
 order and corosync always chooses the first address in that list of the required family.
@@ -880,9 +893,6 @@ but this is not recommended.
 If there is any doubt about the order of addresses returned from getaddrinfo() then it might be simpler to use
 IP addresses (v4 or v6) in the ringX_addr field.
 
-For UDP/UDPU it is possible to force the IP family using totem.ip_version. This is ignored for knet as links
-can have different IP versions.
-
 .SH "FILES"
 .TP
 /etc/corosync/corosync.conf