From b6c702df5d4de8e5a806169404ba1c069ea8fff2 Mon Sep 17 00:00:00 2001 From: Mr NeilBrown Date: Mon, 20 Feb 2023 12:06:41 +1100 Subject: [PATCH] LU-10391 libcfs: add large-nid string conversion functions. The user-space libcfs now has functions to convert between strings and large nids. Signed-off-by: Mr NeilBrown Change-Id: I554e2da0c3d56397ebe60fc84fad28fec6704a18 Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/50092 Tested-by: jenkins Tested-by: Maloo Reviewed-by: James Simmons Reviewed-by: Serguei Smirnov Reviewed-by: Oleg Drokin --- libcfs/autoconf/lustre-libcfs.m4 | 1 + libcfs/include/libcfs/util/string.h | 4 + libcfs/libcfs/util/nidstrings.c | 175 ++++++++++++++++++++++++++++++++++ lnet/include/lnet/lib-types.h | 11 --- lnet/include/uapi/linux/lnet/nidstr.h | 11 +++ 5 files changed, 191 insertions(+), 11 deletions(-) diff --git a/libcfs/autoconf/lustre-libcfs.m4 b/libcfs/autoconf/lustre-libcfs.m4 index b3cadf9..4d66b10 100644 --- a/libcfs/autoconf/lustre-libcfs.m4 +++ b/libcfs/autoconf/lustre-libcfs.m4 @@ -2616,6 +2616,7 @@ AC_MSG_NOTICE([LibCFS core checks # libcfs/libcfs/util/nidstrings.c AC_CHECK_HEADERS([netdb.h asm/types.h endian.h]) AC_CHECK_FUNCS([gethostbyname]) +AC_CHECK_FUNCS([getaddrinfo]) # -------- Check for required packages -------------- diff --git a/libcfs/include/libcfs/util/string.h b/libcfs/include/libcfs/util/string.h index 97d9adb..d44fd2f 100644 --- a/libcfs/include/libcfs/util/string.h +++ b/libcfs/include/libcfs/util/string.h @@ -80,7 +80,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, diff --git a/libcfs/libcfs/util/nidstrings.c b/libcfs/libcfs/util/nidstrings.c index 780a8ab..e7539cf 100644 --- a/libcfs/libcfs/util/nidstrings.c +++ b/libcfs/libcfs/util/nidstrings.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -97,6 +98,22 @@ libcfs_ip_addr2str(__u32 addr, char *str, size_t size) (addr >> 8) & 0xff, addr & 0xff); } +static void +libcfs_ip_addr2str_size(const __be32 *addr, size_t asize, + char *str, size_t size) +{ + switch (asize) { + case 4: + inet_ntop(AF_INET, addr, str, size); + break; + case 16: + inet_ntop(AF_INET6, addr, str, size); + break; + default: + return; + } +} + /* 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 @@ -150,6 +167,68 @@ libcfs_ip_str2addr(const char *str, int nob, __u32 *addr) return 0; } +static int +libcfs_ip_str2addr_size(const char *str, int nob, + __be32 *addr, size_t *alen) +{ + char *tmp = malloc(nob+1); + int ret = 1; + + if (!tmp) + return 0; + memcpy(tmp, str, nob); + tmp[nob] = 0; + + if (inet_pton(AF_INET, tmp, (struct in_addr *)addr) == 0) { + *alen = 4; + goto out; + } + if (inet_pton(AF_INET6, tmp, (struct in6_addr *)addr) == 0) { + *alen = 16; + goto out; + } +#ifdef HAVE_GETADDRINFO + /* known hostname? */ + if (('a' <= str[0] && str[0] <= 'z') || + ('A' <= str[0] && str[0] <= 'Z')) { + struct addrinfo *ai = NULL; + + if (getaddrinfo(tmp, NULL, NULL, &ai) == 0) { + struct addrinfo *a; + /* First look for an AF_INET address */ + for (a = ai; a; a = a->ai_next) { + if (a->ai_family == AF_INET && a->ai_addr) { + struct sockaddr_in *sin = + (void *)ai->ai_addr; + + memcpy(addr, &sin->sin_addr, 4); + *alen = 4; + freeaddrinfo(ai); + goto out; + } + } + /* Now consider AF_INET6 */ + for (a = ai; a; a = a->ai_next) { + if (a->ai_family == AF_INET6 && a->ai_addr) { + struct sockaddr_in6 *sin6 = + (void *)ai->ai_addr; + + memcpy(addr, &sin6->sin6_addr, 16); + *alen = 16; + freeaddrinfo(ai); + goto out; + } + } + } + freeaddrinfo(ai); + } +#endif + ret = 0; +out: + free(tmp); + return ret; +} + int cfs_ip_addr_parse(char *str, int len, struct list_head *list) { @@ -508,7 +587,9 @@ static struct netstrfns libcfs_netstrfns[] = { .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, @@ -709,6 +790,54 @@ libcfs_nid2str_r(lnet_nid_t nid, char *buf, size_t buf_size) return buf; } +char * +libcfs_nidstr_r(const struct lnet_nid *nid, char *buf, size_t buf_size) +{ + __u32 nnum; + __u32 lnd; + struct netstrfns *nf; + + if (LNET_NID_IS_ANY(nid)) { + strncpy(buf, "", buf_size); + buf[buf_size - 1] = '\0'; + return buf; + } + + nnum = __be16_to_cpu(nid->nid_num); + lnd = nid->nid_type; + nf = libcfs_lnd2netstrfns(lnd); + if (nf) { + size_t addr_len; + /* Avoid take address in packed array */ + __u32 addr[4] = { nid->nid_addr[0], nid->nid_addr[1], + nid->nid_addr[2], nid->nid_addr[3]}; + + if (nf->nf_addr2str_size) + nf->nf_addr2str_size(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", + nf->nf_name); + else + snprintf(buf + addr_len, buf_size - addr_len, "@%s%u", + nf->nf_name, nnum); + } else { + int l = 0; + int words = (NID_ADDR_BYTES(nid) + 3) / 4; + int i; + + for (i = 0; i < words && i < 4; i++) + l = snprintf(buf+l, buf_size-l, "%s%x", + i ? ":" : "", ntohl(nid->nid_addr[i])); + snprintf(buf+l, buf_size-l, "@<%u:%u>", lnd, nnum); + } + + return buf; +} + static struct netstrfns * libcfs_str2net_internal(const char *str, __u32 *net) { @@ -781,6 +910,52 @@ libcfs_str2nid(const char *str) return LNET_MKNID(net, addr); } +int +libcfs_strnid(struct lnet_nid *nid, const char *str) +{ + const char *sep = strchr(str, '@'); + struct netstrfns *nf; + __u32 net; + + if (sep != NULL) { + nf = libcfs_str2net_internal(sep + 1, &net); + if (nf == NULL) + return -EINVAL; + } else { + sep = str + strlen(str); + net = LNET_MKNET(SOCKLND, 0); + nf = libcfs_lnd2netstrfns(SOCKLND); + assert(nf != NULL); + } + + 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; + __u32 addr[4]; + + if (!nf->nf_str2addr_size(str, (int)(sep - str), + addr, &asize)) + return -EINVAL; + + /* Avoid take address in packed array */ + nid->nid_addr[0] = addr[0]; + nid->nid_addr[1] = addr[1]; + nid->nid_addr[2] = addr[2]; + nid->nid_addr[3] = addr[3]; + 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; +} + char * libcfs_id2str(struct lnet_process_id id) { diff --git a/lnet/include/lnet/lib-types.h b/lnet/include/lnet/lib-types.h index 6654665..5ce50e7 100644 --- a/lnet/include/lnet/lib-types.h +++ b/lnet/include/lnet/lib-types.h @@ -53,17 +53,6 @@ #include #include -char *libcfs_nidstr_r(const struct lnet_nid *nid, - char *buf, size_t buf_size); - -static inline char *libcfs_nidstr(const struct lnet_nid *nid) -{ - return libcfs_nidstr_r(nid, libcfs_next_nidstring(), - LNET_NIDSTR_SIZE); -} - -int libcfs_strnid(struct lnet_nid *nid, const char *str); -char *libcfs_idstr(struct lnet_processid *id); int libcfs_strid(struct lnet_processid *id, const char *str); int cfs_match_nid_net(struct lnet_nid *nid, u32 net, diff --git a/lnet/include/uapi/linux/lnet/nidstr.h b/lnet/include/uapi/linux/lnet/nidstr.h index 9e4b156..9b494cc 100644 --- a/lnet/include/uapi/linux/lnet/nidstr.h +++ b/lnet/include/uapi/linux/lnet/nidstr.h @@ -86,6 +86,17 @@ static inline char *libcfs_nid2str(lnet_nid_t nid) LNET_NIDSTR_SIZE); } +char *libcfs_nidstr_r(const struct lnet_nid *nid, + char *buf, __kernel_size_t buf_size); + +static inline char *libcfs_nidstr(const struct lnet_nid *nid) +{ + return libcfs_nidstr_r(nid, libcfs_next_nidstring(), + LNET_NIDSTR_SIZE); +} + +int libcfs_strnid(struct lnet_nid *nid, const char *str); +char *libcfs_idstr(struct lnet_processid *id); __u32 libcfs_str2net(const char *str); lnet_nid_t libcfs_str2nid(const char *str); int libcfs_str2anynid(lnet_nid_t *nid, const char *str); -- 1.8.3.1