Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ee3b56f2 authored by Noah Watkins's avatar Noah Watkins Committed by Sage Weil
Browse files

ceph: use kernel DNS resolver



Change ceph_parse_ips to take either names given as
IP addresses or standard hostnames (e.g. localhost).
The DNS lookup is done using the dns_resolver facility
similar to its use in AFS, NFS, and CIFS.

This patch defines CONFIG_CEPH_LIB_USE_DNS_RESOLVER
that controls if this feature is on or off.

Signed-off-by: default avatarNoah Watkins <noahwatkins@gmail.com>
Signed-off-by: default avatarSage Weil <sage@newdream.net>
parent 49d9224c
Loading
Loading
Loading
Loading
+14 −0
Original line number Original line Diff line number Diff line
@@ -27,3 +27,17 @@ config CEPH_LIB_PRETTYDEBUG


	  If unsure, say N.
	  If unsure, say N.


config CEPH_LIB_USE_DNS_RESOLVER
	bool "Use in-kernel support for DNS lookup"
	depends on CEPH_LIB
	select DNS_RESOLVER
	default n
	help
	  If you say Y here, hostnames (e.g. monitor addresses) will
	  be resolved using the CONFIG_DNS_RESOLVER facility.

	  For information on how to use CONFIG_DNS_RESOLVER consult
	  Documentation/networking/dns_resolver.txt

	  If unsure, say N.
+102 −12
Original line number Original line Diff line number Diff line
@@ -11,6 +11,7 @@
#include <linux/string.h>
#include <linux/string.h>
#include <linux/bio.h>
#include <linux/bio.h>
#include <linux/blkdev.h>
#include <linux/blkdev.h>
#include <linux/dns_resolver.h>
#include <net/tcp.h>
#include <net/tcp.h>


#include <linux/ceph/libceph.h>
#include <linux/ceph/libceph.h>
@@ -1077,6 +1078,101 @@ static void addr_set_port(struct sockaddr_storage *ss, int p)
	}
	}
}
}


/*
 * Unlike other *_pton function semantics, zero indicates success.
 */
static int ceph_pton(const char *str, size_t len, struct sockaddr_storage *ss,
		char delim, const char **ipend)
{
	struct sockaddr_in *in4 = (void *)ss;
	struct sockaddr_in6 *in6 = (void *)ss;

	memset(ss, 0, sizeof(*ss));

	if (in4_pton(str, len, (u8 *)&in4->sin_addr.s_addr, delim, ipend)) {
		ss->ss_family = AF_INET;
		return 0;
	}

	if (in6_pton(str, len, (u8 *)&in6->sin6_addr.s6_addr, delim, ipend)) {
		ss->ss_family = AF_INET6;
		return 0;
	}

	return -EINVAL;
}

/*
 * Extract hostname string and resolve using kernel DNS facility.
 */
#ifdef CONFIG_CEPH_LIB_USE_DNS_RESOLVER
static int ceph_dns_resolve_name(const char *name, size_t namelen,
		struct sockaddr_storage *ss, char delim, const char **ipend)
{
	const char *end, *delim_p;
	char *colon_p, *ip_addr = NULL;
	int ip_len, ret;

	/*
	 * The end of the hostname occurs immediately preceding the delimiter or
	 * the port marker (':') where the delimiter takes precedence.
	 */
	delim_p = memchr(name, delim, namelen);
	colon_p = memchr(name, ':', namelen);

	if (delim_p && colon_p)
		end = delim_p < colon_p ? delim_p : colon_p;
	else if (!delim_p && colon_p)
		end = colon_p;
	else {
		end = delim_p;
		if (!end) /* case: hostname:/ */
			end = name + namelen;
	}

	if (end <= name)
		return -EINVAL;

	/* do dns_resolve upcall */
	ip_len = dns_query(NULL, name, end - name, NULL, &ip_addr, NULL);
	if (ip_len > 0)
		ret = ceph_pton(ip_addr, ip_len, ss, -1, NULL);
	else
		ret = -ESRCH;

	kfree(ip_addr);

	*ipend = end;

	pr_info("resolve '%.*s' (ret=%d): %s\n", (int)(end - name), name,
			ret, ret ? "failed" : ceph_pr_addr(ss));

	return ret;
}
#else
static inline int ceph_dns_resolve_name(const char *name, size_t namelen,
		struct sockaddr_storage *ss, char delim, const char **ipend)
{
	return -EINVAL;
}
#endif

/*
 * Parse a server name (IP or hostname). If a valid IP address is not found
 * then try to extract a hostname to resolve using userspace DNS upcall.
 */
static int ceph_parse_server_name(const char *name, size_t namelen,
			struct sockaddr_storage *ss, char delim, const char **ipend)
{
	int ret;

	ret = ceph_pton(name, namelen, ss, delim, ipend);
	if (ret)
		ret = ceph_dns_resolve_name(name, namelen, ss, delim, ipend);

	return ret;
}

/*
/*
 * Parse an ip[:port] list into an addr array.  Use the default
 * Parse an ip[:port] list into an addr array.  Use the default
 * monitor port if a port isn't specified.
 * monitor port if a port isn't specified.
@@ -1085,15 +1181,13 @@ int ceph_parse_ips(const char *c, const char *end,
		   struct ceph_entity_addr *addr,
		   struct ceph_entity_addr *addr,
		   int max_count, int *count)
		   int max_count, int *count)
{
{
	int i;
	int i, ret = -EINVAL;
	const char *p = c;
	const char *p = c;


	dout("parse_ips on '%.*s'\n", (int)(end-c), c);
	dout("parse_ips on '%.*s'\n", (int)(end-c), c);
	for (i = 0; i < max_count; i++) {
	for (i = 0; i < max_count; i++) {
		const char *ipend;
		const char *ipend;
		struct sockaddr_storage *ss = &addr[i].in_addr;
		struct sockaddr_storage *ss = &addr[i].in_addr;
		struct sockaddr_in *in4 = (void *)ss;
		struct sockaddr_in6 *in6 = (void *)ss;
		int port;
		int port;
		char delim = ',';
		char delim = ',';


@@ -1102,15 +1196,11 @@ int ceph_parse_ips(const char *c, const char *end,
			p++;
			p++;
		}
		}


		memset(ss, 0, sizeof(*ss));
		ret = ceph_parse_server_name(p, end - p, ss, delim, &ipend);
		if (in4_pton(p, end - p, (u8 *)&in4->sin_addr.s_addr,
		if (ret)
			     delim, &ipend))
			ss->ss_family = AF_INET;
		else if (in6_pton(p, end - p, (u8 *)&in6->sin6_addr.s6_addr,
				  delim, &ipend))
			ss->ss_family = AF_INET6;
		else
			goto bad;
			goto bad;
		ret = -EINVAL;

		p = ipend;
		p = ipend;


		if (delim == ']') {
		if (delim == ']') {
@@ -1155,7 +1245,7 @@ int ceph_parse_ips(const char *c, const char *end,


bad:
bad:
	pr_err("parse_ips bad ip '%.*s'\n", (int)(end - c), c);
	pr_err("parse_ips bad ip '%.*s'\n", (int)(end - c), c);
	return -EINVAL;
	return ret;
}
}
EXPORT_SYMBOL(ceph_parse_ips);
EXPORT_SYMBOL(ceph_parse_ips);