Whamcloud - gitweb
LU-6245 libcfs: create userland and kernel string operations 35/13835/8
authorJames Simmons <uja.ornl@gmail.com>
Mon, 30 Mar 2015 19:03:21 +0000 (15:03 -0400)
committerOleg Drokin <oleg.drokin@intel.com>
Mon, 6 Apr 2015 03:01:31 +0000 (03:01 +0000)
Additonal string handling and NID string parsing code are both
used by kernel space and user land. This prevents us from
moving forward for cleaning up the userland and kernel space
headers. With the code duplicated for both environments we
can then clean up the headers independently. Since NID string
handling is only done for LNET we move it there.

Signed-off-by: James Simmons <uja.ornl@gmail.com>
Change-Id: I5fccdae61322d0bace7094a36d2e551d719c4982
Reviewed-on: http://review.whamcloud.com/13835
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: John L. Hammond <john.hammond@intel.com>
Reviewed-by: Dmitry Eremin <dmitry.eremin@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
20 files changed:
libcfs/include/libcfs/libcfs.h
libcfs/include/libcfs/libcfs_string.h
libcfs/include/libcfs/util/Makefile.am
libcfs/include/libcfs/util/string.h [new file with mode: 0644]
libcfs/libcfs/Makefile.in
libcfs/libcfs/autoMakefile.am
libcfs/libcfs/libcfs_string.c
libcfs/libcfs/module.c
libcfs/libcfs/user-string.c [deleted file]
libcfs/libcfs/util/Makefile.am
libcfs/libcfs/util/nidstrings.c [new file with mode: 0644]
libcfs/libcfs/util/string.c [new file with mode: 0644]
lnet/include/lnet/nidstr.h
lnet/lnet/Makefile.in
lnet/lnet/autoMakefile.am
lnet/lnet/config.c
lnet/lnet/nidstrings.c [moved from libcfs/libcfs/nidstrings.c with 80% similarity]
lustre/include/obd.h
lustre/utils/Makefile.am
lustre/utils/liblustreapi.c

index 5d36209..9f3d814 100644 (file)
@@ -252,7 +252,9 @@ void cfs_get_random_bytes(void *buf, int size);
 #include <libcfs/libcfs_ioctl.h>
 #include <libcfs/libcfs_prim.h>
 #include <libcfs/libcfs_time.h>
-#include <libcfs/libcfs_string.h>
+#ifdef __KERNEL__
+# include <libcfs/libcfs_string.h>
+#endif /* __KERNEL__ */
 #include <libcfs/libcfs_kernelcomm.h>
 #include <libcfs/libcfs_workitem.h>
 #ifdef __KERNEL__
index e47ce4e..238be35 100644 (file)
@@ -49,11 +49,6 @@ char *cfs_strrstr(const char *haystack, const char *needle);
 int cfs_str2mask(const char *str, const char *(*bit2str)(int bit),
                  int *oldmask, int minmask, int allmask);
 
-/* Allocate space for and copy an existing string.
- * Must free with kfree().
- */
-char *cfs_strdup(const char *str, u_int32_t flags);
-
 /* safe vsnprintf */
 int cfs_vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
 
@@ -89,21 +84,6 @@ struct cfs_expr_list {
        struct list_head        el_exprs;
 };
 
-static inline int
-cfs_iswhite(char c)
-{
-       switch (c) {
-       case ' ':
-       case '\t':
-       case '\n':
-       case '\r':
-               return 1;
-       default:
-               break;
-       }
-       return 0;
-}
-
 char *cfs_trimwhite(char *str);
 int cfs_gettok(struct cfs_lstr *next, char delim, struct cfs_lstr *res);
 int cfs_str2num_check(char *str, int nob, unsigned *num,
@@ -130,10 +110,5 @@ int cfs_expr_list_parse(char *str, int len, unsigned min, unsigned max,
 void cfs_expr_list_free_list(struct list_head *list);
 int cfs_ip_addr_parse(char *str, int len, struct list_head *list);
 int cfs_ip_addr_match(__u32 addr, struct list_head *list);
-void cfs_ip_addr_free(struct list_head *list);
-
-#ifdef __KERNEL__
-#define        strtoul(str, endp, base)        simple_strtoul(str, endp, base)
-#endif
 
 #endif
index 2a1e9bf..d019394 100644 (file)
@@ -1 +1 @@
-EXTRA_DIST = parser.h platform.h libcfsutil_ioctl.h
+EXTRA_DIST = parser.h platform.h string.h libcfsutil_ioctl.h
diff --git a/libcfs/include/libcfs/util/string.h b/libcfs/include/libcfs/util/string.h
new file mode 100644 (file)
index 0000000..450c48c
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 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) 2012, 2014, Intel Corporation.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ * Lustre is a trademark of Sun Microsystems, Inc.
+ *
+ * libcfs/include/libcfs/libcfs_string.h
+ *
+ * Generic string manipulation functions.
+ *
+ * Author: Nathan Rutman <nathan.rutman@sun.com>
+ */
+
+#ifndef __LIBCFS_UTIL_STRING_H__
+#define __LIBCFS_UTIL_STRING_H__
+
+#include <stddef.h>
+
+#include <linux/types.h>
+#include <libcfs/list.h>
+
+#ifndef HAVE_STRLCPY /* not in glibc for RHEL 5.x, remove when obsolete */
+size_t strlcpy(char *tgt, const char *src, size_t tgt_len);
+#endif
+
+#ifndef HAVE_STRLCAT /* not in glibc for RHEL 5.x, remove when obsolete */
+size_t strlcat(char *tgt, const char *src, size_t tgt_len);
+#endif
+
+/**
+ * Structure to represent NULL-less strings.
+ */
+struct cfs_lstr {
+       char            *ls_str;
+       int             ls_len;
+};
+
+/*
+ * Structure to represent \<range_expr\> token of the syntax.
+ */
+struct cfs_range_expr {
+       /*
+        * Link to cfs_expr_list::el_exprs.
+        */
+       struct list_head        re_link;
+       __u32                   re_lo;
+       __u32                   re_hi;
+       __u32                   re_stride;
+};
+
+struct cfs_expr_list {
+       struct list_head        el_link;
+       struct list_head        el_exprs;
+};
+
+int cfs_gettok(struct cfs_lstr *next, char delim, struct cfs_lstr *res);
+int cfs_str2num_check(char *str, int nob, unsigned *num,
+                     unsigned min, unsigned max);
+int cfs_expr_list_match(__u32 value, struct cfs_expr_list *expr_list);
+int cfs_expr_list_print(char *buffer, int count,
+                       struct cfs_expr_list *expr_list);
+int cfs_expr_list_parse(char *str, int len, unsigned min, unsigned max,
+                       struct cfs_expr_list **elpp);
+void cfs_expr_list_free_list(struct list_head *list);
+int cfs_ip_addr_parse(char *str, int len, struct list_head *list);
+int cfs_ip_addr_match(__u32 addr, struct list_head *list);
+
+#endif
index f2fb3a3..9d5cd2d 100644 (file)
@@ -13,8 +13,8 @@ default: all
 
 libcfs-linux-objs := $(addprefix linux/,$(libcfs-linux-objs))
 
-libcfs-all-objs := debug.o fail.o nidstrings.o module.o tracefile.o \
-                  watchdog.o libcfs_string.o hash.o kernel_user_comm.o \
+libcfs-all-objs := debug.o fail.o module.o tracefile.o watchdog.o \
+                  libcfs_string.o hash.o kernel_user_comm.o \
                   prng.o workitem.o libcfs_cpu.o \
                   libcfs_mem.o libcfs_lock.o heap.o
 
index fd97164..1bbe71c 100644 (file)
@@ -40,15 +40,14 @@ SUBDIRS = linux util
 DIST_SUBDIRS = linux util
 
 noinst_LIBRARIES= libcfs.a
-libcfs_a_SOURCES = user-string.c
+libcfs_a_SOURCES = util/string.c util/nidstrings.c
 
 libcfs_a_CPPFLAGS = $(LLCPPFLAGS)
 libcfs_a_CFLAGS = $(LLCFLAGS)
 
 if UTILS
 lib_LIBRARIES = libcfsutil.a
-libcfsutil_a_SOURCES = nidstrings.c libcfs_string.c util/parser.c      \
-               util/l_ioctl.c util/util.c
+libcfsutil_a_SOURCES = util/parser.c util/l_ioctl.c util/util.c
 libcfsutil_a_CPPFLAGS = $(LLCPPFLAGS)
 libcfsutil_a_CFLAGS = $(LLCFLAGS) -DLUSTRE_UTILS=1
 endif
@@ -63,6 +62,5 @@ endif # MODULES
 
 MOSTLYCLEANFILES := @MOSTLYCLEANFILES@ linux-*.c linux/*.o libcfs
 EXTRA_DIST := $(libcfs-all-objs:%.o=%.c) tracefile.h prng.c \
-             workitem.c \
-             kernel_user_comm.c fail.c libcfs_cpu.c heap.c \
-             libcfs_mem.c libcfs_lock.c user-string.c
+             workitem.c kernel_user_comm.c fail.c libcfs_cpu.c \
+             heap.c libcfs_mem.c libcfs_lock.c
index 0d26580..ebe91ac 100644 (file)
@@ -139,24 +139,6 @@ int cfs_str2mask(const char *str, const char *(*bit2str)(int bit),
 }
 EXPORT_SYMBOL(cfs_str2mask);
 
-/* Duplicate a string in a platform-independent way */
-char *cfs_strdup(const char *str, u_int32_t flags)
-{
-        size_t lenz; /* length of str + zero byte */
-        char *dup_str;
-
-        lenz = strlen(str) + 1;
-
-       dup_str = kmalloc(lenz, flags);
-        if (dup_str == NULL)
-                return NULL;
-
-        memcpy(dup_str, str, lenz);
-
-        return dup_str;
-}
-EXPORT_SYMBOL(cfs_strdup);
-
 /**
  * cfs_{v}snprintf() return the actual size that is printed rather than
  * the size that would be printed in standard functions.
@@ -220,12 +202,12 @@ cfs_trimwhite(char *str)
 {
        char *end;
 
-       while (cfs_iswhite(*str))
+       while (isspace(*str))
                str++;
 
        end = str + strlen(str);
        while (end > str) {
-               if (!cfs_iswhite(end[-1]))
+               if (!isspace(end[-1]))
                        break;
                end--;
        }
@@ -255,7 +237,7 @@ cfs_gettok(struct cfs_lstr *next, char delim, struct cfs_lstr *res)
 
        /* skip leading white spaces */
        while (next->ls_len) {
-               if (!cfs_iswhite(*next->ls_str))
+               if (!isspace(*next->ls_str))
                        break;
                next->ls_str++;
                next->ls_len--;
@@ -282,7 +264,7 @@ cfs_gettok(struct cfs_lstr *next, char delim, struct cfs_lstr *res)
 
        /* skip ending whitespaces */
        while (--end != res->ls_str) {
-               if (!cfs_iswhite(*end))
+               if (!isspace(*end))
                        break;
        }
 
@@ -306,12 +288,12 @@ cfs_str2num_check(char *str, int nob, unsigned *num,
 {
        char    *endp;
 
-       *num = strtoul(str, &endp, 0);
+       *num = simple_strtoul(str, &endp, 0);
        if (endp == str)
                return 0;
 
        for (; endp < str + nob; endp++) {
-               if (!cfs_iswhite(*endp))
+               if (!isspace(*endp))
                        return 0;
        }
 
@@ -545,7 +527,7 @@ cfs_expr_list_free(struct cfs_expr_list *expr_list)
                struct cfs_range_expr *expr;
 
                expr = list_entry(expr_list->el_exprs.next,
-                                     struct cfs_range_expr, re_link),
+                                     struct cfs_range_expr, re_link);
                list_del(&expr->re_link);
                LIBCFS_FREE(expr, sizeof(*expr));
        }
@@ -699,10 +681,3 @@ cfs_ip_addr_match(__u32 addr, struct list_head *list)
        return i == 4;
 }
 EXPORT_SYMBOL(cfs_ip_addr_match);
-
-void
-cfs_ip_addr_free(struct list_head *list)
-{
-       cfs_expr_list_free_list(list);
-}
-EXPORT_SYMBOL(cfs_ip_addr_free);
index e284384..767bc07 100644 (file)
@@ -317,7 +317,6 @@ static int init_libcfs_module(void)
        int rc;
 
        libcfs_arch_init();
-       libcfs_init_nidstrings();
 
        rc = libcfs_debug_init(5 * 1024 * 1024);
        if (rc < 0) {
diff --git a/libcfs/libcfs/user-string.c b/libcfs/libcfs/user-string.c
deleted file mode 100644 (file)
index 6b725b5..0000000
+++ /dev/null
@@ -1,67 +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.gnu.org/licenses/gpl-2.0.html
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2014 Intel Corporation.
- */
-#ifndef __KERNEL__
-
-#include <string.h>
-
-/*
- * According manual of strlcpy() and strlcat() the functions should return
- * the total length of the string they tried to create. For strlcpy() that
- * means the length of src. For strlcat() that means the initial length of
- * dst plus the length of src. So, the function strnlen() cannot be used
- * otherwise the return value will be wrong.
- */
-#ifndef HAVE_STRLCPY /* not in glibc for RHEL 5.x, remove when obsolete */
-size_t strlcpy(char *dst, const char *src, size_t size)
-{
-       size_t ret = strlen(src);
-
-       if (size) {
-               size_t len = (ret >= size) ? size - 1 : ret;
-               memcpy(dst, src, len);
-               dst[len] = '\0';
-       }
-       return ret;
-}
-#endif
-
-#ifndef HAVE_STRLCAT /* not in glibc for RHEL 5.x, remove when obsolete */
-size_t strlcat(char *dst, const char *src, size_t size)
-{
-       size_t dsize = strlen(dst);
-       size_t len = strlen(src);
-       size_t ret = dsize + len;
-
-       dst  += dsize;
-       size -= dsize;
-       if (len >= size)
-               len = size-1;
-       memcpy(dst, src, len);
-       dst[len] = '\0';
-       return ret;
-}
-#endif
-
-#endif /* __KERNEL__ */
index 9194671..baa1f5a 100644 (file)
@@ -1 +1 @@
-EXTRA_DIST = parser.c l_ioctl.c util.c
+EXTRA_DIST = parser.c l_ioctl.c nidstrings.c string.c util.c
diff --git a/libcfs/libcfs/util/nidstrings.c b/libcfs/libcfs/util/nidstrings.c
new file mode 100644 (file)
index 0000000..26c4fec
--- /dev/null
@@ -0,0 +1,1343 @@
+/*
+ * 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, 2014, Intel Corporation.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ * Lustre is a trademark of Sun Microsystems, Inc.
+ *
+ * libcfs/libcfs/util/nidstrings.c
+ *
+ * Author: Phil Schwan <phil@clusterfs.com>
+ */
+
+#define DEBUG_SUBSYSTEM S_LNET
+
+#include <libcfs/util/string.h>
+#include <libcfs/libcfs.h>
+#include <lnet/nidstr.h>
+#ifdef HAVE_GETHOSTBYNAME
+# include <netdb.h>
+#endif
+
+/* max value for numeric network address */
+#define MAX_NUMERIC_VALUE 0xffffffff
+
+#define IPSTRING_LENGTH 16
+
+/* 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;
+
+char *
+libcfs_next_nidstring(void)
+{
+       char          *str;
+
+       str = libcfs_nidstrings[libcfs_nidstring_idx++];
+       if (libcfs_nidstring_idx ==
+           sizeof(libcfs_nidstrings)/sizeof(libcfs_nidstrings[0]))
+               libcfs_nidstring_idx = 0;
+
+       return str;
+}
+
+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);
+
+struct netstrfns {
+       __u32 nf_type;
+       char    *nf_name;
+       char    *nf_modname;
+       void    (*nf_addr2str)(__u32 addr, char *str, size_t size);
+       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);
+       bool    (*nf_is_contiguous)(struct list_head *nidlist);
+       void    (*nf_min_max)(struct list_head *nidlist, __u32 *min_nid,
+                             __u32 *max_nid);
+};
+
+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},
+};
+
+static const size_t libcfs_nnetstrfns =
+       sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
+
+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;
+       }
+
+#ifdef HAVE_GETHOSTBYNAME
+       /* known hostname? */
+       if (('a' <= str[0] && str[0] <= 'z') ||
+           ('A' <= str[0] && str[0] <= 'Z')) {
+               char *tmp;
+
+               tmp = calloc(1, nob + 1);
+               if (tmp != NULL) {
+                       struct hostent *he;
+
+                       memcpy(tmp, str, nob);
+                       tmp[nob] = 0;
+
+                       he = gethostbyname(tmp);
+
+                       free(tmp);
+
+                       if (he != NULL) {
+                               __u32 ip = *(__u32 *)he->h_addr;
+
+                               *addr = ntohl(ip);
+                               return 1;
+                       }
+               }
+       }
+#endif
+       return 0;
+}
+
+static void
+libcfs_decnum_addr2str(__u32 addr, char *str, size_t size)
+{
+       snprintf(str, size, "%u", addr);
+}
+
+static void
+libcfs_hexnum_addr2str(__u32 addr, char *str, size_t size)
+{
+       snprintf(str, 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;
+}
+
+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;
+}
+
+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(__u32 lnd)
+{
+       return libcfs_lnd2netstrfns(lnd) != NULL;
+}
+
+char *
+libcfs_lnd2modname(__u32 lnd)
+{
+       struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
+
+       return (nf == NULL) ? NULL : nf->nf_modname;
+}
+
+int
+libcfs_str2lnd(const char *str)
+{
+       struct netstrfns *nf = libcfs_name2netstrfns(str);
+
+       if (nf != NULL)
+               return nf->nf_type;
+
+       return -1;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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);
+}
+
+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);
+}
+
+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;
+}
+
+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;
+}
+
+/**
+ * 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;
+};
+
+/**
+ * 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 \<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;
+       }
+
+       addrrange = calloc(1, 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;
+       }
+
+       nr = calloc(1, 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);
+               free(ar);
+       }
+}
+
+/**
+ * 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);
+               free(nr);
+       }
+}
+
+/**
+ * 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;
+}
+
+/*
+ * 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).
+ *
+ * \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;
+}
+
+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;
+}
+
+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 += snprintf(buffer + i, count - i, ".");
+               i += cfs_expr_list_print(buffer + i, count - i, el);
+       }
+       return i;
+}
+
+
+/**
+ * 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 snprintf(buffer, count, "@%s", nf->nf_name);
+       else
+               return snprintf(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 += snprintf(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 += snprintf(buffer + i, count - i, " ");
+
+               if (nr->nr_all != 0) {
+                       LASSERT(list_empty(&nr->nr_addrranges));
+                       i += snprintf(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;
+}
+
+/**
+ * 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)
+{
+       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++;
+               }
+       }
+
+       tmp_ip_addr = ((min_ip[0] << 24) | (min_ip[1] << 16) |
+                      (min_ip[2] << 8) | min_ip[3]);
+
+       if (min_nid != NULL)
+               *min_nid = tmp_ip_addr;
+
+       tmp_ip_addr = ((max_ip[0] << 24) | (max_ip[1] << 16) |
+                      (max_ip[2] << 8) | max_ip[3]);
+
+       if (max_nid != NULL)
+               *max_nid = tmp_ip_addr;
+}
+
+/**
+ * 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)
+{
+       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;
+               }
+       }
+
+       if (min_nid != NULL)
+               *min_nid = min_addr;
+       if (max_nid != NULL)
+               *max_nid = max_addr;
+}
+
+/**
+ * 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)
+{
+       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;
+       }
+
+       if (nf == NULL)
+               return false;
+
+       if (!nf->nf_is_contiguous(nidlist))
+               return false;
+
+       return true;
+}
+
+/**
+ * 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)
+{
+       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;
+
+       list_for_each_entry(nr, nidlist, nr_link) {
+               list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
+                       cfs_num_ar_min_max(ar, &current_start_nid,
+                                          &current_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;
+                               }
+                       }
+               }
+       }
+
+       return true;
+}
+
+/**
+ * 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)
+{
+       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;
+
+       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, &current_start_nid,
+                                         &current_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;
+                               }
+                       }
+               }
+       }
+
+       return true;
+}
+
+/**
+ * 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)
+{
+       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];
+
+       list_for_each_entry(nr, nidlist, nr_link) {
+               nf = nr->nr_netstrfns;
+               lndname = nf->nf_name;
+               if (netnum == -1)
+                       netnum = nr->nr_netnum;
+
+               nf->nf_min_max(nidlist, &min_addr, &max_addr);
+       }
+       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);
+}
+
+/**
+ * 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)
+{
+       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;
+
+       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;
+               }
+       }
+       *max_nid = max_addr;
+       *min_nid = min_addr;
+}
+
+/**
+ * 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)
+{
+       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 (min_nid != NULL)
+               *min_nid = min_ip_addr;
+       if (max_nid != NULL)
+               *max_nid = max_ip_addr;
+}
diff --git a/libcfs/libcfs/util/string.c b/libcfs/libcfs/util/string.c
new file mode 100644 (file)
index 0000000..f4c6f45
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * 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) 2012, 2014, Intel Corporation.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ * Lustre is a trademark of Sun Microsystems, Inc.
+ *
+ * String manipulation functions.
+ *
+ * libcfs/libcfs/util/string.c
+ *
+ * Author: Nathan Rutman <nathan.rutman@sun.com>
+ */
+#include <ctype.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libcfs/util/string.h>
+
+/*
+ * According manual of strlcpy() and strlcat() the functions should return
+ * the total length of the string they tried to create. For strlcpy() that
+ * means the length of src. For strlcat() that means the initial length of
+ * dst plus the length of src. So, the function strnlen() cannot be used
+ * otherwise the return value will be wrong.
+ */
+#ifndef HAVE_STRLCPY /* not in glibc for RHEL 5.x, remove when obsolete */
+size_t strlcpy(char *dst, const char *src, size_t size)
+{
+       size_t ret = strlen(src);
+
+       if (size) {
+               size_t len = (ret >= size) ? size - 1 : ret;
+               memcpy(dst, src, len);
+               dst[len] = '\0';
+       }
+       return ret;
+}
+#endif
+
+#ifndef HAVE_STRLCAT /* not in glibc for RHEL 5.x, remove when obsolete */
+size_t strlcat(char *dst, const char *src, size_t size)
+{
+       size_t dsize = strlen(dst);
+       size_t len = strlen(src);
+       size_t ret = dsize + len;
+
+       dst  += dsize;
+       size -= dsize;
+       if (len >= size)
+               len = size-1;
+       memcpy(dst, src, len);
+       dst[len] = '\0';
+       return ret;
+}
+#endif
+
+/**
+ * Extracts tokens from strings.
+ *
+ * Looks for \a delim in string \a next, sets \a res to point to
+ * substring before the delimiter, sets \a next right after the found
+ * delimiter.
+ *
+ * \retval 1 if \a res points to a string of non-whitespace characters
+ * \retval 0 otherwise
+ */
+int
+cfs_gettok(struct cfs_lstr *next, char delim, struct cfs_lstr *res)
+{
+       char *end;
+
+       if (next->ls_str == NULL)
+               return 0;
+
+       /* skip leading white spaces */
+       while (next->ls_len) {
+               if (!isspace(*next->ls_str))
+                       break;
+               next->ls_str++;
+               next->ls_len--;
+       }
+
+       if (next->ls_len == 0) /* whitespaces only */
+               return 0;
+
+       if (*next->ls_str == delim) {
+               /* first non-writespace is the delimiter */
+               return 0;
+       }
+
+       res->ls_str = next->ls_str;
+       end = memchr(next->ls_str, delim, next->ls_len);
+       if (end == NULL) {
+               /* there is no the delimeter in the string */
+               end = next->ls_str + next->ls_len;
+               next->ls_str = NULL;
+       } else {
+               next->ls_str = end + 1;
+               next->ls_len -= (end - res->ls_str + 1);
+       }
+
+       /* skip ending whitespaces */
+       while (--end != res->ls_str) {
+               if (!isspace(*end))
+                       break;
+       }
+
+       res->ls_len = end - res->ls_str + 1;
+       return 1;
+}
+
+/**
+ * Converts string to integer.
+ *
+ * Accepts decimal and hexadecimal number recordings.
+ *
+ * \retval 1 if first \a nob chars of \a str convert to decimal or
+ * hexadecimal integer in the range [\a min, \a max]
+ * \retval 0 otherwise
+ */
+int
+cfs_str2num_check(char *str, int nob, unsigned *num,
+                 unsigned min, unsigned max)
+{
+       char    *endp;
+
+       *num = strtoul(str, &endp, 0);
+       if (endp == str)
+               return 0;
+
+       for (; endp < str + nob; endp++) {
+               if (!isspace(*endp))
+                       return 0;
+       }
+
+       return (*num >= min && *num <= max);
+}
+
+/**
+ * Parses \<range_expr\> token of the syntax. If \a bracketed is false,
+ * \a src should only have a single token which can be \<number\> or  \*
+ *
+ * \retval pointer to allocated range_expr and initialized
+ * range_expr::re_lo, range_expr::re_hi and range_expr:re_stride if \a
+ * src parses to
+ * \<number\> |
+ * \<number\> '-' \<number\> |
+ * \<number\> '-' \<number\> '/' \<number\>
+ * \retval 0 will be returned if it can be parsed, otherwise -EINVAL or
+ * -ENOMEM will be returned.
+ */
+static int
+cfs_range_expr_parse(struct cfs_lstr *src, unsigned min, unsigned max,
+                    int bracketed, struct cfs_range_expr **expr)
+{
+       struct cfs_range_expr   *re;
+       struct cfs_lstr         tok;
+
+       re = calloc(1, sizeof(*re));
+       if (re == NULL)
+               return -ENOMEM;
+
+       if (src->ls_len == 1 && src->ls_str[0] == '*') {
+               re->re_lo = min;
+               re->re_hi = max;
+               re->re_stride = 1;
+               goto out;
+       }
+
+       if (cfs_str2num_check(src->ls_str, src->ls_len,
+                             &re->re_lo, min, max)) {
+               /* <number> is parsed */
+               re->re_hi = re->re_lo;
+               re->re_stride = 1;
+               goto out;
+       }
+
+       if (!bracketed || !cfs_gettok(src, '-', &tok))
+               goto failed;
+
+       if (!cfs_str2num_check(tok.ls_str, tok.ls_len,
+                              &re->re_lo, min, max))
+               goto failed;
+
+       /* <number> - */
+       if (cfs_str2num_check(src->ls_str, src->ls_len,
+                             &re->re_hi, min, max)) {
+               /* <number> - <number> is parsed */
+               re->re_stride = 1;
+               goto out;
+       }
+
+       /* go to check <number> '-' <number> '/' <number> */
+       if (cfs_gettok(src, '/', &tok)) {
+               if (!cfs_str2num_check(tok.ls_str, tok.ls_len,
+                                      &re->re_hi, min, max))
+                       goto failed;
+
+               /* <number> - <number> / ... */
+               if (cfs_str2num_check(src->ls_str, src->ls_len,
+                                     &re->re_stride, min, max)) {
+                       /* <number> - <number> / <number> is parsed */
+                       goto out;
+               }
+       }
+
+ out:
+       *expr = re;
+       return 0;
+
+ failed:
+       free(re);
+       return -EINVAL;
+}
+
+/**
+ * Print the range expression \a re into specified \a buffer.
+ * If \a bracketed is true, expression does not need additional
+ * brackets.
+ *
+ * \retval number of characters written
+ */
+static int
+cfs_range_expr_print(char *buffer, int count, struct cfs_range_expr *expr,
+                    bool bracketed)
+{
+       int i;
+       char s[] = "[";
+       char e[] = "]";
+
+       if (bracketed)
+               s[0] = e[0] = '\0';
+
+       if (expr->re_lo == expr->re_hi)
+               i = snprintf(buffer, count, "%u", expr->re_lo);
+       else if (expr->re_stride == 1)
+               i = snprintf(buffer, count, "%s%u-%u%s",
+                                 s, expr->re_lo, expr->re_hi, e);
+       else
+               i = snprintf(buffer, count, "%s%u-%u/%u%s",
+                                 s, expr->re_lo, expr->re_hi,
+                                 expr->re_stride, e);
+       return i;
+}
+
+/**
+ * Print a list of range expressions (\a expr_list) into specified \a buffer.
+ * If the list contains several expressions, separate them with comma
+ * and surround the list with brackets.
+ *
+ * \retval number of characters written
+ */
+int
+cfs_expr_list_print(char *buffer, int count, struct cfs_expr_list *expr_list)
+{
+       struct cfs_range_expr *expr;
+       int i = 0, j = 0;
+       int numexprs = 0;
+
+       if (count <= 0)
+               return 0;
+
+       list_for_each_entry(expr, &expr_list->el_exprs, re_link)
+               numexprs++;
+
+       if (numexprs > 1)
+               i += snprintf(buffer + i, count - i, "[");
+
+       list_for_each_entry(expr, &expr_list->el_exprs, re_link) {
+               if (j++ != 0)
+                       i += snprintf(buffer + i, count - i, ",");
+               i += cfs_range_expr_print(buffer + i, count - i, expr,
+                                         numexprs > 1);
+       }
+
+       if (numexprs > 1)
+               i += snprintf(buffer + i, count - i, "]");
+
+       return i;
+}
+
+/**
+ * Matches value (\a value) against ranges expression list \a expr_list.
+ *
+ * \retval 1 if \a value matches
+ * \retval 0 otherwise
+ */
+int
+cfs_expr_list_match(__u32 value, struct cfs_expr_list *expr_list)
+{
+       struct cfs_range_expr   *expr;
+
+       list_for_each_entry(expr, &expr_list->el_exprs, re_link) {
+               if (value >= expr->re_lo && value <= expr->re_hi &&
+                   ((value - expr->re_lo) % expr->re_stride) == 0)
+                       return 1;
+       }
+
+       return 0;
+}
+
+/**
+ * Frees cfs_range_expr structures of \a expr_list.
+ *
+ * \retval none
+ */
+static void
+cfs_expr_list_free(struct cfs_expr_list *expr_list)
+{
+       while (!list_empty(&expr_list->el_exprs)) {
+               struct cfs_range_expr *expr;
+
+               expr = list_entry(expr_list->el_exprs.next,
+                                 struct cfs_range_expr, re_link);
+               list_del(&expr->re_link);
+               free(expr);
+       }
+
+       free(expr_list);
+}
+
+/**
+ * Parses \<cfs_expr_list\> token of the syntax.
+ *
+ * \retval 0 if \a str parses to \<number\> | \<expr_list\>
+ * \retval -errno otherwise
+ */
+int
+cfs_expr_list_parse(char *str, int len, unsigned min, unsigned max,
+                   struct cfs_expr_list **elpp)
+{
+       struct cfs_expr_list    *expr_list;
+       struct cfs_range_expr   *expr;
+       struct cfs_lstr         src;
+       int                     rc;
+
+       expr_list = calloc(1, sizeof(*expr_list));
+       if (expr_list == NULL)
+               return -ENOMEM;
+
+       src.ls_str = str;
+       src.ls_len = len;
+
+       INIT_LIST_HEAD(&expr_list->el_exprs);
+
+       if (src.ls_str[0] == '[' &&
+           src.ls_str[src.ls_len - 1] == ']') {
+               src.ls_str++;
+               src.ls_len -= 2;
+
+               rc = -EINVAL;
+               while (src.ls_str != NULL) {
+                       struct cfs_lstr tok;
+
+                       if (!cfs_gettok(&src, ',', &tok)) {
+                               rc = -EINVAL;
+                               break;
+                       }
+
+                       rc = cfs_range_expr_parse(&tok, min, max, 1, &expr);
+                       if (rc != 0)
+                               break;
+
+                       list_add_tail(&expr->re_link,
+                                         &expr_list->el_exprs);
+               }
+       } else {
+               rc = cfs_range_expr_parse(&src, min, max, 0, &expr);
+               if (rc == 0) {
+                       list_add_tail(&expr->re_link,
+                                         &expr_list->el_exprs);
+               }
+       }
+
+       if (rc != 0)
+               cfs_expr_list_free(expr_list);
+       else
+               *elpp = expr_list;
+
+       return rc;
+}
+
+/**
+ * Frees cfs_expr_list structures of \a list.
+ *
+ * For each struct cfs_expr_list structure found on \a list it frees
+ * range_expr list attached to it and frees the cfs_expr_list itself.
+ *
+ * \retval none
+ */
+void
+cfs_expr_list_free_list(struct list_head *list)
+{
+       struct cfs_expr_list *el;
+
+       while (!list_empty(list)) {
+               el = list_entry(list->next,
+                                   struct cfs_expr_list, el_link);
+               list_del(&el->el_link);
+               cfs_expr_list_free(el);
+       }
+}
+
+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;
+}
+
+/**
+ * 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;
+}
index b9e398e..fcfcbfb 100644 (file)
@@ -34,16 +34,29 @@ struct list_head;
 #define LNET_NIDSTR_COUNT  1024    /* # of nidstrings */
 #define LNET_NIDSTR_SIZE   32      /* size of each one (see below for usage) */
 
-/* support decl needed both by kernel and liblustre */
+/* support decl needed by both kernel and user space */
+char *libcfs_next_nidstring(void);
 int libcfs_isknown_lnd(__u32 lnd);
 char *libcfs_lnd2modname(__u32 lnd);
-char *libcfs_lnd2str(__u32 lnd);
 char *libcfs_lnd2str_r(__u32 lnd, char *buf, size_t buf_size);
+static inline char *libcfs_lnd2str(__u32 lnd)
+{
+       return libcfs_lnd2str_r(lnd, libcfs_next_nidstring(),
+                               LNET_NIDSTR_SIZE);
+}
 int libcfs_str2lnd(const char *str);
-char *libcfs_net2str(__u32 net);
 char *libcfs_net2str_r(__u32 net, char *buf, size_t buf_size);
-char *libcfs_nid2str(lnet_nid_t nid);
+static inline char *libcfs_net2str(__u32 net)
+{
+       return libcfs_net2str_r(net, libcfs_next_nidstring(),
+                               LNET_NIDSTR_SIZE);
+}
 char *libcfs_nid2str_r(lnet_nid_t nid, char *buf, size_t buf_size);
+static inline char *libcfs_nid2str(lnet_nid_t nid)
+{
+       return libcfs_nid2str_r(nid, libcfs_next_nidstring(),
+                               LNET_NIDSTR_SIZE);
+}
 __u32 libcfs_str2net(const char *str);
 lnet_nid_t libcfs_str2nid(const char *str);
 int libcfs_str2anynid(lnet_nid_t *nid, const char *str);
@@ -55,6 +68,5 @@ int cfs_match_nid(lnet_nid_t nid, struct list_head *list);
 bool cfs_nidrange_is_contiguous(struct list_head *nidlist);
 void cfs_nidrange_find_min_max(struct list_head *nidlist, char *min_nid,
                               char *max_nid, size_t nidstr_length);
-void libcfs_init_nidstrings(void);
 
 #endif /* _LNET_NIDSTRINGS_H */
index 2e6736a..ee119ad 100644 (file)
@@ -1,6 +1,6 @@
 MODULES := lnet
 
-lnet-objs := api-ni.o config.o
+lnet-objs := api-ni.o config.o nidstrings.o
 lnet-objs += lib-me.o lib-msg.o lib-eq.o lib-md.o lib-ptl.o
 lnet-objs += lib-socket.o lib-move.o module.o lo.o
 lnet-objs += router.o router_proc.o acceptor.o peer.o net_fault.o
index 9956886..a569e9f 100644 (file)
@@ -1,4 +1,4 @@
-my_sources =    api-ni.c config.c \
+my_sources =    api-ni.c config.c nidstring.c \
                lib-me.c lib-msg.c lib-eq.c lib-socket.c \
                lib-md.c lib-ptl.c lib-move.c lo.c \
                router.c router_proc.c \
index d8a70f1..1b8fc3c 100644 (file)
@@ -466,7 +466,7 @@ lnet_str2tbs_sep(struct list_head *tbs, char *str)
        /* Split 'str' into separate commands */
        for (;;) {
                 /* skip leading whitespace */
-                while (cfs_iswhite(*str))
+               while (isspace(*str))
                         str++;
 
                /* scan for separator or comment */
@@ -483,7 +483,7 @@ lnet_str2tbs_sep(struct list_head *tbs, char *str)
                        }
 
                         for (i = 0; i < nob; i++)
-                                if (cfs_iswhite(str[i]))
+                               if (isspace(str[i]))
                                         ltb->ltb_text[i] = ' ';
                                 else
                                         ltb->ltb_text[i] = str[i];
@@ -690,7 +690,7 @@ lnet_parse_route (char *str, int *im_a_router)
        sep = str;
        for (;;) {
                /* scan for token start */
-                while (cfs_iswhite(*sep))
+               while (isspace(*sep))
                        sep++;
                if (*sep == 0) {
                        if (ntokens < (got_hops ? 3 : 2))
@@ -702,7 +702,7 @@ lnet_parse_route (char *str, int *im_a_router)
                token = sep++;
 
                /* scan for token end */
-                while (*sep != 0 && !cfs_iswhite(*sep))
+               while (*sep != 0 && !isspace(*sep))
                        sep++;
                if (*sep != 0)
                        *sep++ = 0;
@@ -857,7 +857,7 @@ lnet_match_network_token(char *token, int len, __u32 *ipaddrs, int nip)
        for (rc = i = 0; !rc && i < nip; i++)
                rc = cfs_ip_addr_match(ipaddrs[i], &list);
 
-       cfs_ip_addr_free(&list);
+       cfs_expr_list_free_list(&list);
 
         return rc;
 }
@@ -882,7 +882,7 @@ lnet_match_network_tokens(char *net_entry, __u32 *ipaddrs, int nip)
         sep = tokens;
         for (;;) {
                 /* scan for token start */
-                while (cfs_iswhite(*sep))
+               while (isspace(*sep))
                         sep++;
                 if (*sep == 0)
                         break;
@@ -890,7 +890,7 @@ lnet_match_network_tokens(char *net_entry, __u32 *ipaddrs, int nip)
                 token = sep++;
 
                 /* scan for token end */
-                while (*sep != 0 && !cfs_iswhite(*sep))
+               while (*sep != 0 && !isspace(*sep))
                         sep++;
                 if (*sep != 0)
                         *sep++ = 0;
similarity index 80%
rename from libcfs/libcfs/nidstrings.c
rename to lnet/lnet/nidstrings.c
index 73bd389..2474445 100644 (file)
@@ -33,7 +33,7 @@
  * This file is part of Lustre, http://www.lustre.org/
  * Lustre is a trademark of Sun Microsystems, Inc.
  *
- * libcfs/libcfs/nidstrings.c
+ * lnet/lnet/nidstrings.c
  *
  * Author: Phil Schwan <phil@clusterfs.com>
  */
 
 #include <libcfs/libcfs.h>
 #include <lnet/nidstr.h>
-#ifndef __KERNEL__
-#ifdef HAVE_GETHOSTBYNAME
-# include <netdb.h>
-#endif
-#endif
 
 /* max value for numeric network address */
 #define MAX_NUMERIC_VALUE 0xffffffff
  */
 
 static char      libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE];
-static int       libcfs_nidstring_idx = 0;
+static int       libcfs_nidstring_idx;
 
-#ifdef __KERNEL__
-static spinlock_t libcfs_nidstring_lock;
+static DEFINE_SPINLOCK(libcfs_nidstring_lock);
 
-void libcfs_init_nidstrings (void)
-{
-       spin_lock_init(&libcfs_nidstring_lock);
-}
-
-# define NIDSTR_LOCK(f)   spin_lock_irqsave(&libcfs_nidstring_lock, f)
-# define NIDSTR_UNLOCK(f) spin_unlock_irqrestore(&libcfs_nidstring_lock, f)
-#else
-# define NIDSTR_LOCK(f)   (f=sizeof(f))  /* avoid set-but-unused warnings */
-# define NIDSTR_UNLOCK(f) (f=sizeof(f))
-#endif
-
-static char *
-libcfs_next_nidstring (void)
+char *
+libcfs_next_nidstring(void)
 {
-        char          *str;
-        unsigned long  flags;
+       char          *str;
+       unsigned long  flags;
 
-        NIDSTR_LOCK(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]))
-                libcfs_nidstring_idx = 0;
+       str = libcfs_nidstrings[libcfs_nidstring_idx++];
+       if (libcfs_nidstring_idx ==
+           sizeof(libcfs_nidstrings)/sizeof(libcfs_nidstrings[0]))
+               libcfs_nidstring_idx = 0;
 
-        NIDSTR_UNLOCK(flags);
-        return str;
+       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);
 static void libcfs_ip_addr2str(__u32 addr, char *str, size_t size);
@@ -118,7 +101,7 @@ static bool cfs_num_is_contiguous(struct list_head *nidlist);
 static void cfs_num_min_max(struct list_head *nidlist, __u32 *min, __u32 *max);
 
 struct netstrfns {
-       __u32    nf_type;
+       __u32 nf_type;
        char    *nf_name;
        char    *nf_modname;
        void    (*nf_addr2str)(__u32 addr, char *str, size_t size);
@@ -130,7 +113,7 @@ struct netstrfns {
        int     (*nf_match_addr)(__u32 addr, struct list_head *list);
        bool    (*nf_is_contiguous)(struct list_head *nidlist);
        void    (*nf_min_max)(struct list_head *nidlist, __u32 *min_nid,
-                               __u32 *max_nid);
+                             __u32 *max_nid);
 };
 
 static struct netstrfns  libcfs_netstrfns[] = {
@@ -281,7 +264,8 @@ static struct netstrfns  libcfs_netstrfns[] = {
 static const size_t libcfs_nnetstrfns =
        sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
 
-static int libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
+static int
+libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
 {
        *addr = 0;
        return 1;
@@ -301,8 +285,8 @@ libcfs_ip_addr2str(__u32 addr, char *str, size_t size)
  * 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)
+static int
+libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
 {
        unsigned int    a;
        unsigned int    b;
@@ -310,42 +294,15 @@ static int libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
        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;
-        }
-
-#if !defined(__KERNEL__) && defined HAVE_GETHOSTBYNAME
-        /* known hostname? */
-        if (('a' <= str[0] && str[0] <= 'z') ||
-            ('A' <= str[0] && str[0] <= 'Z')) {
-                char *tmp;
-
-                LIBCFS_ALLOC(tmp, nob + 1);
-                if (tmp != NULL) {
-                        struct hostent *he;
-
-                        memcpy(tmp, str, nob);
-                        tmp[nob] = 0;
-
-                        he = gethostbyname(tmp);
-
-                        LIBCFS_FREE(tmp, nob);
-
-                        if (he != NULL) {
-                                __u32 ip = *(__u32 *)he->h_addr;
-
-                                *addr = ntohl(ip);
-                                return 1;
-                        }
-                }
-        }
-#endif
-        return 0;
+       /* 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 void
@@ -363,27 +320,27 @@ libcfs_hexnum_addr2str(__u32 addr, char *str, size_t size)
 static int
 libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
 {
-        int     n;
+       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, "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;
+       n = nob;
+       if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
+               return 1;
 
-        return 0;
+       return 0;
 }
 
 static struct netstrfns *
 libcfs_lnd2netstrfns(__u32 lnd)
 {
-       __u32 i;
+       int     i;
 
        for (i = 0; i < libcfs_nnetstrfns; i++)
                if (lnd == libcfs_netstrfns[i].nf_type)
@@ -395,55 +352,61 @@ libcfs_lnd2netstrfns(__u32 lnd)
 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;
+       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;
+       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];
+       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;
+       return NULL;
 }
 
-int libcfs_isknown_lnd(__u32 lnd)
+int
+libcfs_isknown_lnd(__u32 lnd)
 {
        return libcfs_lnd2netstrfns(lnd) != NULL;
 }
+EXPORT_SYMBOL(libcfs_isknown_lnd);
 
-char *libcfs_lnd2modname(__u32 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);
+       struct netstrfns *nf = libcfs_name2netstrfns(str);
 
-        if (nf != NULL)
-                return nf->nf_type;
+       if (nf != NULL)
+               return nf->nf_type;
 
-        return -1;
+       return -1;
 }
+EXPORT_SYMBOL(libcfs_str2lnd);
 
-char *libcfs_lnd2str_r(__u32 lnd, char *buf, size_t buf_size)
+char *
+libcfs_lnd2str_r(__u32 lnd, char *buf, size_t buf_size)
 {
        struct netstrfns *nf;
 
@@ -455,8 +418,10 @@ char *libcfs_lnd2str_r(__u32 lnd, char *buf, size_t buf_size)
 
        return buf;
 }
+EXPORT_SYMBOL(libcfs_lnd2str_r);
 
-char *libcfs_net2str_r(__u32 net, char *buf, size_t buf_size)
+char *
+libcfs_net2str_r(__u32 net, char *buf, size_t buf_size)
 {
        __u32             nnum = LNET_NETNUM(net);
        __u32             lnd  = LNET_NETTYP(net);
@@ -472,8 +437,10 @@ char *libcfs_net2str_r(__u32 net, char *buf, size_t buf_size)
 
        return buf;
 }
+EXPORT_SYMBOL(libcfs_net2str_r);
 
-char *libcfs_nid2str_r(lnet_nid_t nid, char *buf, size_t buf_size)
+char *
+libcfs_nid2str_r(lnet_nid_t nid, char *buf, size_t buf_size)
 {
        __u32             addr = LNET_NIDADDR(nid);
        __u32             net  = LNET_NIDNET(nid);
@@ -497,32 +464,15 @@ char *libcfs_nid2str_r(lnet_nid_t nid, char *buf, size_t buf_size)
                addr_len = strlen(buf);
                if (nnum == 0)
                        snprintf(buf + addr_len, buf_size - addr_len, "@%s",
-                                       nf->nf_name);
+                                nf->nf_name);
                else
                        snprintf(buf + addr_len, buf_size - addr_len, "@%s%u",
-                                       nf->nf_name, nnum);
+                                nf->nf_name, nnum);
        }
 
        return buf;
 }
-
-char *libcfs_lnd2str(__u32 lnd)
-{
-       return libcfs_lnd2str_r(lnd, libcfs_next_nidstring(),
-                               LNET_NIDSTR_SIZE);
-}
-
-char *libcfs_net2str(__u32 net)
-{
-       return libcfs_net2str_r(net, libcfs_next_nidstring(),
-                               LNET_NIDSTR_SIZE);
-}
-
-char *libcfs_nid2str(lnet_nid_t nid)
-{
-       return libcfs_nid2str_r(nid, libcfs_next_nidstring(),
-                               LNET_NIDSTR_SIZE);
-}
+EXPORT_SYMBOL(libcfs_nid2str_r);
 
 static struct netstrfns *
 libcfs_str2net_internal(const char *str, __u32 *net)
@@ -532,99 +482,103 @@ libcfs_str2net_internal(const char *str, __u32 *net)
        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;
+       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;
+       __u32  net;
 
-        if (libcfs_str2net_internal(str, &net) != NULL)
-                return net;
+       if (libcfs_str2net_internal(str, &net) != NULL)
+               return net;
 
-        return LNET_NIDNET(LNET_NID_ANY);
+       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);
+       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;
+       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;
-        }
+       if (!strcmp(str, "*")) {
+               *nidp = LNET_NID_ANY;
+               return 1;
+       }
 
-        *nidp = libcfs_str2nid(str);
-        return *nidp != LNET_NID_ANY;
+       *nidp = libcfs_str2nid(str);
+       return *nidp != LNET_NID_ANY;
 }
+EXPORT_SYMBOL(libcfs_str2anynid);
 
 /**
  * Nid range list syntax.
@@ -757,29 +711,29 @@ 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 */
+       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;
-        }
+                       return NULL;
+       }
 
        list_for_each_entry(nr, nidlist, nr_link) {
                if (nr->nr_netstrfns != nf)
@@ -813,26 +767,26 @@ 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;
+       struct nidrange *nr;
 
-        tmp = *src;
+       tmp = *src;
        if (cfs_gettok(src, '@', &addrrange) == 0)
-                goto failed;
+               goto failed;
 
        if (cfs_gettok(src, '@', &net) == 0 || src->ls_str != NULL)
-                goto failed;
+               goto failed;
 
-        nr = add_nidrange(&net, nidlist);
-        if (nr == NULL)
-                goto failed;
+       nr = add_nidrange(&net, nidlist);
+       if (nr == NULL)
+               goto failed;
 
        if (parse_addrange(&addrrange, nr) != 0)
-                goto failed;
+               goto failed;
 
-        return 1;
+       return 1;
  failed:
-        CWARN("can't parse nidrange: \"%.*s\"\n", tmp.ls_len, tmp.ls_str);
-        return 0;
+       CWARN("can't parse nidrange: \"%.*s\"\n", tmp.ls_len, tmp.ls_str);
+       return 0;
 }
 
 /**
@@ -878,6 +832,7 @@ cfs_free_nidlist(struct list_head *list)
                LIBCFS_FREE(nr, sizeof(struct nidrange));
        }
 }
+EXPORT_SYMBOL(cfs_free_nidlist);
 
 /**
  * Parses nid range list.
@@ -916,6 +871,7 @@ cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
        }
        return 1;
 }
+EXPORT_SYMBOL(cfs_parse_nidlist);
 
 /*
  * Nf_match_addr method for networks using numeric addresses
@@ -961,6 +917,7 @@ int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist)
        }
        return 0;
 }
+EXPORT_SYMBOL(cfs_match_nid);
 
 static int
 libcfs_num_addr_range_print(char *buffer, int count, struct list_head *list)
@@ -1033,7 +990,6 @@ cfs_print_addrranges(char *buffer, int count, struct list_head *addrranges,
        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.
@@ -1064,6 +1020,7 @@ int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist)
        }
        return i;
 }
+EXPORT_SYMBOL(cfs_print_nidlist);
 
 /**
  * Determines minimum and maximum addresses for a single
@@ -1376,25 +1333,3 @@ static void cfs_ip_min_max(struct list_head *nidlist, __u32 *min_nid,
        if (max_nid != NULL)
                *max_nid = max_ip_addr;
 }
-
-#ifdef __KERNEL__
-
-EXPORT_SYMBOL(libcfs_isknown_lnd);
-EXPORT_SYMBOL(libcfs_lnd2modname);
-EXPORT_SYMBOL(libcfs_lnd2str);
-EXPORT_SYMBOL(libcfs_lnd2str_r);
-EXPORT_SYMBOL(libcfs_str2lnd);
-EXPORT_SYMBOL(libcfs_net2str);
-EXPORT_SYMBOL(libcfs_net2str_r);
-EXPORT_SYMBOL(libcfs_nid2str);
-EXPORT_SYMBOL(libcfs_nid2str_r);
-EXPORT_SYMBOL(libcfs_str2net);
-EXPORT_SYMBOL(libcfs_str2nid);
-EXPORT_SYMBOL(libcfs_id2str);
-EXPORT_SYMBOL(libcfs_str2anynid);
-EXPORT_SYMBOL(cfs_free_nidlist);
-EXPORT_SYMBOL(cfs_parse_nidlist);
-EXPORT_SYMBOL(cfs_print_nidlist);
-EXPORT_SYMBOL(cfs_match_nid);
-
-#endif
index 85a1633..1435b13 100644 (file)
@@ -1264,7 +1264,7 @@ static inline bool filename_is_volatile(const char *name, size_t namelen,
        }
        /* we have an idx, read it */
        start = name + LUSTRE_VOLATILE_HDR_LEN + 1;
-       *idx = strtoul(start, &end, 16);
+       *idx = simple_strtoul(start, &end, 16);
        /* error cases:
         * no digit, no trailing :, negative value
         */
index 13fc74c..1faf1cf 100644 (file)
@@ -81,14 +81,13 @@ llverfs_LDADD := $(EXT2FSLIB) $(E2PLIB)
 
 llverdev_LDADD := $(EXT2FSLIB) $(BLKIDLIB)
 
-L_STRING := $(top_builddir)/libcfs/libcfs/user-string.c
-L_IOCTL := $(top_builddir)/libcfs/libcfs/util/l_ioctl.c
+L_STRING := $(top_builddir)/libcfs/libcfs/util/string.c
 L_KERNELCOMM := $(top_builddir)/libcfs/libcfs/kernel_user_comm.c
 liblustreapitmp_a_SOURCES = liblustreapi.c liblustreapi_hsm.c \
                            liblustreapi_nodemap.c lustreapi_internal.h \
                            liblustreapi_json.c liblustreapi_layout.c \
                            liblustreapi_lease.c liblustreapi_util.c \
-                           $(L_IOCTL) $(L_KERNELCOMM) $(L_STRING)
+                           $(L_KERNELCOMM) $(L_STRING)
 
 if UTILS
 # build static and shared lib lustreapi
index 4728779..4694491 100644 (file)
@@ -71,6 +71,7 @@
 #endif
 #include <poll.h>
 
+#include <libcfs/util/string.h>
 #include <libcfs/libcfs.h>
 #include <lnet/lnetctl.h>
 #include <lustre/lustreapi.h>