X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lnet%2Flnet%2Fnidstrings.c;h=2061142f295611bcb87fbd472f0342ece3c41f94;hb=416e67222b769df490a8be034ef987a596dd8dff;hp=59cccf9a3ca69d31a52b781e1fbeb225eb781be3;hpb=d231bc874075672d3302727e53baef8f4dd03287;p=fs%2Flustre-release.git diff --git a/lnet/lnet/nidstrings.c b/lnet/lnet/nidstrings.c index 59cccf9..2061142 100644 --- a/lnet/lnet/nidstrings.c +++ b/lnet/lnet/nidstrings.c @@ -15,11 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ @@ -27,7 +23,7 @@ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. * - * Copyright (c) 2011, 2014, Intel Corporation. + * Copyright (c) 2011, 2015, Intel Corporation. */ /* * This file is part of Lustre, http://www.lustre.org/ @@ -41,7 +37,7 @@ #define DEBUG_SUBSYSTEM S_LNET #include -#include +#include /* max value for numeric network address */ #define MAX_NUMERIC_VALUE 0xffffffff @@ -60,22 +56,23 @@ * between getting its string and using it. */ -static char libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE]; -static int libcfs_nidstring_idx; +static char libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE]; +static int libcfs_nidstring_idx; static DEFINE_SPINLOCK(libcfs_nidstring_lock); +static struct netstrfns *libcfs_namenum2netstrfns(const char *name); + char * libcfs_next_nidstring(void) { - char *str; + char *str; unsigned long flags; spin_lock_irqsave(&libcfs_nidstring_lock, flags); str = libcfs_nidstrings[libcfs_nidstring_idx++]; - if (libcfs_nidstring_idx == - sizeof(libcfs_nidstrings)/sizeof(libcfs_nidstrings[0])) + if (libcfs_nidstring_idx == ARRAY_SIZE(libcfs_nidstrings)) libcfs_nidstring_idx = 0; spin_unlock_irqrestore(&libcfs_nidstring_lock, flags); @@ -83,740 +80,235 @@ libcfs_next_nidstring(void) } EXPORT_SYMBOL(libcfs_next_nidstring); -static int libcfs_lo_str2addr(const char *str, int nob, __u32 *addr); -static void libcfs_ip_addr2str(__u32 addr, char *str, size_t size); -static int libcfs_ip_str2addr(const char *str, int nob, __u32 *addr); -static bool cfs_ip_is_contiguous(struct list_head *nidlist); -static void cfs_ip_min_max(struct list_head *nidlist, __u32 *min, __u32 *max); -static void libcfs_decnum_addr2str(__u32 addr, char *str, size_t size); -static void libcfs_hexnum_addr2str(__u32 addr, char *str, size_t size); -static int libcfs_num_str2addr(const char *str, int nob, __u32 *addr); -static int libcfs_num_parse(char *str, int len, struct list_head *list); -static int libcfs_num_match(__u32 addr, struct list_head *list); -static int libcfs_num_addr_range_print(char *buffer, int count, - struct list_head *list); -static int libcfs_ip_addr_range_print(char *buffer, int count, - struct list_head *list); -static bool cfs_num_is_contiguous(struct list_head *nidlist); -static void cfs_num_min_max(struct list_head *nidlist, __u32 *min, __u32 *max); - -static struct netstrfns libcfs_netstrfns[] = { - {/* .nf_type */ LOLND, - /* .nf_name */ "lo", - /* .nf_modname */ "klolnd", - /* .nf_addr2str */ libcfs_decnum_addr2str, - /* .nf_str2addr */ libcfs_lo_str2addr, - /* .nf_parse_addr*/ libcfs_num_parse, - /* .nf_print_addrlist*/ libcfs_num_addr_range_print, - /* .nf_match_addr*/ libcfs_num_match, - /* .nf_is_contiguous */ cfs_num_is_contiguous, - /* .nf_min_max */ cfs_num_min_max}, - {/* .nf_type */ SOCKLND, - /* .nf_name */ "tcp", - /* .nf_modname */ "ksocklnd", - /* .nf_addr2str */ libcfs_ip_addr2str, - /* .nf_str2addr */ libcfs_ip_str2addr, - /* .nf_parse_addrlist*/ cfs_ip_addr_parse, - /* .nf_print_addrlist*/ libcfs_ip_addr_range_print, - /* .nf_match_addr*/ cfs_ip_addr_match, - /* .nf_is_contiguous */ cfs_ip_is_contiguous, - /* .nf_min_max */ cfs_ip_min_max}, - {/* .nf_type */ O2IBLND, - /* .nf_name */ "o2ib", - /* .nf_modname */ "ko2iblnd", - /* .nf_addr2str */ libcfs_ip_addr2str, - /* .nf_str2addr */ libcfs_ip_str2addr, - /* .nf_parse_addrlist*/ cfs_ip_addr_parse, - /* .nf_print_addrlist*/ libcfs_ip_addr_range_print, - /* .nf_match_addr*/ cfs_ip_addr_match, - /* .nf_is_contiguous */ cfs_ip_is_contiguous, - /* .nf_min_max */ cfs_ip_min_max}, - {/* .nf_type */ CIBLND, - /* .nf_name */ "cib", - /* .nf_modname */ "kciblnd", - /* .nf_addr2str */ libcfs_ip_addr2str, - /* .nf_str2addr */ libcfs_ip_str2addr, - /* .nf_parse_addrlist*/ cfs_ip_addr_parse, - /* .nf_print_addrlist*/ libcfs_ip_addr_range_print, - /* .nf_match_addr*/ cfs_ip_addr_match, - /* .nf_is_contiguous */ cfs_ip_is_contiguous, - /* .nf_min_max */ cfs_ip_min_max}, - {/* .nf_type */ OPENIBLND, - /* .nf_name */ "openib", - /* .nf_modname */ "kopeniblnd", - /* .nf_addr2str */ libcfs_ip_addr2str, - /* .nf_str2addr */ libcfs_ip_str2addr, - /* .nf_parse_addrlist*/ cfs_ip_addr_parse, - /* .nf_print_addrlist*/ libcfs_ip_addr_range_print, - /* .nf_match_addr*/ cfs_ip_addr_match, - /* .nf_is_contiguous */ cfs_ip_is_contiguous, - /* .nf_min_max */ cfs_ip_min_max}, - {/* .nf_type */ IIBLND, - /* .nf_name */ "iib", - /* .nf_modname */ "kiiblnd", - /* .nf_addr2str */ libcfs_ip_addr2str, - /* .nf_str2addr */ libcfs_ip_str2addr, - /* .nf_parse_addrlist*/ cfs_ip_addr_parse, - /* .nf_print_addrlist*/ libcfs_ip_addr_range_print, - /* .nf_match_addr*/ cfs_ip_addr_match, - /* .nf_is_contiguous */ cfs_ip_is_contiguous, - /* .nf_min_max */ cfs_ip_min_max}, - {/* .nf_type */ VIBLND, - /* .nf_name */ "vib", - /* .nf_modname */ "kviblnd", - /* .nf_addr2str */ libcfs_ip_addr2str, - /* .nf_str2addr */ libcfs_ip_str2addr, - /* .nf_parse_addrlist*/ cfs_ip_addr_parse, - /* .nf_print_addrlist*/ libcfs_ip_addr_range_print, - /* .nf_match_addr*/ cfs_ip_addr_match, - /* .nf_is_contiguous */ cfs_ip_is_contiguous, - /* .nf_min_max */ cfs_ip_min_max}, - {/* .nf_type */ RALND, - /* .nf_name */ "ra", - /* .nf_modname */ "kralnd", - /* .nf_addr2str */ libcfs_ip_addr2str, - /* .nf_str2addr */ libcfs_ip_str2addr, - /* .nf_parse_addrlist*/ cfs_ip_addr_parse, - /* .nf_print_addrlist*/ libcfs_ip_addr_range_print, - /* .nf_match_addr*/ cfs_ip_addr_match, - /* .nf_is_contiguous */ cfs_ip_is_contiguous, - /* .nf_min_max */ cfs_ip_min_max}, - {/* .nf_type */ QSWLND, - /* .nf_name */ "elan", - /* .nf_modname */ "kqswlnd", - /* .nf_addr2str */ libcfs_decnum_addr2str, - /* .nf_str2addr */ libcfs_num_str2addr, - /* .nf_parse_addrlist*/ libcfs_num_parse, - /* .nf_print_addrlist*/ libcfs_num_addr_range_print, - /* .nf_match_addr*/ libcfs_num_match, - /* .nf_is_contiguous */ cfs_num_is_contiguous, - /* .nf_min_max */ cfs_num_min_max}, - {/* .nf_type */ GMLND, - /* .nf_name */ "gm", - /* .nf_modname */ "kgmlnd", - /* .nf_addr2str */ libcfs_hexnum_addr2str, - /* .nf_str2addr */ libcfs_num_str2addr, - /* .nf_parse_addrlist*/ libcfs_num_parse, - /* .nf_print_addrlist*/ libcfs_num_addr_range_print, - /* .nf_match_addr*/ libcfs_num_match, - /* .nf_is_contiguous */ cfs_num_is_contiguous, - /* .nf_min_max */ cfs_num_min_max}, - {/* .nf_type */ MXLND, - /* .nf_name */ "mx", - /* .nf_modname */ "kmxlnd", - /* .nf_addr2str */ libcfs_ip_addr2str, - /* .nf_str2addr */ libcfs_ip_str2addr, - /* .nf_parse_addrlist*/ cfs_ip_addr_parse, - /* .nf_print_addrlist*/ libcfs_ip_addr_range_print, - /* .nf_match_addr*/ cfs_ip_addr_match, - /* .nf_is_contiguous */ cfs_ip_is_contiguous, - /* .nf_min_max */ cfs_ip_min_max}, - {/* .nf_type */ PTLLND, - /* .nf_name */ "ptl", - /* .nf_modname */ "kptllnd", - /* .nf_addr2str */ libcfs_decnum_addr2str, - /* .nf_str2addr */ libcfs_num_str2addr, - /* .nf_parse_addrlist*/ libcfs_num_parse, - /* .nf_print_addrlist*/ libcfs_num_addr_range_print, - /* .nf_match_addr*/ libcfs_num_match, - /* .nf_is_contiguous */ cfs_num_is_contiguous, - /* .nf_min_max */ cfs_num_min_max}, - {/* .nf_type */ GNILND, - /* .nf_name */ "gni", - /* .nf_modname */ "kgnilnd", - /* .nf_addr2str */ libcfs_decnum_addr2str, - /* .nf_str2addr */ libcfs_num_str2addr, - /* .nf_parse_addrlist*/ libcfs_num_parse, - /* .nf_print_addrlist*/ libcfs_num_addr_range_print, - /* .nf_match_addr*/ libcfs_num_match, - /* .nf_is_contiguous */ cfs_num_is_contiguous, - /* .nf_min_max */ cfs_num_min_max}, - {/* .nf_type */ GNIIPLND, - /* .nf_name */ "gip", - /* .nf_modname */ "kgnilnd", - /* .nf_addr2str */ libcfs_ip_addr2str, - /* .nf_str2addr */ libcfs_ip_str2addr, - /* .nf_parse_addrlist*/ cfs_ip_addr_parse, - /* .nf_print_addrlist*/ libcfs_ip_addr_range_print, - /* .nf_match_addr*/ cfs_ip_addr_match, - /* .nf_is_contiguous */ cfs_ip_is_contiguous, - /* .nf_min_max */ cfs_ip_min_max}, - /* placeholder for net0 alias. It MUST BE THE LAST ENTRY */ - {/* .nf_type */ -1}, +/** + * Nid range list syntax. + * \verbatim + * + * :== [ ' ' ] + * :== '@' + * :== '*' | + * | + * + * :== ... + * + * :== | + * + * :== '[' [ ',' ] ']' + * :== | + * '-' | + * '-' '/' + * :== | + * :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" | + * "vib" | "ra" | "elan" | "mx" | "ptl" + * \endverbatim + */ + +/** + * Structure to represent \ token of the syntax. + * + * One of this is created for each \ parsed. + */ +struct nidrange { + /** + * Link to list of this structures which is built on nid range + * list parsing. + */ + struct list_head nr_link; + /** + * List head for addrrange::ar_link. + */ + struct list_head nr_addrranges; + /** + * Flag indicating that *@ is found. + */ + int nr_all; + /** + * Pointer to corresponding element of libcfs_netstrfns. + */ + struct netstrfns *nr_netstrfns; + /** + * Number of network. E.g. 5 if \ is "elan5". + */ + int nr_netnum; }; -static const size_t libcfs_nnetstrfns = - sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]); +/** + * Structure to represent \ token of the syntax. + */ +struct addrrange { + /** + * Link to nidrange::nr_addrranges. + */ + struct list_head ar_link; + /** + * List head for cfs_expr_list::el_list. + */ + struct list_head ar_numaddr_ranges; +}; +/** + * Parses \ token on the syntax. + * + * Allocates struct addrrange and links to \a nidrange via + * (nidrange::nr_addrranges) + * + * \retval 0 if \a src parses to '*' | \ | \ + * \retval -errno otherwise + */ static int -libcfs_lo_str2addr(const char *str, int nob, __u32 *addr) +parse_addrange(const struct cfs_lstr *src, struct nidrange *nidrange) { - *addr = 0; - return 1; -} + struct addrrange *addrrange; -static void -libcfs_ip_addr2str(__u32 addr, char *str, size_t size) -{ - snprintf(str, size, "%u.%u.%u.%u", - (addr >> 24) & 0xff, (addr >> 16) & 0xff, - (addr >> 8) & 0xff, addr & 0xff); + if (src->ls_len == 1 && src->ls_str[0] == '*') { + nidrange->nr_all = 1; + return 0; + } + + CFS_ALLOC_PTR(addrrange); + if (addrrange == NULL) + return -ENOMEM; + list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges); + INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges); + + return nidrange->nr_netstrfns->nf_parse_addrlist(src->ls_str, + src->ls_len, + &addrrange->ar_numaddr_ranges); } -/* 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; - * fine, if it doesn't, then the scan ended at the end of the string, which is - * fine too :) */ -static int -libcfs_ip_str2addr(const char *str, int nob, __u32 *addr) +/** + * Finds or creates struct nidrange. + * + * Checks if \a src is a valid network name, looks for corresponding + * nidrange on the ist of nidranges (\a nidlist), creates new struct + * nidrange if it is not found. + * + * \retval pointer to struct nidrange matching network specified via \a src + * \retval NULL if \a src does not match any network + */ +static struct nidrange * +add_nidrange(const struct cfs_lstr *src, + struct list_head *nidlist) { - unsigned int a; - unsigned int b; - unsigned int c; - unsigned int d; - int n = nob; /* XscanfX */ + struct netstrfns *nf; + struct nidrange *nr; + int endlen; + unsigned netnum; - /* numeric IP? */ - if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 && - n == nob && - (a & ~0xff) == 0 && (b & ~0xff) == 0 && - (c & ~0xff) == 0 && (d & ~0xff) == 0) { - *addr = ((a<<24)|(b<<16)|(c<<8)|d); - return 1; + if (src->ls_len >= LNET_NIDSTR_SIZE) + return NULL; + + nf = libcfs_namenum2netstrfns(src->ls_str); + if (nf == NULL) + return NULL; + endlen = src->ls_len - strlen(nf->nf_name); + if (endlen == 0) + /* network name only, e.g. "elan" or "tcp" */ + netnum = 0; + else { + /* e.g. "elan25" or "tcp23", refuse to parse if + * network name is not appended with decimal or + * hexadecimal number */ + if (!cfs_str2num_check(src->ls_str + strlen(nf->nf_name), + endlen, &netnum, 0, MAX_NUMERIC_VALUE)) + return NULL; } - return 0; -} -static void -libcfs_decnum_addr2str(__u32 addr, char *str, size_t size) -{ - snprintf(str, size, "%u", addr); -} + list_for_each_entry(nr, nidlist, nr_link) { + if (nr->nr_netstrfns != nf) + continue; + if (nr->nr_netnum != netnum) + continue; + return nr; + } -static void -libcfs_hexnum_addr2str(__u32 addr, char *str, size_t size) -{ - snprintf(str, size, "0x%x", addr); + CFS_ALLOC_PTR(nr); + if (nr == NULL) + return NULL; + list_add_tail(&nr->nr_link, nidlist); + INIT_LIST_HEAD(&nr->nr_addrranges); + nr->nr_netstrfns = nf; + nr->nr_all = 0; + nr->nr_netnum = netnum; + + return nr; } +/** + * Parses \ token of the syntax. + * + * \retval 1 if \a src parses to \ '@' \ + * \retval 0 otherwise + */ static int -libcfs_num_str2addr(const char *str, int nob, __u32 *addr) +parse_nidrange(struct cfs_lstr *src, struct list_head *nidlist) { - int n; + struct cfs_lstr addrrange; + struct cfs_lstr net; + struct nidrange *nr; - n = nob; - if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob) - return 1; + if (cfs_gettok(src, '@', &addrrange) == 0) + goto failed; - n = nob; - if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob) - return 1; + if (cfs_gettok(src, '@', &net) == 0 || src->ls_str != NULL) + goto failed; - n = nob; - if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob) - return 1; + nr = add_nidrange(&net, nidlist); + if (nr == NULL) + goto failed; + + if (parse_addrange(&addrrange, nr) != 0) + goto failed; + return 1; +failed: return 0; } -static struct netstrfns * -libcfs_lnd2netstrfns(__u32 lnd) +/** + * Frees addrrange structures of \a list. + * + * For each struct addrrange structure found on \a list it frees + * cfs_expr_list list attached to it and frees the addrrange itself. + * + * \retval none + */ +static void +free_addrranges(struct list_head *list) { - int i; - - for (i = 0; i < libcfs_nnetstrfns; i++) - if (lnd == libcfs_netstrfns[i].nf_type) - return &libcfs_netstrfns[i]; - - return NULL; -} + while (!list_empty(list)) { + struct addrrange *ar; -static struct netstrfns * -libcfs_namenum2netstrfns(const char *name) -{ - struct netstrfns *nf; - int i; + ar = list_entry(list->next, struct addrrange, ar_link); - for (i = 0; i < libcfs_nnetstrfns; i++) { - nf = &libcfs_netstrfns[i]; - if (nf->nf_type >= 0 && - !strncmp(name, nf->nf_name, strlen(nf->nf_name))) - return nf; + cfs_expr_list_free_list(&ar->ar_numaddr_ranges); + list_del(&ar->ar_link); + CFS_FREE_PTR(ar); } - return NULL; } -static struct netstrfns * -libcfs_name2netstrfns(const char *name) +/** + * Frees nidrange strutures of \a list. + * + * For each struct nidrange structure found on \a list it frees + * addrrange list attached to it and frees the nidrange itself. + * + * \retval none + */ +void +cfs_free_nidlist(struct list_head *list) { - int i; - - for (i = 0; i < libcfs_nnetstrfns; i++) - if (libcfs_netstrfns[i].nf_type >= 0 && - !strcmp(libcfs_netstrfns[i].nf_name, name)) - return &libcfs_netstrfns[i]; + struct list_head *pos, *next; + struct nidrange *nr; - return NULL; + list_for_each_safe(pos, next, list) { + nr = list_entry(pos, struct nidrange, nr_link); + free_addrranges(&nr->nr_addrranges); + list_del(pos); + CFS_FREE_PTR(nr); + } } - -int -libcfs_isknown_lnd(__u32 lnd) -{ - return libcfs_lnd2netstrfns(lnd) != NULL; -} -EXPORT_SYMBOL(libcfs_isknown_lnd); - -char * -libcfs_lnd2modname(__u32 lnd) -{ - struct netstrfns *nf = libcfs_lnd2netstrfns(lnd); - - return (nf == NULL) ? NULL : nf->nf_modname; -} -EXPORT_SYMBOL(libcfs_lnd2modname); - -int -libcfs_str2lnd(const char *str) -{ - struct netstrfns *nf = libcfs_name2netstrfns(str); - - if (nf != NULL) - return nf->nf_type; - - return -1; -} -EXPORT_SYMBOL(libcfs_str2lnd); - -char * -libcfs_lnd2str_r(__u32 lnd, char *buf, size_t buf_size) -{ - struct netstrfns *nf; - - nf = libcfs_lnd2netstrfns(lnd); - if (nf == NULL) - snprintf(buf, buf_size, "?%u?", lnd); - else - snprintf(buf, buf_size, "%s", nf->nf_name); - - return buf; -} -EXPORT_SYMBOL(libcfs_lnd2str_r); - -char * -libcfs_net2str_r(__u32 net, char *buf, size_t buf_size) -{ - __u32 nnum = LNET_NETNUM(net); - __u32 lnd = LNET_NETTYP(net); - struct netstrfns *nf; - - nf = libcfs_lnd2netstrfns(lnd); - if (nf == NULL) - snprintf(buf, buf_size, "<%u:%u>", lnd, nnum); - else if (nnum == 0) - snprintf(buf, buf_size, "%s", nf->nf_name); - else - snprintf(buf, buf_size, "%s%u", nf->nf_name, nnum); - - return buf; -} -EXPORT_SYMBOL(libcfs_net2str_r); - -char * -libcfs_nid2str_r(lnet_nid_t nid, char *buf, size_t buf_size) -{ - __u32 addr = LNET_NIDADDR(nid); - __u32 net = LNET_NIDNET(nid); - __u32 nnum = LNET_NETNUM(net); - __u32 lnd = LNET_NETTYP(net); - struct netstrfns *nf; - - if (nid == LNET_NID_ANY) { - strncpy(buf, "", buf_size); - buf[buf_size - 1] = '\0'; - return buf; - } - - nf = libcfs_lnd2netstrfns(lnd); - if (nf == NULL) { - snprintf(buf, buf_size, "%x@<%u:%u>", addr, lnd, nnum); - } else { - size_t addr_len; - - nf->nf_addr2str(addr, 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); - } - - return buf; -} -EXPORT_SYMBOL(libcfs_nid2str_r); - -static struct netstrfns * -libcfs_str2net_internal(const char *str, __u32 *net) -{ - struct netstrfns *nf = NULL; - int nob; - unsigned int netnum; - int i; - - for (i = 0; i < libcfs_nnetstrfns; i++) { - nf = &libcfs_netstrfns[i]; - if (nf->nf_type >= 0 && - !strncmp(str, nf->nf_name, strlen(nf->nf_name))) - break; - } - - if (i == libcfs_nnetstrfns) - return NULL; - - nob = strlen(nf->nf_name); - - if (strlen(str) == (unsigned int)nob) { - netnum = 0; - } else { - if (nf->nf_type == LOLND) /* net number not allowed */ - return NULL; - - str += nob; - i = strlen(str); - if (sscanf(str, "%u%n", &netnum, &i) < 1 || - i != (int)strlen(str)) - return NULL; - } - - *net = LNET_MKNET(nf->nf_type, netnum); - return nf; -} - -__u32 -libcfs_str2net(const char *str) -{ - __u32 net; - - if (libcfs_str2net_internal(str, &net) != NULL) - return net; - - return LNET_NIDNET(LNET_NID_ANY); -} -EXPORT_SYMBOL(libcfs_str2net); - -lnet_nid_t -libcfs_str2nid(const char *str) -{ - const char *sep = strchr(str, '@'); - struct netstrfns *nf; - __u32 net; - __u32 addr; - - if (sep != NULL) { - nf = libcfs_str2net_internal(sep + 1, &net); - if (nf == NULL) - return LNET_NID_ANY; - } else { - sep = str + strlen(str); - net = LNET_MKNET(SOCKLND, 0); - nf = libcfs_lnd2netstrfns(SOCKLND); - LASSERT(nf != NULL); - } - - if (!nf->nf_str2addr(str, (int)(sep - str), &addr)) - return LNET_NID_ANY; - - return LNET_MKNID(net, addr); -} -EXPORT_SYMBOL(libcfs_str2nid); - -char * -libcfs_id2str(lnet_process_id_t id) -{ - char *str = libcfs_next_nidstring(); - - if (id.pid == LNET_PID_ANY) { - snprintf(str, LNET_NIDSTR_SIZE, - "LNET_PID_ANY-%s", libcfs_nid2str(id.nid)); - return str; - } - - snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s", - ((id.pid & LNET_PID_USERFLAG) != 0) ? "U" : "", - (id.pid & ~LNET_PID_USERFLAG), libcfs_nid2str(id.nid)); - return str; -} -EXPORT_SYMBOL(libcfs_id2str); - -int -libcfs_str2anynid(lnet_nid_t *nidp, const char *str) -{ - if (!strcmp(str, "*")) { - *nidp = LNET_NID_ANY; - return 1; - } - - *nidp = libcfs_str2nid(str); - return *nidp != LNET_NID_ANY; -} -EXPORT_SYMBOL(libcfs_str2anynid); - -/** - * Nid range list syntax. - * \verbatim - * - * :== [ ' ' ] - * :== '@' - * :== '*' | - * | - * - * :== ... - * - * :== | - * - * :== '[' [ ',' ] ']' - * :== | - * '-' | - * '-' '/' - * :== | - * :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" | - * "vib" | "ra" | "elan" | "mx" | "ptl" - * \endverbatim - */ - -/** - * Structure to represent \ token of the syntax. - * - * One of this is created for each \ parsed. - */ -struct nidrange { - /** - * Link to list of this structures which is built on nid range - * list parsing. - */ - struct list_head nr_link; - /** - * List head for addrrange::ar_link. - */ - struct list_head nr_addrranges; - /** - * Flag indicating that *@ is found. - */ - int nr_all; - /** - * Pointer to corresponding element of libcfs_netstrfns. - */ - struct netstrfns *nr_netstrfns; - /** - * Number of network. E.g. 5 if \ is "elan5". - */ - int nr_netnum; -}; - -/** - * Structure to represent \ token of the syntax. - */ -struct addrrange { - /** - * Link to nidrange::nr_addrranges. - */ - struct list_head ar_link; - /** - * List head for cfs_expr_list::el_list. - */ - struct list_head ar_numaddr_ranges; -}; - -/** - * Nf_parse_addrlist method for networks using numeric addresses. - * - * Examples of such networks are gm and elan. - * - * \retval 0 if \a str parsed to numeric address - * \retval errno otherwise - */ -static int -libcfs_num_parse(char *str, int len, struct list_head *list) -{ - struct cfs_expr_list *el; - int rc; - - rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el); - if (rc == 0) - list_add_tail(&el->el_link, list); - - return rc; -} - -/** - * Parses \ token on the syntax. - * - * Allocates struct addrrange and links to \a nidrange via - * (nidrange::nr_addrranges) - * - * \retval 0 if \a src parses to '*' | \ | \ - * \retval -errno otherwise - */ -static int -parse_addrange(const struct cfs_lstr *src, struct nidrange *nidrange) -{ - struct addrrange *addrrange; - - if (src->ls_len == 1 && src->ls_str[0] == '*') { - nidrange->nr_all = 1; - return 0; - } - - LIBCFS_ALLOC(addrrange, sizeof(struct addrrange)); - if (addrrange == NULL) - return -ENOMEM; - list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges); - INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges); - - return nidrange->nr_netstrfns->nf_parse_addrlist(src->ls_str, - src->ls_len, - &addrrange->ar_numaddr_ranges); -} - -/** - * Finds or creates struct nidrange. - * - * Checks if \a src is a valid network name, looks for corresponding - * nidrange on the ist of nidranges (\a nidlist), creates new struct - * nidrange if it is not found. - * - * \retval pointer to struct nidrange matching network specified via \a src - * \retval NULL if \a src does not match any network - */ -static struct nidrange * -add_nidrange(const struct cfs_lstr *src, - struct list_head *nidlist) -{ - struct netstrfns *nf; - struct nidrange *nr; - int endlen; - unsigned netnum; - - if (src->ls_len >= LNET_NIDSTR_SIZE) - return NULL; - - nf = libcfs_namenum2netstrfns(src->ls_str); - if (nf == NULL) - return NULL; - endlen = src->ls_len - strlen(nf->nf_name); - if (endlen == 0) - /* network name only, e.g. "elan" or "tcp" */ - netnum = 0; - else { - /* e.g. "elan25" or "tcp23", refuse to parse if - * network name is not appended with decimal or - * hexadecimal number */ - if (!cfs_str2num_check(src->ls_str + strlen(nf->nf_name), - endlen, &netnum, 0, MAX_NUMERIC_VALUE)) - return NULL; - } - - list_for_each_entry(nr, nidlist, nr_link) { - if (nr->nr_netstrfns != nf) - continue; - if (nr->nr_netnum != netnum) - continue; - return nr; - } - - LIBCFS_ALLOC(nr, sizeof(struct nidrange)); - if (nr == NULL) - return NULL; - list_add_tail(&nr->nr_link, nidlist); - INIT_LIST_HEAD(&nr->nr_addrranges); - nr->nr_netstrfns = nf; - nr->nr_all = 0; - nr->nr_netnum = netnum; - - return nr; -} - -/** - * Parses \ token of the syntax. - * - * \retval 1 if \a src parses to \ '@' \ - * \retval 0 otherwise - */ -static int -parse_nidrange(struct cfs_lstr *src, struct list_head *nidlist) -{ - struct cfs_lstr addrrange; - struct cfs_lstr net; - struct cfs_lstr tmp; - struct nidrange *nr; - - tmp = *src; - if (cfs_gettok(src, '@', &addrrange) == 0) - goto failed; - - if (cfs_gettok(src, '@', &net) == 0 || src->ls_str != NULL) - goto failed; - - nr = add_nidrange(&net, nidlist); - if (nr == NULL) - goto failed; - - if (parse_addrange(&addrrange, nr) != 0) - goto failed; - - return 1; - failed: - CWARN("can't parse nidrange: \"%.*s\"\n", tmp.ls_len, tmp.ls_str); - return 0; -} - -/** - * Frees addrrange structures of \a list. - * - * For each struct addrrange structure found on \a list it frees - * cfs_expr_list list attached to it and frees the addrrange itself. - * - * \retval none - */ -static void -free_addrranges(struct list_head *list) -{ - while (!list_empty(list)) { - struct addrrange *ar; - - ar = list_entry(list->next, struct addrrange, ar_link); - - cfs_expr_list_free_list(&ar->ar_numaddr_ranges); - list_del(&ar->ar_link); - LIBCFS_FREE(ar, sizeof(struct addrrange)); - } -} - -/** - * Frees nidrange strutures of \a list. - * - * For each struct nidrange structure found on \a list it frees - * addrrange list attached to it and frees the nidrange itself. - * - * \retval none - */ -void -cfs_free_nidlist(struct list_head *list) -{ - struct list_head *pos, *next; - struct nidrange *nr; - - list_for_each_safe(pos, next, list) { - nr = list_entry(pos, struct nidrange, nr_link); - free_addrranges(&nr->nr_addrranges); - list_del(pos); - LIBCFS_FREE(nr, sizeof(struct nidrange)); - } -} -EXPORT_SYMBOL(cfs_free_nidlist); +EXPORT_SYMBOL(cfs_free_nidlist); /** * Parses nid range list. @@ -857,23 +349,6 @@ cfs_parse_nidlist(char *str, int len, struct list_head *nidlist) } EXPORT_SYMBOL(cfs_parse_nidlist); -/* - * Nf_match_addr method for networks using numeric addresses - * - * \retval 1 on match - * \retval 0 otherwise - */ -static int -libcfs_num_match(__u32 addr, struct list_head *numaddr) -{ - struct cfs_expr_list *el; - - LASSERT(!list_empty(numaddr)); - el = list_entry(numaddr->next, struct cfs_expr_list, el_link); - - return cfs_expr_list_match(addr, el); -} - /** * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist). * @@ -903,18 +378,158 @@ int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist) } EXPORT_SYMBOL(cfs_match_nid); +/** + * Print the network part of the nidrange \a nr into the specified \a buffer. + * + * \retval number of characters written + */ static int -libcfs_num_addr_range_print(char *buffer, int count, struct list_head *list) +cfs_print_network(char *buffer, int count, struct nidrange *nr) { - int i = 0, j = 0; - struct cfs_expr_list *el; + struct netstrfns *nf = nr->nr_netstrfns; - list_for_each_entry(el, list, el_link) { - LASSERT(j++ < 1); - i += cfs_expr_list_print(buffer + i, count - i, el); + if (nr->nr_netnum == 0) + return scnprintf(buffer, count, "@%s", nf->nf_name); + else + return scnprintf(buffer, count, "@%s%u", + nf->nf_name, nr->nr_netnum); +} + +/** + * Print a list of addrrange (\a addrranges) into the specified \a buffer. + * At max \a count characters can be printed into \a buffer. + * + * \retval number of characters written + */ +static int +cfs_print_addrranges(char *buffer, int count, struct list_head *addrranges, + struct nidrange *nr) +{ + int i = 0; + struct addrrange *ar; + struct netstrfns *nf = nr->nr_netstrfns; + + list_for_each_entry(ar, addrranges, ar_link) { + if (i != 0) + i += scnprintf(buffer + i, count - i, " "); + i += nf->nf_print_addrlist(buffer + i, count - i, + &ar->ar_numaddr_ranges); + i += cfs_print_network(buffer + i, count - i, nr); + } + return i; +} + +/** + * Print a list of nidranges (\a nidlist) into the specified \a buffer. + * At max \a count characters can be printed into \a buffer. + * Nidranges are separated by a space character. + * + * \retval number of characters written + */ +int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist) +{ + int i = 0; + struct nidrange *nr; + + if (count <= 0) + return 0; + + list_for_each_entry(nr, nidlist, nr_link) { + if (i != 0) + i += scnprintf(buffer + i, count - i, " "); + + if (nr->nr_all != 0) { + LASSERT(list_empty(&nr->nr_addrranges)); + i += scnprintf(buffer + i, count - i, "*"); + i += cfs_print_network(buffer + i, count - i, nr); + } else { + i += cfs_print_addrranges(buffer + i, count - i, + &nr->nr_addrranges, nr); + } } return i; } +EXPORT_SYMBOL(cfs_print_nidlist); + +static int +libcfs_lo_str2addr(const char *str, int nob, __u32 *addr) +{ + *addr = 0; + return 1; +} + +static void +libcfs_ip_addr2str(__u32 addr, char *str, size_t size) +{ + snprintf(str, size, "%u.%u.%u.%u", + (addr >> 24) & 0xff, (addr >> 16) & 0xff, + (addr >> 8) & 0xff, addr & 0xff); +} + +/* 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; + * fine, if it doesn't, then the scan ended at the end of the string, which is + * fine too :) */ +static int +libcfs_ip_str2addr(const char *str, int nob, __u32 *addr) +{ + unsigned int a; + unsigned int b; + unsigned int c; + unsigned int d; + int n = nob; /* XscanfX */ + + /* numeric IP? */ + if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 && + n == nob && + (a & ~0xff) == 0 && (b & ~0xff) == 0 && + (c & ~0xff) == 0 && (d & ~0xff) == 0) { + *addr = ((a<<24)|(b<<16)|(c<<8)|d); + 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) +{ + struct cfs_expr_list *el; + struct cfs_lstr src; + int rc; + int i; + + src.ls_str = str; + src.ls_len = len; + i = 0; + + while (src.ls_str != NULL) { + struct cfs_lstr res; + + if (!cfs_gettok(&src, '.', &res)) { + rc = -EINVAL; + goto out; + } + + rc = cfs_expr_list_parse(res.ls_str, res.ls_len, 0, 255, &el); + if (rc != 0) + goto out; + + list_add_tail(&el->el_link, list); + i++; + } + + if (i == 4) + return 0; + + rc = -EINVAL; +out: + cfs_expr_list_free_list(list); + + return rc; +} static int libcfs_ip_addr_range_print(char *buffer, int count, struct list_head *list) @@ -931,389 +546,405 @@ libcfs_ip_addr_range_print(char *buffer, int count, struct list_head *list) return i; } +/** + * Matches address (\a addr) against address set encoded in \a list. + * + * \retval 1 if \a addr matches + * \retval 0 otherwise + */ +int +cfs_ip_addr_match(__u32 addr, struct list_head *list) +{ + struct cfs_expr_list *el; + int i = 0; + + list_for_each_entry_reverse(el, list, el_link) { + if (!cfs_expr_list_match(addr & 0xff, el)) + return 0; + addr >>= 8; + i++; + } + + return i == 4; +} /** * Print the network part of the nidrange \a nr into the specified \a buffer. * * \retval number of characters written */ +static void +libcfs_decnum_addr2str(__u32 addr, char *str, size_t size) +{ + snprintf(str, size, "%u", addr); +} + static int -cfs_print_network(char *buffer, int count, struct nidrange *nr) +libcfs_num_str2addr(const char *str, int nob, __u32 *addr) { - struct netstrfns *nf = nr->nr_netstrfns; + int n; - if (nr->nr_netnum == 0) - return scnprintf(buffer, count, "@%s", nf->nf_name); - else - return scnprintf(buffer, count, "@%s%u", - nf->nf_name, nr->nr_netnum); + n = nob; + if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob) + return 1; + + n = nob; + if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob) + return 1; + + n = nob; + if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob) + return 1; + + return 0; +} + +/** + * Nf_parse_addrlist method for networks using numeric addresses. + * + * Examples of such networks are gm and elan. + * + * \retval 0 if \a str parsed to numeric address + * \retval errno otherwise + */ +static int +libcfs_num_parse(char *str, int len, struct list_head *list) +{ + struct cfs_expr_list *el; + int rc; + + rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el); + if (rc == 0) + list_add_tail(&el->el_link, list); + + return rc; +} + +static int +libcfs_num_addr_range_print(char *buffer, int count, struct list_head *list) +{ + int i = 0, j = 0; + struct cfs_expr_list *el; + + list_for_each_entry(el, list, el_link) { + LASSERT(j++ < 1); + i += cfs_expr_list_print(buffer + i, count - i, el); + } + return i; +} + +/* + * Nf_match_addr method for networks using numeric addresses + * + * \retval 1 on match + * \retval 0 otherwise + */ +static int +libcfs_num_match(__u32 addr, struct list_head *numaddr) +{ + struct cfs_expr_list *el; + + LASSERT(!list_empty(numaddr)); + el = list_entry(numaddr->next, struct cfs_expr_list, el_link); + + return cfs_expr_list_match(addr, el); } +static struct netstrfns libcfs_netstrfns[] = { + { .nf_type = LOLND, + .nf_name = "lo", + .nf_modname = "klolnd", + .nf_addr2str = libcfs_decnum_addr2str, + .nf_str2addr = libcfs_lo_str2addr, + .nf_parse_addrlist = libcfs_num_parse, + .nf_print_addrlist = libcfs_num_addr_range_print, + .nf_match_addr = libcfs_num_match + }, + { .nf_type = SOCKLND, + .nf_name = "tcp", + .nf_modname = "ksocklnd", + .nf_addr2str = libcfs_ip_addr2str, + .nf_str2addr = libcfs_ip_str2addr, + .nf_parse_addrlist = cfs_ip_addr_parse, + .nf_print_addrlist = libcfs_ip_addr_range_print, + .nf_match_addr = cfs_ip_addr_match + }, + { .nf_type = O2IBLND, + .nf_name = "o2ib", + .nf_modname = "ko2iblnd", + .nf_addr2str = libcfs_ip_addr2str, + .nf_str2addr = libcfs_ip_str2addr, + .nf_parse_addrlist = cfs_ip_addr_parse, + .nf_print_addrlist = libcfs_ip_addr_range_print, + .nf_match_addr = cfs_ip_addr_match + }, + { .nf_type = GNILND, + .nf_name = "gni", + .nf_modname = "kgnilnd", + .nf_addr2str = libcfs_decnum_addr2str, + .nf_str2addr = libcfs_num_str2addr, + .nf_parse_addrlist = libcfs_num_parse, + .nf_print_addrlist = libcfs_num_addr_range_print, + .nf_match_addr = libcfs_num_match + }, + { .nf_type = GNIIPLND, + .nf_name = "gip", + .nf_modname = "kgnilnd", + .nf_addr2str = libcfs_ip_addr2str, + .nf_str2addr = libcfs_ip_str2addr, + .nf_parse_addrlist = cfs_ip_addr_parse, + .nf_print_addrlist = libcfs_ip_addr_range_print, + .nf_match_addr = cfs_ip_addr_match + }, + { .nf_type = PTL4LND, + .nf_name = "ptlf", + .nf_modname = "kptl4lnd", + .nf_addr2str = libcfs_decnum_addr2str, + .nf_str2addr = libcfs_num_str2addr, + .nf_parse_addrlist = libcfs_num_parse, + .nf_print_addrlist = libcfs_num_addr_range_print, + .nf_match_addr = libcfs_num_match + }, +}; + +static const size_t libcfs_nnetstrfns = ARRAY_SIZE(libcfs_netstrfns); + +static struct netstrfns * +libcfs_lnd2netstrfns(__u32 lnd) +{ + int i; + + for (i = 0; i < libcfs_nnetstrfns; i++) + if (lnd == libcfs_netstrfns[i].nf_type) + return &libcfs_netstrfns[i]; + + return NULL; +} -/** - * Print a list of addrrange (\a addrranges) into the specified \a buffer. - * At max \a count characters can be printed into \a buffer. - * - * \retval number of characters written - */ -static int -cfs_print_addrranges(char *buffer, int count, struct list_head *addrranges, - struct nidrange *nr) +static struct netstrfns * +libcfs_namenum2netstrfns(const char *name) { - int i = 0; - struct addrrange *ar; - struct netstrfns *nf = nr->nr_netstrfns; + struct netstrfns *nf; + int i; - list_for_each_entry(ar, addrranges, ar_link) { - if (i != 0) - i += scnprintf(buffer + i, count - i, " "); - i += nf->nf_print_addrlist(buffer + i, count - i, - &ar->ar_numaddr_ranges); - i += cfs_print_network(buffer + i, count - i, nr); + for (i = 0; i < libcfs_nnetstrfns; i++) { + nf = &libcfs_netstrfns[i]; + if (!strncmp(name, nf->nf_name, strlen(nf->nf_name))) + return nf; } - return i; + return NULL; } -/** - * Print a list of nidranges (\a nidlist) into the specified \a buffer. - * At max \a count characters can be printed into \a buffer. - * Nidranges are separated by a space character. - * - * \retval number of characters written - */ -int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist) +static struct netstrfns * +libcfs_name2netstrfns(const char *name) { - int i = 0; - struct nidrange *nr; + int i; - if (count <= 0) - return 0; + for (i = 0; i < libcfs_nnetstrfns; i++) + if (!strcmp(libcfs_netstrfns[i].nf_name, name)) + return &libcfs_netstrfns[i]; - list_for_each_entry(nr, nidlist, nr_link) { - if (i != 0) - i += scnprintf(buffer + i, count - i, " "); + return NULL; +} - if (nr->nr_all != 0) { - LASSERT(list_empty(&nr->nr_addrranges)); - i += scnprintf(buffer + i, count - i, "*"); - i += cfs_print_network(buffer + i, count - i, nr); - } else { - i += cfs_print_addrranges(buffer + i, count - i, - &nr->nr_addrranges, nr); - } - } - return i; +int +libcfs_isknown_lnd(__u32 lnd) +{ + return libcfs_lnd2netstrfns(lnd) != NULL; } -EXPORT_SYMBOL(cfs_print_nidlist); +EXPORT_SYMBOL(libcfs_isknown_lnd); -/** - * Determines minimum and maximum addresses for a single - * numeric address range - * - * \param ar - * \param min_nid - * \param max_nid - */ -static void cfs_ip_ar_min_max(struct addrrange *ar, __u32 *min_nid, - __u32 *max_nid) +char * +libcfs_lnd2modname(__u32 lnd) { - struct cfs_expr_list *el; - struct cfs_range_expr *re; - __u32 tmp_ip_addr = 0; - unsigned int min_ip[4] = {0}; - unsigned int max_ip[4] = {0}; - int re_count = 0; - - list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) { - list_for_each_entry(re, &el->el_exprs, re_link) { - min_ip[re_count] = re->re_lo; - max_ip[re_count] = re->re_hi; - re_count++; - } - } + struct netstrfns *nf = libcfs_lnd2netstrfns(lnd); - tmp_ip_addr = ((min_ip[0] << 24) | (min_ip[1] << 16) | - (min_ip[2] << 8) | min_ip[3]); + return (nf == NULL) ? NULL : nf->nf_modname; +} +EXPORT_SYMBOL(libcfs_lnd2modname); - if (min_nid != NULL) - *min_nid = tmp_ip_addr; +int +libcfs_str2lnd(const char *str) +{ + struct netstrfns *nf = libcfs_name2netstrfns(str); - tmp_ip_addr = ((max_ip[0] << 24) | (max_ip[1] << 16) | - (max_ip[2] << 8) | max_ip[3]); + if (nf != NULL) + return nf->nf_type; - if (max_nid != NULL) - *max_nid = tmp_ip_addr; + return -ENXIO; } +EXPORT_SYMBOL(libcfs_str2lnd); -/** - * Determines minimum and maximum addresses for a single - * numeric address range - * - * \param ar - * \param min_nid - * \param max_nid - */ -static void cfs_num_ar_min_max(struct addrrange *ar, __u32 *min_nid, - __u32 *max_nid) +char * +libcfs_lnd2str_r(__u32 lnd, char *buf, size_t buf_size) { - struct cfs_expr_list *el; - struct cfs_range_expr *re; - unsigned int min_addr = 0; - unsigned int max_addr = 0; - - list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) { - list_for_each_entry(re, &el->el_exprs, re_link) { - if (re->re_lo < min_addr || min_addr == 0) - min_addr = re->re_lo; - if (re->re_hi > max_addr) - max_addr = re->re_hi; - } - } + struct netstrfns *nf; + + nf = libcfs_lnd2netstrfns(lnd); + if (nf == NULL) + snprintf(buf, buf_size, "?%u?", lnd); + else + snprintf(buf, buf_size, "%s", nf->nf_name); - if (min_nid != NULL) - *min_nid = min_addr; - if (max_nid != NULL) - *max_nid = max_addr; + return buf; } +EXPORT_SYMBOL(libcfs_lnd2str_r); -/** - * Determines whether an expression list in an nidrange contains exactly - * one contiguous address range. Calls the correct netstrfns for the LND - * - * \param *nidlist - * - * \retval true if contiguous - * \retval false if not contiguous - */ -bool cfs_nidrange_is_contiguous(struct list_head *nidlist) +char * +libcfs_net2str_r(__u32 net, char *buf, size_t buf_size) { - struct nidrange *nr; - struct netstrfns *nf = NULL; - char *lndname = NULL; - int netnum = -1; - - list_for_each_entry(nr, nidlist, nr_link) { - nf = nr->nr_netstrfns; - if (lndname == NULL) - lndname = nf->nf_name; - if (netnum == -1) - netnum = nr->nr_netnum; - - if (strcmp(lndname, nf->nf_name) != 0 || - netnum != nr->nr_netnum) - return false; - } + __u32 nnum = LNET_NETNUM(net); + __u32 lnd = LNET_NETTYP(net); + struct netstrfns *nf; + nf = libcfs_lnd2netstrfns(lnd); if (nf == NULL) - return false; - - if (!nf->nf_is_contiguous(nidlist)) - return false; + snprintf(buf, buf_size, "<%u:%u>", lnd, nnum); + else if (nnum == 0) + snprintf(buf, buf_size, "%s", nf->nf_name); + else + snprintf(buf, buf_size, "%s%u", nf->nf_name, nnum); - return true; + return buf; } -EXPORT_SYMBOL(cfs_nidrange_is_contiguous); +EXPORT_SYMBOL(libcfs_net2str_r); -/** - * Determines whether an expression list in an num nidrange contains exactly - * one contiguous address range. - * - * \param *nidlist - * - * \retval true if contiguous - * \retval false if not contiguous - */ -static bool cfs_num_is_contiguous(struct list_head *nidlist) +char * +libcfs_nid2str_r(lnet_nid_t nid, char *buf, size_t buf_size) { - struct nidrange *nr; - struct addrrange *ar; - struct cfs_expr_list *el; - struct cfs_range_expr *re; - int last_hi = 0; - __u32 last_end_nid = 0; - __u32 current_start_nid = 0; - __u32 current_end_nid = 0; + __u32 addr = LNET_NIDADDR(nid); + __u32 net = LNET_NIDNET(nid); + __u32 nnum = LNET_NETNUM(net); + __u32 lnd = LNET_NETTYP(net); + struct netstrfns *nf; - list_for_each_entry(nr, nidlist, nr_link) { - list_for_each_entry(ar, &nr->nr_addrranges, ar_link) { - cfs_num_ar_min_max(ar, ¤t_start_nid, - ¤t_end_nid); - if (last_end_nid != 0 && - (current_start_nid - last_end_nid != 1)) - return false; - last_end_nid = current_end_nid; - list_for_each_entry(el, &ar->ar_numaddr_ranges, - el_link) { - list_for_each_entry(re, &el->el_exprs, - re_link) { - if (re->re_stride > 1) - return false; - else if (last_hi != 0 && - re->re_hi - last_hi != 1) - return false; - last_hi = re->re_hi; - } - } - } + if (nid == LNET_NID_ANY) { + strncpy(buf, "", buf_size); + buf[buf_size - 1] = '\0'; + return buf; + } + + nf = libcfs_lnd2netstrfns(lnd); + if (nf == NULL) { + snprintf(buf, buf_size, "%x@<%u:%u>", addr, lnd, nnum); + } else { + size_t addr_len; + + nf->nf_addr2str(addr, 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); } - return true; + return buf; } +EXPORT_SYMBOL(libcfs_nid2str_r); -/** - * Determines whether an expression list in an ip nidrange contains exactly - * one contiguous address range. - * - * \param *nidlist - * - * \retval true if contiguous - * \retval false if not contiguous - */ -static bool cfs_ip_is_contiguous(struct list_head *nidlist) +static struct netstrfns * +libcfs_str2net_internal(const char *str, __u32 *net) { - struct nidrange *nr; - struct addrrange *ar; - struct cfs_expr_list *el; - struct cfs_range_expr *re; - int expr_count; - int last_hi = 255; - int last_diff = 0; - __u32 last_end_nid = 0; - __u32 current_start_nid = 0; - __u32 current_end_nid = 0; + struct netstrfns *nf = NULL; + int nob; + unsigned int netnum; + int i; - list_for_each_entry(nr, nidlist, nr_link) { - list_for_each_entry(ar, &nr->nr_addrranges, ar_link) { - last_hi = 255; - last_diff = 0; - cfs_ip_ar_min_max(ar, ¤t_start_nid, - ¤t_end_nid); - if (last_end_nid != 0 && - (current_start_nid - last_end_nid != 1)) - return false; - last_end_nid = current_end_nid; - list_for_each_entry(el, - &ar->ar_numaddr_ranges, - el_link) { - expr_count = 0; - list_for_each_entry(re, &el->el_exprs, - re_link) { - expr_count++; - if (re->re_stride > 1 || - (last_diff > 0 && last_hi != 255) || - (last_diff > 0 && last_hi == 255 && - re->re_lo > 0)) - return false; - last_hi = re->re_hi; - last_diff = re->re_hi - re->re_lo; - } - } - } + for (i = 0; i < libcfs_nnetstrfns; i++) { + nf = &libcfs_netstrfns[i]; + if (!strncmp(str, nf->nf_name, strlen(nf->nf_name))) + break; + } + + if (i == libcfs_nnetstrfns) + return NULL; + + nob = strlen(nf->nf_name); + + if (strlen(str) == (unsigned int)nob) { + netnum = 0; + } else { + if (nf->nf_type == LOLND) /* net number not allowed */ + return NULL; + + str += nob; + i = strlen(str); + if (sscanf(str, "%u%n", &netnum, &i) < 1 || + i != (int)strlen(str)) + return NULL; } - return true; + *net = LNET_MKNET(nf->nf_type, netnum); + return nf; } -/** - * Takes a linked list of nidrange expressions, determines the minimum - * and maximum nid and creates appropriate nid structures - * - * \param *nidlist - * \param *min_nid - * \param *max_nid - */ -void cfs_nidrange_find_min_max(struct list_head *nidlist, char *min_nid, - char *max_nid, size_t nidstr_length) +__u32 +libcfs_str2net(const char *str) { - struct nidrange *nr; - struct netstrfns *nf = NULL; - int netnum = -1; - __u32 min_addr; - __u32 max_addr; - char *lndname = NULL; - char min_addr_str[IPSTRING_LENGTH]; - char max_addr_str[IPSTRING_LENGTH]; + __u32 net; - list_for_each_entry(nr, nidlist, nr_link) { - nf = nr->nr_netstrfns; - lndname = nf->nf_name; - if (netnum == -1) - netnum = nr->nr_netnum; + if (libcfs_str2net_internal(str, &net) != NULL) + return net; + + return LNET_NIDNET(LNET_NID_ANY); +} +EXPORT_SYMBOL(libcfs_str2net); + +lnet_nid_t +libcfs_str2nid(const char *str) +{ + const char *sep = strchr(str, '@'); + struct netstrfns *nf; + __u32 net; + __u32 addr; - nf->nf_min_max(nidlist, &min_addr, &max_addr); + if (sep != NULL) { + nf = libcfs_str2net_internal(sep + 1, &net); + if (nf == NULL) + return LNET_NID_ANY; + } else { + sep = str + strlen(str); + net = LNET_MKNET(SOCKLND, 0); + nf = libcfs_lnd2netstrfns(SOCKLND); + LASSERT(nf != NULL); } - nf->nf_addr2str(min_addr, min_addr_str, sizeof(min_addr_str)); - nf->nf_addr2str(max_addr, max_addr_str, sizeof(max_addr_str)); - snprintf(min_nid, nidstr_length, "%s@%s%d", min_addr_str, lndname, - netnum); - snprintf(max_nid, nidstr_length, "%s@%s%d", max_addr_str, lndname, - netnum); + if (!nf->nf_str2addr(str, (int)(sep - str), &addr)) + return LNET_NID_ANY; + + return LNET_MKNID(net, addr); } -EXPORT_SYMBOL(cfs_nidrange_find_min_max); +EXPORT_SYMBOL(libcfs_str2nid); -/** - * Determines the min and max NID values for num LNDs - * - * \param *nidlist - * \param *min_nid - * \param *max_nid - */ -static void cfs_num_min_max(struct list_head *nidlist, __u32 *min_nid, - __u32 *max_nid) +char * +libcfs_id2str(struct lnet_process_id id) { - struct nidrange *nr; - struct addrrange *ar; - unsigned int tmp_min_addr = 0; - unsigned int tmp_max_addr = 0; - unsigned int min_addr = 0; - unsigned int max_addr = 0; + char *str = libcfs_next_nidstring(); - list_for_each_entry(nr, nidlist, nr_link) { - list_for_each_entry(ar, &nr->nr_addrranges, ar_link) { - cfs_num_ar_min_max(ar, &tmp_min_addr, - &tmp_max_addr); - if (tmp_min_addr < min_addr || min_addr == 0) - min_addr = tmp_min_addr; - if (tmp_max_addr > max_addr) - max_addr = tmp_min_addr; - } + if (id.pid == LNET_PID_ANY) { + snprintf(str, LNET_NIDSTR_SIZE, + "LNET_PID_ANY-%s", libcfs_nid2str(id.nid)); + return str; } - *max_nid = max_addr; - *min_nid = min_addr; + + snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s", + ((id.pid & LNET_PID_USERFLAG) != 0) ? "U" : "", + (id.pid & ~LNET_PID_USERFLAG), libcfs_nid2str(id.nid)); + return str; } +EXPORT_SYMBOL(libcfs_id2str); -/** - * Takes an nidlist and determines the minimum and maximum - * ip addresses. - * - * \param *nidlist - * \param *min_nid - * \param *max_nid - */ -static void cfs_ip_min_max(struct list_head *nidlist, __u32 *min_nid, - __u32 *max_nid) +int +libcfs_str2anynid(lnet_nid_t *nidp, const char *str) { - struct nidrange *nr; - struct addrrange *ar; - __u32 tmp_min_ip_addr = 0; - __u32 tmp_max_ip_addr = 0; - __u32 min_ip_addr = 0; - __u32 max_ip_addr = 0; - - list_for_each_entry(nr, nidlist, nr_link) { - list_for_each_entry(ar, &nr->nr_addrranges, ar_link) { - cfs_ip_ar_min_max(ar, &tmp_min_ip_addr, - &tmp_max_ip_addr); - if (tmp_min_ip_addr < min_ip_addr || min_ip_addr == 0) - min_ip_addr = tmp_min_ip_addr; - if (tmp_max_ip_addr > max_ip_addr) - max_ip_addr = tmp_max_ip_addr; - } + if (!strcmp(str, "*")) { + *nidp = LNET_NID_ANY; + return 1; } - if (min_nid != NULL) - *min_nid = min_ip_addr; - if (max_nid != NULL) - *max_nid = max_ip_addr; + *nidp = libcfs_str2nid(str); + return *nidp != LNET_NID_ANY; } +EXPORT_SYMBOL(libcfs_str2anynid);