aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ceph/Kconfig14
-rw-r--r--net/ceph/messenger.c114
2 files changed, 116 insertions, 12 deletions
diff --git a/net/ceph/Kconfig b/net/ceph/Kconfig
index be683f2d401f..cc04dd667a10 100644
--- a/net/ceph/Kconfig
+++ b/net/ceph/Kconfig
@@ -27,3 +27,17 @@ config CEPH_LIB_PRETTYDEBUG
27 27
28 If unsure, say N. 28 If unsure, say N.
29 29
30config CEPH_LIB_USE_DNS_RESOLVER
31 bool "Use in-kernel support for DNS lookup"
32 depends on CEPH_LIB
33 select DNS_RESOLVER
34 default n
35 help
36 If you say Y here, hostnames (e.g. monitor addresses) will
37 be resolved using the CONFIG_DNS_RESOLVER facility.
38
39 For information on how to use CONFIG_DNS_RESOLVER consult
40 Documentation/networking/dns_resolver.txt
41
42 If unsure, say N.
43
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
index f56aca302617..f466930e26fa 100644
--- a/net/ceph/messenger.c
+++ b/net/ceph/messenger.c
@@ -11,6 +11,7 @@
11#include <linux/string.h> 11#include <linux/string.h>
12#include <linux/bio.h> 12#include <linux/bio.h>
13#include <linux/blkdev.h> 13#include <linux/blkdev.h>
14#include <linux/dns_resolver.h>
14#include <net/tcp.h> 15#include <net/tcp.h>
15 16
16#include <linux/ceph/libceph.h> 17#include <linux/ceph/libceph.h>
@@ -1078,6 +1079,101 @@ static void addr_set_port(struct sockaddr_storage *ss, int p)
1078} 1079}
1079 1080
1080/* 1081/*
1082 * Unlike other *_pton function semantics, zero indicates success.
1083 */
1084static int ceph_pton(const char *str, size_t len, struct sockaddr_storage *ss,
1085 char delim, const char **ipend)
1086{
1087 struct sockaddr_in *in4 = (void *)ss;
1088 struct sockaddr_in6 *in6 = (void *)ss;
1089
1090 memset(ss, 0, sizeof(*ss));
1091
1092 if (in4_pton(str, len, (u8 *)&in4->sin_addr.s_addr, delim, ipend)) {
1093 ss->ss_family = AF_INET;
1094 return 0;
1095 }
1096
1097 if (in6_pton(str, len, (u8 *)&in6->sin6_addr.s6_addr, delim, ipend)) {
1098 ss->ss_family = AF_INET6;
1099 return 0;
1100 }
1101
1102 return -EINVAL;
1103}
1104
1105/*
1106 * Extract hostname string and resolve using kernel DNS facility.
1107 */
1108#ifdef CONFIG_CEPH_LIB_USE_DNS_RESOLVER
1109static int ceph_dns_resolve_name(const char *name, size_t namelen,
1110 struct sockaddr_storage *ss, char delim, const char **ipend)
1111{
1112 const char *end, *delim_p;
1113 char *colon_p, *ip_addr = NULL;
1114 int ip_len, ret;
1115
1116 /*
1117 * The end of the hostname occurs immediately preceding the delimiter or
1118 * the port marker (':') where the delimiter takes precedence.
1119 */
1120 delim_p = memchr(name, delim, namelen);
1121 colon_p = memchr(name, ':', namelen);
1122
1123 if (delim_p && colon_p)
1124 end = delim_p < colon_p ? delim_p : colon_p;
1125 else if (!delim_p && colon_p)
1126 end = colon_p;
1127 else {
1128 end = delim_p;
1129 if (!end) /* case: hostname:/ */
1130 end = name + namelen;
1131 }
1132
1133 if (end <= name)
1134 return -EINVAL;
1135
1136 /* do dns_resolve upcall */
1137 ip_len = dns_query(NULL, name, end - name, NULL, &ip_addr, NULL);
1138 if (ip_len > 0)
1139 ret = ceph_pton(ip_addr, ip_len, ss, -1, NULL);
1140 else
1141 ret = -ESRCH;
1142
1143 kfree(ip_addr);
1144
1145 *ipend = end;
1146
1147 pr_info("resolve '%.*s' (ret=%d): %s\n", (int)(end - name), name,
1148 ret, ret ? "failed" : ceph_pr_addr(ss));
1149
1150 return ret;
1151}
1152#else
1153static inline int ceph_dns_resolve_name(const char *name, size_t namelen,
1154 struct sockaddr_storage *ss, char delim, const char **ipend)
1155{
1156 return -EINVAL;
1157}
1158#endif
1159
1160/*
1161 * Parse a server name (IP or hostname). If a valid IP address is not found
1162 * then try to extract a hostname to resolve using userspace DNS upcall.
1163 */
1164static int ceph_parse_server_name(const char *name, size_t namelen,
1165 struct sockaddr_storage *ss, char delim, const char **ipend)
1166{
1167 int ret;
1168
1169 ret = ceph_pton(name, namelen, ss, delim, ipend);
1170 if (ret)
1171 ret = ceph_dns_resolve_name(name, namelen, ss, delim, ipend);
1172
1173 return ret;
1174}
1175
1176/*
1081 * Parse an ip[:port] list into an addr array. Use the default 1177 * Parse an ip[:port] list into an addr array. Use the default
1082 * monitor port if a port isn't specified. 1178 * monitor port if a port isn't specified.
1083 */ 1179 */
@@ -1085,15 +1181,13 @@ int ceph_parse_ips(const char *c, const char *end,
1085 struct ceph_entity_addr *addr, 1181 struct ceph_entity_addr *addr,
1086 int max_count, int *count) 1182 int max_count, int *count)
1087{ 1183{
1088 int i; 1184 int i, ret = -EINVAL;
1089 const char *p = c; 1185 const char *p = c;
1090 1186
1091 dout("parse_ips on '%.*s'\n", (int)(end-c), c); 1187 dout("parse_ips on '%.*s'\n", (int)(end-c), c);
1092 for (i = 0; i < max_count; i++) { 1188 for (i = 0; i < max_count; i++) {
1093 const char *ipend; 1189 const char *ipend;
1094 struct sockaddr_storage *ss = &addr[i].in_addr; 1190 struct sockaddr_storage *ss = &addr[i].in_addr;
1095 struct sockaddr_in *in4 = (void *)ss;
1096 struct sockaddr_in6 *in6 = (void *)ss;
1097 int port; 1191 int port;
1098 char delim = ','; 1192 char delim = ',';
1099 1193
@@ -1102,15 +1196,11 @@ int ceph_parse_ips(const char *c, const char *end,
1102 p++; 1196 p++;
1103 } 1197 }
1104 1198
1105 memset(ss, 0, sizeof(*ss)); 1199 ret = ceph_parse_server_name(p, end - p, ss, delim, &ipend);
1106 if (in4_pton(p, end - p, (u8 *)&in4->sin_addr.s_addr, 1200 if (ret)
1107 delim, &ipend))
1108 ss->ss_family = AF_INET;
1109 else if (in6_pton(p, end - p, (u8 *)&in6->sin6_addr.s6_addr,
1110 delim, &ipend))
1111 ss->ss_family = AF_INET6;
1112 else
1113 goto bad; 1201 goto bad;
1202 ret = -EINVAL;
1203
1114 p = ipend; 1204 p = ipend;
1115 1205
1116 if (delim == ']') { 1206 if (delim == ']') {
@@ -1155,7 +1245,7 @@ int ceph_parse_ips(const char *c, const char *end,
1155 1245
1156bad: 1246bad:
1157 pr_err("parse_ips bad ip '%.*s'\n", (int)(end - c), c); 1247 pr_err("parse_ips bad ip '%.*s'\n", (int)(end - c), c);
1158 return -EINVAL; 1248 return ret;
1159} 1249}
1160EXPORT_SYMBOL(ceph_parse_ips); 1250EXPORT_SYMBOL(ceph_parse_ips);
1161 1251