@@ -248,7 +248,11 @@ struct netstrfns {
char *nf_name;
char *nf_modname;
void (*nf_addr2str)(u32 addr, char *str, size_t size);
+ void (*nf_addr2str_size)(const __be32 *addr, size_t asize,
+ char *str, size_t size);
int (*nf_str2addr)(const char *str, int nob, u32 *addr);
+ int (*nf_str2addr_size)(const char *str, int nob,
+ __be32 *addr, size_t *asize);
int (*nf_parse_addrlist)(char *str, int len,
struct list_head *list);
int (*nf_print_addrlist)(char *buffer, int count,
@@ -100,6 +100,7 @@ static inline char *libcfs_nidstr(const struct lnet_nid *nid)
__u32 libcfs_str2net(const char *str);
lnet_nid_t libcfs_str2nid(const char *str);
+int libcfs_strnid(struct lnet_nid *nid, const char *str);
int libcfs_str2anynid(lnet_nid_t *nid, const char *str);
char *libcfs_id2str(struct lnet_process_id id);
void cfs_free_nidlist(struct list_head *list);
@@ -38,6 +38,7 @@
#include <linux/spinlock.h>
#include <linux/slab.h>
+#include <linux/sunrpc/addr.h>
#include <linux/libcfs/libcfs.h>
#include <linux/libcfs/libcfs_string.h>
#include <uapi/linux/lnet/nidstr.h>
@@ -466,8 +467,31 @@ int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist)
(addr >> 8) & 0xff, addr & 0xff);
}
-/*
- * CAVEAT EMPTOR XscanfX
+static void
+libcfs_ip_addr2str_size(const __be32 *addr, size_t asize,
+ char *str, size_t size)
+{
+ struct sockaddr_storage sa = {};
+
+ switch (asize) {
+ case 4:
+ sa.ss_family = AF_INET;
+ memcpy(&((struct sockaddr_in *)(&sa))->sin_addr.s_addr,
+ addr, asize);
+ break;
+ case 16:
+ sa.ss_family = AF_INET6;
+ memcpy(&((struct sockaddr_in6 *)(&sa))->sin6_addr.s6_addr,
+ addr, asize);
+ break;
+ default:
+ return;
+ }
+
+ rpc_ntop((struct sockaddr *)&sa, str, size);
+}
+
+/* CAVEAT EMPTOR XscanfX
* I use "%n" at the end of a sscanf format to detect trailing junk. However
* sscanf may return immediately if it sees the terminating '0' in a string, so
* I initialise the %n variable to the expected length. If sscanf sets it;
@@ -495,6 +519,37 @@ int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist)
return 0;
}
+static int
+libcfs_ip_str2addr_size(const char *str, int nob,
+ __be32 *addr, size_t *alen)
+{
+ struct sockaddr_storage sa;
+
+ /* Note: 'net' arg to rpc_pton is only needed for link-local
+ * addresses. Such addresses would not work with LNet routing,
+ * so we can assume they aren't used. So it doesn't matter
+ * which net namespace is passed.
+ */
+ if (rpc_pton(&init_net, str, nob,
+ (struct sockaddr *)&sa, sizeof(sa)) == 0)
+ return 0;
+ if (sa.ss_family == AF_INET6) {
+ memcpy(addr,
+ &((struct sockaddr_in6 *)(&sa))->sin6_addr.s6_addr,
+ 16);
+ *alen = 16;
+ return 1;
+ }
+ if (sa.ss_family == AF_INET) {
+ memcpy(addr,
+ &((struct sockaddr_in *)(&sa))->sin_addr.s_addr,
+ 4);
+ *alen = 4;
+ return 1;
+ }
+ return 0;
+}
+
/* Used by lnet/config.c so it can't be static */
int
cfs_ip_addr_parse(char *str, int len, struct list_head *list)
@@ -660,7 +715,9 @@ int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist)
.nf_name = "tcp",
.nf_modname = "ksocklnd",
.nf_addr2str = libcfs_ip_addr2str,
+ .nf_addr2str_size = libcfs_ip_addr2str_size,
.nf_str2addr = libcfs_ip_str2addr,
+ .nf_str2addr_size = libcfs_ip_str2addr_size,
.nf_parse_addrlist = cfs_ip_addr_parse,
.nf_print_addrlist = libcfs_ip_addr_range_print,
.nf_match_addr = cfs_ip_addr_match
@@ -920,10 +977,14 @@ int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist)
}
nf = libcfs_lnd2netstrfns(lnd);
- if (nf && nid_is_nid4(nid)) {
+ if (nf) {
size_t addr_len;
- nf->nf_addr2str(ntohl(nid->nid_addr[0]), buf, buf_size);
+ if (nf->nf_addr2str_size)
+ nf->nf_addr2str_size(nid->nid_addr, NID_ADDR_BYTES(nid),
+ buf, buf_size);
+ else
+ nf->nf_addr2str(ntohl(nid->nid_addr[0]), buf, buf_size);
addr_len = strlen(buf);
if (nnum == 0)
snprintf(buf + addr_len, buf_size - addr_len, "@%s",
@@ -1020,6 +1081,46 @@ int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist)
}
EXPORT_SYMBOL(libcfs_str2nid);
+int
+libcfs_strnid(struct lnet_nid *nid, const char *str)
+{
+ const char *sep = strchr(str, '@');
+ struct netstrfns *nf;
+ u32 net;
+
+ if (sep) {
+ nf = libcfs_str2net_internal(sep + 1, &net);
+ if (!nf)
+ return -EINVAL;
+ } else {
+ sep = str + strlen(str);
+ net = LNET_MKNET(SOCKLND, 0);
+ nf = libcfs_lnd2netstrfns(SOCKLND);
+ LASSERT(nf);
+ }
+
+ memset(nid, 0, sizeof(*nid));
+ nid->nid_type = LNET_NETTYP(net);
+ nid->nid_num = htons(LNET_NETNUM(net));
+ if (nf->nf_str2addr_size) {
+ size_t asize = 0;
+
+ if (!nf->nf_str2addr_size(str, (int)(sep - str),
+ nid->nid_addr, &asize))
+ return -EINVAL;
+ nid->nid_size = asize - 4;
+ } else {
+ u32 addr;
+
+ if (!nf->nf_str2addr(str, (int)(sep - str), &addr))
+ return -EINVAL;
+ nid->nid_addr[0] = htonl(addr);
+ nid->nid_size = 0;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(libcfs_strnid);
+
char *
libcfs_id2str(struct lnet_process_id id)
{