staging: lustre: move nidstring handling to LNet layer
authorJames Simmons <jsimmons@infradead.org>
Thu, 22 Oct 2015 01:52:40 +0000 (21:52 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 25 Oct 2015 01:52:21 +0000 (18:52 -0700)
Moved the source file nidstring.c from libcfs to lnet
since that is the only place it is used. With the
move of nidstring to lnet some functions in libcfs
need to be exported. In later patches those functions
that are only used by LNet also will be moved to the
LNet layer. Also add in missing MAX_NUMERIC_VALUE
defination.

Signed-off-by: James Simmons <jsimmons@infradead.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/lustre/lnet/lnet/Makefile
drivers/staging/lustre/lnet/lnet/nidstrings.c [new file with mode: 0644]
drivers/staging/lustre/lustre/libcfs/Makefile
drivers/staging/lustre/lustre/libcfs/libcfs_string.c
drivers/staging/lustre/lustre/libcfs/nidstrings.c [deleted file]

index 52492fb10f855866172db9ec2a20b01ba830c054..e276fe2bf8f3db68d06ff9ac05d8ffd517d69424 100644 (file)
@@ -1,6 +1,6 @@
 obj-$(CONFIG_LNET) += lnet.o
 
-lnet-y := api-ni.o config.o                                    \
+lnet-y := api-ni.o config.o nidstrings.o                       \
          lib-me.o lib-msg.o lib-eq.o lib-md.o lib-ptl.o        \
          lib-socket.o lib-move.o module.o lo.o                 \
          router.o router_proc.o acceptor.o peer.o
diff --git a/drivers/staging/lustre/lnet/lnet/nidstrings.c b/drivers/staging/lustre/lnet/lnet/nidstrings.c
new file mode 100644 (file)
index 0000000..81ec3a8
--- /dev/null
@@ -0,0 +1,963 @@
+/*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * 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.
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 2011, 2012, Intel Corporation.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ * Lustre is a trademark of Sun Microsystems, Inc.
+ *
+ * lnet/lnet/nidstrings.c
+ *
+ * Author: Phil Schwan <phil@clusterfs.com>
+ */
+
+#define DEBUG_SUBSYSTEM S_LNET
+
+#include "../../include/linux/libcfs/libcfs.h"
+#include "../../include/linux/lnet/lnet.h"
+
+/* max value for numeric network address */
+#define MAX_NUMERIC_VALUE 0xffffffff
+
+/* CAVEAT VENDITOR! Keep the canonical string representation of nets/nids
+ * consistent in all conversion functions.  Some code fragments are copied
+ * around for the sake of clarity...
+ */
+
+/* CAVEAT EMPTOR! Racey temporary buffer allocation!
+ * Choose the number of nidstrings to support the MAXIMUM expected number of
+ * concurrent users.  If there are more, the returned string will be volatile.
+ * NB this number must allow for a process to be descheduled for a timeslice
+ * between getting its string and using it.
+ */
+
+static char      libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE];
+static int       libcfs_nidstring_idx;
+
+static spinlock_t libcfs_nidstring_lock;
+
+void libcfs_init_nidstrings(void)
+{
+       spin_lock_init(&libcfs_nidstring_lock);
+}
+EXPORT_SYMBOL(libcfs_init_nidstrings);
+
+char *
+libcfs_next_nidstring(void)
+{
+       char *str;
+       unsigned long flags;
+
+       spin_lock_irqsave(&libcfs_nidstring_lock, flags);
+
+       str = libcfs_nidstrings[libcfs_nidstring_idx++];
+       if (libcfs_nidstring_idx == ARRAY_SIZE(libcfs_nidstrings))
+               libcfs_nidstring_idx = 0;
+
+       spin_unlock_irqrestore(&libcfs_nidstring_lock, flags);
+       return str;
+}
+EXPORT_SYMBOL(libcfs_next_nidstring);
+
+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)
+{
+       snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u",
+                (addr >> 24) & 0xff, (addr >> 16) & 0xff,
+                (addr >> 8) & 0xff, addr & 0xff);
+}
+
+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;
+}
+
+static int
+libcfs_ip_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++ < 4);
+               if (i != 0)
+                       i += scnprintf(buffer + i, count - i, ".");
+               i += cfs_expr_list_print(buffer + i, count - i, el);
+       }
+       return i;
+}
+
+static void libcfs_decnum_addr2str(__u32 addr, char *str)
+{
+       snprintf(str, LNET_NIDSTR_SIZE, "%u", addr);
+}
+
+static void libcfs_hexnum_addr2str(__u32 addr, char *str)
+{
+       snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr);
+}
+
+static int libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
+{
+       int     n;
+
+       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);
+}
+
+struct netstrfns {
+       int       nf_type;
+       char    *nf_name;
+       char    *nf_modname;
+       void       (*nf_addr2str)(__u32 addr, char *str);
+       int     (*nf_str2addr)(const char *str, int nob, __u32 *addr);
+       int     (*nf_parse_addrlist)(char *str, int len,
+                                       struct list_head *list);
+       int     (*nf_print_addrlist)(char *buffer, int count,
+                                    struct list_head *list);
+       int     (*nf_match_addr)(__u32 addr, struct list_head *list);
+};
+
+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_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      */  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_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_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_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_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_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_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_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_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_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},
+       /* placeholder for net0 alias.  It MUST BE THE LAST ENTRY */
+       {/* .nf_type      */  -1},
+};
+
+static const int libcfs_nnetstrfns = ARRAY_SIZE(libcfs_netstrfns);
+
+/* 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 struct netstrfns *
+libcfs_lnd2netstrfns(int lnd)
+{
+       int    i;
+
+       if (lnd >= 0)
+               for (i = 0; i < libcfs_nnetstrfns; i++)
+                       if (lnd == libcfs_netstrfns[i].nf_type)
+                               return &libcfs_netstrfns[i];
+
+       return NULL;
+}
+
+static struct netstrfns *
+libcfs_namenum2netstrfns(const char *name)
+{
+       struct netstrfns *nf;
+       int            i;
+
+       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;
+       }
+       return NULL;
+}
+
+static struct netstrfns *
+libcfs_name2netstrfns(const char *name)
+{
+       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];
+
+       return NULL;
+}
+
+int
+libcfs_isknown_lnd(int type)
+{
+       return libcfs_lnd2netstrfns(type) != NULL;
+}
+EXPORT_SYMBOL(libcfs_isknown_lnd);
+
+char *
+libcfs_lnd2modname(int lnd)
+{
+       struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
+
+       return (nf == NULL) ? NULL : nf->nf_modname;
+}
+EXPORT_SYMBOL(libcfs_lnd2modname);
+
+char *
+libcfs_lnd2str(int lnd)
+{
+       char       *str;
+       struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
+
+       if (nf != NULL)
+               return nf->nf_name;
+
+       str = libcfs_next_nidstring();
+       snprintf(str, LNET_NIDSTR_SIZE, "?%d?", lnd);
+       return str;
+}
+EXPORT_SYMBOL(libcfs_lnd2str);
+
+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_net2str(__u32 net)
+{
+       int            lnd = LNET_NETTYP(net);
+       int            num = LNET_NETNUM(net);
+       struct netstrfns *nf  = libcfs_lnd2netstrfns(lnd);
+       char         *str = libcfs_next_nidstring();
+
+       if (nf == NULL)
+               snprintf(str, LNET_NIDSTR_SIZE, "<%d:%d>", lnd, num);
+       else if (num == 0)
+               snprintf(str, LNET_NIDSTR_SIZE, "%s", nf->nf_name);
+       else
+               snprintf(str, LNET_NIDSTR_SIZE, "%s%d", nf->nf_name, num);
+
+       return str;
+}
+EXPORT_SYMBOL(libcfs_net2str);
+
+char *
+libcfs_nid2str(lnet_nid_t nid)
+{
+       __u32        addr = LNET_NIDADDR(nid);
+       __u32        net = LNET_NIDNET(nid);
+       int            lnd = LNET_NETTYP(net);
+       int            nnum = LNET_NETNUM(net);
+       struct netstrfns *nf;
+       char         *str;
+       int            nob;
+
+       if (nid == LNET_NID_ANY)
+               return "<?>";
+
+       nf = libcfs_lnd2netstrfns(lnd);
+       str = libcfs_next_nidstring();
+
+       if (nf == NULL)
+               snprintf(str, LNET_NIDSTR_SIZE, "%x@<%d:%d>", addr, lnd, nnum);
+       else {
+               nf->nf_addr2str(addr, str);
+               nob = strlen(str);
+               if (nnum == 0)
+                       snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s",
+                                nf->nf_name);
+               else
+                       snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s%d",
+                                nf->nf_name, nnum);
+       }
+
+       return str;
+}
+EXPORT_SYMBOL(libcfs_nid2str);
+
+static struct netstrfns *
+libcfs_str2net_internal(const char *str, __u32 *net)
+{
+       struct netstrfns *uninitialized_var(nf);
+       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
+ *
+ * <nidlist>    :== <nidrange> [ ' ' <nidrange> ]
+ * <nidrange>  :== <addrrange> '@' <net>
+ * <addrrange>       :== '*' |
+ *                    <ipaddr_range> |
+ *                      <cfs_expr_list>
+ * <ipaddr_range>    :== <cfs_expr_list>.<cfs_expr_list>.<cfs_expr_list>.
+ *                      <cfs_expr_list>
+ * <cfs_expr_list>   :== <number> |
+ *                    <expr_list>
+ * <expr_list>       :== '[' <range_expr> [ ',' <range_expr>] ']'
+ * <range_expr>      :== <number> |
+ *                    <number> '-' <number> |
+ *                    <number> '-' <number> '/' <number>
+ * <net>            :== <netname> | <netname><number>
+ * <netname>    :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" |
+ *                    "vib" | "ra" | "elan" | "mx" | "ptl"
+ * \endverbatim
+ */
+
+/**
+ * Structure to represent \<nidrange\> token of the syntax.
+ *
+ * One of this is created for each \<net\> 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 *@<net> is found.
+        */
+       int nr_all;
+       /**
+        * Pointer to corresponding element of libcfs_netstrfns.
+        */
+       struct netstrfns *nr_netstrfns;
+       /**
+        * Number of network. E.g. 5 if \<net\> is "elan5".
+        */
+       int nr_netnum;
+};
+
+/**
+ * Structure to represent \<addrrange\> 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 \<addrrange\> token on the syntax.
+ *
+ * Allocates struct addrrange and links to \a nidrange via
+ * (nidrange::nr_addrranges)
+ *
+ * \retval 0 if \a src parses to '*' | \<ipaddr_range\> | \<cfs_expr_list\>
+ * \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 \<nidrange\> token of the syntax.
+ *
+ * \retval 1 if \a src parses to \<addrrange\> '@' \<net\>
+ * \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);
+
+/**
+ * Parses nid range list.
+ *
+ * Parses with rigorous syntax and overflow checking \a str into
+ * \<nidrange\> [ ' ' \<nidrange\> ], compiles \a str into set of
+ * structures and links that structure to \a nidlist. The resulting
+ * list can be used to match a NID againts set of NIDS defined by \a
+ * str.
+ * \see cfs_match_nid
+ *
+ * \retval 1 on success
+ * \retval 0 otherwise
+ */
+int
+cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
+{
+       struct cfs_lstr src;
+       struct cfs_lstr res;
+       int rc;
+
+       src.ls_str = str;
+       src.ls_len = len;
+       INIT_LIST_HEAD(nidlist);
+       while (src.ls_str) {
+               rc = cfs_gettok(&src, ' ', &res);
+               if (rc == 0) {
+                       cfs_free_nidlist(nidlist);
+                       return 0;
+               }
+               rc = parse_nidrange(&res, nidlist);
+               if (rc == 0) {
+                       cfs_free_nidlist(nidlist);
+                       return 0;
+               }
+       }
+       return 1;
+}
+EXPORT_SYMBOL(cfs_parse_nidlist);
+
+/**
+ * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
+ *
+ * \see cfs_parse_nidlist()
+ *
+ * \retval 1 on match
+ * \retval 0  otherwises
+ */
+int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist)
+{
+       struct nidrange *nr;
+       struct addrrange *ar;
+
+       list_for_each_entry(nr, nidlist, nr_link) {
+               if (nr->nr_netstrfns->nf_type != LNET_NETTYP(LNET_NIDNET(nid)))
+                       continue;
+               if (nr->nr_netnum != LNET_NETNUM(LNET_NIDNET(nid)))
+                       continue;
+               if (nr->nr_all)
+                       return 1;
+               list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
+                       if (nr->nr_netstrfns->nf_match_addr(LNET_NIDADDR(nid),
+                                                      &ar->ar_numaddr_ranges))
+                               return 1;
+       }
+       return 0;
+}
+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
+cfs_print_network(char *buffer, int count, struct nidrange *nr)
+{
+       struct netstrfns *nf = nr->nr_netstrfns;
+
+       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);
index ec98f44a10dd882d97183342206e100fac131ac8..03d3f3d7b1f815232d6284735cc3ca3561ff00d5 100644 (file)
@@ -10,7 +10,7 @@ libcfs-linux-objs += linux-mem.o
 
 libcfs-linux-objs := $(addprefix linux/,$(libcfs-linux-objs))
 
-libcfs-all-objs := debug.o fail.o nidstrings.o module.o tracefile.o \
+libcfs-all-objs := debug.o fail.o module.o tracefile.o \
                   libcfs_string.o hash.o kernel_user_comm.o \
                   prng.o workitem.o libcfs_cpu.o \
                   libcfs_mem.o libcfs_lock.o
index bbfef983e1308532b599c4559542e02d9a04ae9b..896185f54c4fded303b88211ed2913fd06a81084 100644 (file)
@@ -214,6 +214,7 @@ cfs_gettok(struct cfs_lstr *next, char delim, struct cfs_lstr *res)
        res->ls_len = end - res->ls_str + 1;
        return 1;
 }
+EXPORT_SYMBOL(cfs_gettok);
 
 /**
  * Converts string to integer.
@@ -242,6 +243,7 @@ cfs_str2num_check(char *str, int nob, unsigned *num,
 
        return (*num >= min && *num <= max);
 }
+EXPORT_SYMBOL(cfs_str2num_check);
 
 /**
  * Parses \<range_expr\> token of the syntax. If \a bracketed is false,
@@ -406,6 +408,7 @@ cfs_expr_list_match(__u32 value, struct cfs_expr_list *expr_list)
 
        return 0;
 }
+EXPORT_SYMBOL(cfs_expr_list_match);
 
 /**
  * Convert express list (\a expr_list) to an array of all matched values
@@ -558,6 +561,7 @@ cfs_expr_list_free_list(struct list_head *list)
                cfs_expr_list_free(el);
        }
 }
+EXPORT_SYMBOL(cfs_expr_list_free_list);
 
 int
 cfs_ip_addr_parse(char *str, int len, struct list_head *list)
diff --git a/drivers/staging/lustre/lustre/libcfs/nidstrings.c b/drivers/staging/lustre/lustre/libcfs/nidstrings.c
deleted file mode 100644 (file)
index a54594a..0000000
+++ /dev/null
@@ -1,958 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * 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.
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- *
- * Copyright (c) 2011, 2012, Intel Corporation.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- *
- * libcfs/libcfs/nidstrings.c
- *
- * Author: Phil Schwan <phil@clusterfs.com>
- */
-
-#define DEBUG_SUBSYSTEM S_LNET
-
-#include "../../include/linux/libcfs/libcfs.h"
-#include "../../include/linux/lnet/lnet.h"
-
-/* CAVEAT VENDITOR! Keep the canonical string representation of nets/nids
- * consistent in all conversion functions.  Some code fragments are copied
- * around for the sake of clarity...
- */
-
-/* CAVEAT EMPTOR! Racey temporary buffer allocation!
- * Choose the number of nidstrings to support the MAXIMUM expected number of
- * concurrent users.  If there are more, the returned string will be volatile.
- * NB this number must allow for a process to be descheduled for a timeslice
- * between getting its string and using it.
- */
-
-static char      libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE];
-static int       libcfs_nidstring_idx;
-
-static spinlock_t libcfs_nidstring_lock;
-
-void libcfs_init_nidstrings(void)
-{
-       spin_lock_init(&libcfs_nidstring_lock);
-}
-
-static char *
-libcfs_next_nidstring(void)
-{
-       char      *str;
-       unsigned long  flags;
-
-       spin_lock_irqsave(&libcfs_nidstring_lock, flags);
-
-       str = libcfs_nidstrings[libcfs_nidstring_idx++];
-       if (libcfs_nidstring_idx == ARRAY_SIZE(libcfs_nidstrings))
-               libcfs_nidstring_idx = 0;
-
-       spin_unlock_irqrestore(&libcfs_nidstring_lock, flags);
-       return str;
-}
-
-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)
-{
-       snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u",
-                (addr >> 24) & 0xff, (addr >> 16) & 0xff,
-                (addr >> 8) & 0xff, addr & 0xff);
-}
-
-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;
-}
-
-static int
-libcfs_ip_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++ < 4);
-               if (i != 0)
-                       i += scnprintf(buffer + i, count - i, ".");
-               i += cfs_expr_list_print(buffer + i, count - i, el);
-       }
-       return i;
-}
-
-static void libcfs_decnum_addr2str(__u32 addr, char *str)
-{
-       snprintf(str, LNET_NIDSTR_SIZE, "%u", addr);
-}
-
-static void libcfs_hexnum_addr2str(__u32 addr, char *str)
-{
-       snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr);
-}
-
-static int libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
-{
-       int     n;
-
-       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);
-}
-
-struct netstrfns {
-       int       nf_type;
-       char    *nf_name;
-       char    *nf_modname;
-       void       (*nf_addr2str)(__u32 addr, char *str);
-       int     (*nf_str2addr)(const char *str, int nob, __u32 *addr);
-       int     (*nf_parse_addrlist)(char *str, int len,
-                                       struct list_head *list);
-       int     (*nf_print_addrlist)(char *buffer, int count,
-                                    struct list_head *list);
-       int     (*nf_match_addr)(__u32 addr, struct list_head *list);
-};
-
-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_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      */  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_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_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_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_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_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_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_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_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_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},
-       /* placeholder for net0 alias.  It MUST BE THE LAST ENTRY */
-       {/* .nf_type      */  -1},
-};
-
-static const int libcfs_nnetstrfns = ARRAY_SIZE(libcfs_netstrfns);
-
-/* 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 struct netstrfns *
-libcfs_lnd2netstrfns(int lnd)
-{
-       int    i;
-
-       if (lnd >= 0)
-               for (i = 0; i < libcfs_nnetstrfns; i++)
-                       if (lnd == libcfs_netstrfns[i].nf_type)
-                               return &libcfs_netstrfns[i];
-
-       return NULL;
-}
-
-static struct netstrfns *
-libcfs_namenum2netstrfns(const char *name)
-{
-       struct netstrfns *nf;
-       int            i;
-
-       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;
-       }
-       return NULL;
-}
-
-static struct netstrfns *
-libcfs_name2netstrfns(const char *name)
-{
-       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];
-
-       return NULL;
-}
-
-int
-libcfs_isknown_lnd(int type)
-{
-       return libcfs_lnd2netstrfns(type) != NULL;
-}
-EXPORT_SYMBOL(libcfs_isknown_lnd);
-
-char *
-libcfs_lnd2modname(int lnd)
-{
-       struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
-
-       return (nf == NULL) ? NULL : nf->nf_modname;
-}
-EXPORT_SYMBOL(libcfs_lnd2modname);
-
-char *
-libcfs_lnd2str(int lnd)
-{
-       char       *str;
-       struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
-
-       if (nf != NULL)
-               return nf->nf_name;
-
-       str = libcfs_next_nidstring();
-       snprintf(str, LNET_NIDSTR_SIZE, "?%d?", lnd);
-       return str;
-}
-EXPORT_SYMBOL(libcfs_lnd2str);
-
-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_net2str(__u32 net)
-{
-       int            lnd = LNET_NETTYP(net);
-       int            num = LNET_NETNUM(net);
-       struct netstrfns *nf  = libcfs_lnd2netstrfns(lnd);
-       char         *str = libcfs_next_nidstring();
-
-       if (nf == NULL)
-               snprintf(str, LNET_NIDSTR_SIZE, "<%d:%d>", lnd, num);
-       else if (num == 0)
-               snprintf(str, LNET_NIDSTR_SIZE, "%s", nf->nf_name);
-       else
-               snprintf(str, LNET_NIDSTR_SIZE, "%s%d", nf->nf_name, num);
-
-       return str;
-}
-EXPORT_SYMBOL(libcfs_net2str);
-
-char *
-libcfs_nid2str(lnet_nid_t nid)
-{
-       __u32        addr = LNET_NIDADDR(nid);
-       __u32        net = LNET_NIDNET(nid);
-       int            lnd = LNET_NETTYP(net);
-       int            nnum = LNET_NETNUM(net);
-       struct netstrfns *nf;
-       char         *str;
-       int            nob;
-
-       if (nid == LNET_NID_ANY)
-               return "<?>";
-
-       nf = libcfs_lnd2netstrfns(lnd);
-       str = libcfs_next_nidstring();
-
-       if (nf == NULL)
-               snprintf(str, LNET_NIDSTR_SIZE, "%x@<%d:%d>", addr, lnd, nnum);
-       else {
-               nf->nf_addr2str(addr, str);
-               nob = strlen(str);
-               if (nnum == 0)
-                       snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s",
-                                nf->nf_name);
-               else
-                       snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s%d",
-                                nf->nf_name, nnum);
-       }
-
-       return str;
-}
-EXPORT_SYMBOL(libcfs_nid2str);
-
-static struct netstrfns *
-libcfs_str2net_internal(const char *str, __u32 *net)
-{
-       struct netstrfns *uninitialized_var(nf);
-       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
- *
- * <nidlist>    :== <nidrange> [ ' ' <nidrange> ]
- * <nidrange>  :== <addrrange> '@' <net>
- * <addrrange>       :== '*' |
- *                    <ipaddr_range> |
- *                      <cfs_expr_list>
- * <ipaddr_range>    :== <cfs_expr_list>.<cfs_expr_list>.<cfs_expr_list>.
- *                      <cfs_expr_list>
- * <cfs_expr_list>   :== <number> |
- *                    <expr_list>
- * <expr_list>       :== '[' <range_expr> [ ',' <range_expr>] ']'
- * <range_expr>      :== <number> |
- *                    <number> '-' <number> |
- *                    <number> '-' <number> '/' <number>
- * <net>            :== <netname> | <netname><number>
- * <netname>    :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" |
- *                    "vib" | "ra" | "elan" | "mx" | "ptl"
- * \endverbatim
- */
-
-/**
- * Structure to represent \<nidrange\> token of the syntax.
- *
- * One of this is created for each \<net\> 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 *@<net> is found.
-        */
-       int nr_all;
-       /**
-        * Pointer to corresponding element of libcfs_netstrfns.
-        */
-       struct netstrfns *nr_netstrfns;
-       /**
-        * Number of network. E.g. 5 if \<net\> is "elan5".
-        */
-       int nr_netnum;
-};
-
-/**
- * Structure to represent \<addrrange\> 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 \<addrrange\> token on the syntax.
- *
- * Allocates struct addrrange and links to \a nidrange via
- * (nidrange::nr_addrranges)
- *
- * \retval 0 if \a src parses to '*' | \<ipaddr_range\> | \<cfs_expr_list\>
- * \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 \<nidrange\> token of the syntax.
- *
- * \retval 1 if \a src parses to \<addrrange\> '@' \<net\>
- * \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);
-
-/**
- * Parses nid range list.
- *
- * Parses with rigorous syntax and overflow checking \a str into
- * \<nidrange\> [ ' ' \<nidrange\> ], compiles \a str into set of
- * structures and links that structure to \a nidlist. The resulting
- * list can be used to match a NID againts set of NIDS defined by \a
- * str.
- * \see cfs_match_nid
- *
- * \retval 1 on success
- * \retval 0 otherwise
- */
-int
-cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
-{
-       struct cfs_lstr src;
-       struct cfs_lstr res;
-       int rc;
-
-       src.ls_str = str;
-       src.ls_len = len;
-       INIT_LIST_HEAD(nidlist);
-       while (src.ls_str) {
-               rc = cfs_gettok(&src, ' ', &res);
-               if (rc == 0) {
-                       cfs_free_nidlist(nidlist);
-                       return 0;
-               }
-               rc = parse_nidrange(&res, nidlist);
-               if (rc == 0) {
-                       cfs_free_nidlist(nidlist);
-                       return 0;
-               }
-       }
-       return 1;
-}
-EXPORT_SYMBOL(cfs_parse_nidlist);
-
-/**
- * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
- *
- * \see cfs_parse_nidlist()
- *
- * \retval 1 on match
- * \retval 0  otherwises
- */
-int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist)
-{
-       struct nidrange *nr;
-       struct addrrange *ar;
-
-       list_for_each_entry(nr, nidlist, nr_link) {
-               if (nr->nr_netstrfns->nf_type != LNET_NETTYP(LNET_NIDNET(nid)))
-                       continue;
-               if (nr->nr_netnum != LNET_NETNUM(LNET_NIDNET(nid)))
-                       continue;
-               if (nr->nr_all)
-                       return 1;
-               list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
-                       if (nr->nr_netstrfns->nf_match_addr(LNET_NIDADDR(nid),
-                                                      &ar->ar_numaddr_ranges))
-                               return 1;
-       }
-       return 0;
-}
-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
-cfs_print_network(char *buffer, int count, struct nidrange *nr)
-{
-       struct netstrfns *nf = nr->nr_netstrfns;
-
-       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);