diff options
-rw-r--r-- | net/ceph/Kconfig | 14 | ||||
-rw-r--r-- | net/ceph/messenger.c | 114 |
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 | ||
30 | config 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 | */ | ||
1084 | static 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 | ||
1109 | static 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 | ||
1153 | static 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 | */ | ||
1164 | static 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 | ||
1156 | bad: | 1246 | bad: |
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 | } |
1160 | EXPORT_SYMBOL(ceph_parse_ips); | 1250 | EXPORT_SYMBOL(ceph_parse_ips); |
1161 | 1251 | ||