* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, Whamcloud, Inc.
+ * Copyright (c) 2011, 2012, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
* Author: Phil Schwan <phil@clusterfs.com>
*/
-#ifndef EXPORT_SYMTAB
-# define EXPORT_SYMTAB
-#endif
-
#define DEBUG_SUBSYSTEM S_LNET
#include <libcfs/libcfs.h>
-#include <lnet/lnet.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
+
+#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...
static int libcfs_nidstring_idx = 0;
#ifdef __KERNEL__
-static cfs_spinlock_t libcfs_nidstring_lock;
+static spinlock_t libcfs_nidstring_lock;
void libcfs_init_nidstrings (void)
{
- cfs_spin_lock_init(&libcfs_nidstring_lock);
+ spin_lock_init(&libcfs_nidstring_lock);
}
-# define NIDSTR_LOCK(f) cfs_spin_lock_irqsave(&libcfs_nidstring_lock, f)
-# define NIDSTR_UNLOCK(f) cfs_spin_unlock_irqrestore(&libcfs_nidstring_lock, f)
+# 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))
static int libcfs_lo_str2addr(const char *str, int nob, __u32 *addr);
static void libcfs_ip_addr2str(__u32 addr, char *str);
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);
static void libcfs_hexnum_addr2str(__u32 addr, char *str);
static int libcfs_num_str2addr(const char *str, int nob, __u32 *addr);
-static int libcfs_ip_parse(char *str, int len, cfs_list_t *list);
-static int libcfs_num_parse(char *str, int len, cfs_list_t *list);
-static int libcfs_ip_match(__u32 addr, cfs_list_t *list);
-static int libcfs_num_match(__u32 addr, cfs_list_t *list);
+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 {
- int nf_type;
- char *nf_name;
- char *nf_modname;
- void (*nf_addr2str)(__u32 addr, char *str);
- int (*nf_str2addr)(const char *str, int nob, __u32 *addr);
- int (*nf_parse_addrlist)(char *str, int len,
- cfs_list_t *list);
- int (*nf_match_addr)(__u32 addr, cfs_list_t *list);
+ int nf_type;
+ char *nf_name;
+ char *nf_modname;
+ void (*nf_addr2str)(__u32 addr, char *str);
+ int (*nf_str2addr)(const char *str, int nob, __u32 *addr);
+ int (*nf_parse_addrlist)(char *str, int len,
+ struct list_head *list);
+ int (*nf_print_addrlist)(char *buffer, int count,
+ struct list_head *list);
+ int (*nf_match_addr)(__u32 addr, struct list_head *list);
+ 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_match_addr*/ libcfs_num_match},
- {/* .nf_type */ SOCKLND,
- /* .nf_name */ "tcp",
- /* .nf_modname */ "ksocklnd",
- /* .nf_addr2str */ libcfs_ip_addr2str,
- /* .nf_str2addr */ libcfs_ip_str2addr,
- /* .nf_parse_addrlist*/ libcfs_ip_parse,
- /* .nf_match_addr*/ libcfs_ip_match},
- {/* .nf_type */ O2IBLND,
- /* .nf_name */ "o2ib",
- /* .nf_modname */ "ko2iblnd",
- /* .nf_addr2str */ libcfs_ip_addr2str,
- /* .nf_str2addr */ libcfs_ip_str2addr,
- /* .nf_parse_addrlist*/ libcfs_ip_parse,
- /* .nf_match_addr*/ libcfs_ip_match},
- {/* .nf_type */ CIBLND,
- /* .nf_name */ "cib",
- /* .nf_modname */ "kciblnd",
- /* .nf_addr2str */ libcfs_ip_addr2str,
- /* .nf_str2addr */ libcfs_ip_str2addr,
- /* .nf_parse_addrlist*/ libcfs_ip_parse,
- /* .nf_match_addr*/ libcfs_ip_match},
- {/* .nf_type */ OPENIBLND,
- /* .nf_name */ "openib",
- /* .nf_modname */ "kopeniblnd",
- /* .nf_addr2str */ libcfs_ip_addr2str,
- /* .nf_str2addr */ libcfs_ip_str2addr,
- /* .nf_parse_addrlist*/ libcfs_ip_parse,
- /* .nf_match_addr*/ libcfs_ip_match},
- {/* .nf_type */ IIBLND,
- /* .nf_name */ "iib",
- /* .nf_modname */ "kiiblnd",
- /* .nf_addr2str */ libcfs_ip_addr2str,
- /* .nf_str2addr */ libcfs_ip_str2addr,
- /* .nf_parse_addrlist*/ libcfs_ip_parse,
- /* .nf_match_addr*/ libcfs_ip_match},
- {/* .nf_type */ VIBLND,
- /* .nf_name */ "vib",
- /* .nf_modname */ "kviblnd",
- /* .nf_addr2str */ libcfs_ip_addr2str,
- /* .nf_str2addr */ libcfs_ip_str2addr,
- /* .nf_parse_addrlist*/ libcfs_ip_parse,
- /* .nf_match_addr*/ libcfs_ip_match},
- {/* .nf_type */ RALND,
- /* .nf_name */ "ra",
- /* .nf_modname */ "kralnd",
- /* .nf_addr2str */ libcfs_ip_addr2str,
- /* .nf_str2addr */ libcfs_ip_str2addr,
- /* .nf_parse_addrlist*/ libcfs_ip_parse,
- /* .nf_match_addr*/ libcfs_ip_match},
- {/* .nf_type */ QSWLND,
- /* .nf_name */ "elan",
- /* .nf_modname */ "kqswlnd",
- /* .nf_addr2str */ libcfs_decnum_addr2str,
- /* .nf_str2addr */ libcfs_num_str2addr,
- /* .nf_parse_addrlist*/ libcfs_num_parse,
- /* .nf_match_addr*/ libcfs_num_match},
- {/* .nf_type */ GMLND,
- /* .nf_name */ "gm",
- /* .nf_modname */ "kgmlnd",
- /* .nf_addr2str */ libcfs_hexnum_addr2str,
- /* .nf_str2addr */ libcfs_num_str2addr,
- /* .nf_parse_addrlist*/ libcfs_num_parse,
- /* .nf_match_addr*/ libcfs_num_match},
- {/* .nf_type */ MXLND,
- /* .nf_name */ "mx",
- /* .nf_modname */ "kmxlnd",
- /* .nf_addr2str */ libcfs_ip_addr2str,
- /* .nf_str2addr */ libcfs_ip_str2addr,
- /* .nf_parse_addrlist*/ libcfs_ip_parse,
- /* .nf_match_addr*/ libcfs_ip_match},
- {/* .nf_type */ PTLLND,
- /* .nf_name */ "ptl",
- /* .nf_modname */ "kptllnd",
- /* .nf_addr2str */ libcfs_decnum_addr2str,
- /* .nf_str2addr */ libcfs_num_str2addr,
- /* .nf_parse_addrlist*/ libcfs_num_parse,
- /* .nf_match_addr*/ libcfs_num_match},
- {/* .nf_type */ GNILND,
- /* .nf_name */ "gni",
- /* .nf_modname */ "kgnilnd",
- /* .nf_addr2str */ libcfs_decnum_addr2str,
- /* .nf_str2addr */ libcfs_num_str2addr,
- /* .nf_parse_addrlist*/ libcfs_num_parse,
- /* .nf_match_addr*/ libcfs_num_match},
- /* placeholder for net0 alias. It MUST BE THE LAST ENTRY */
- {/* .nf_type */ -1},
+ {/* .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},
};
const int libcfs_nnetstrfns = sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
int
libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
{
- int a;
- int b;
- int c;
- int d;
- int n = nob; /* XscanfX */
+ 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 &&
static struct netstrfns *
libcfs_str2net_internal(const char *str, __u32 *net)
{
- struct netstrfns *nf;
- int nob;
- int netnum;
- int i;
+ struct netstrfns *nf = NULL;
+ int nob;
+ unsigned int netnum;
+ int i;
for (i = 0; i < libcfs_nnetstrfns; i++) {
nf = &libcfs_netstrfns[i];
* <nidrange> :== <addrrange> '@' <net>
* <addrrange> :== '*' |
* <ipaddr_range> |
- * <numaddr_range>
- * <ipaddr_range> :== <numaddr_range>.<numaddr_range>.<numaddr_range>.
- * <numaddr_range>
- * <numaddr_range> :== <number> |
+ * <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> |
*/
/**
- * Structure to represent NULL-less strings.
- */
-struct lstr {
- char *ls_str;
- int ls_len;
-};
-
-/**
* 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.
- */
- cfs_list_t nr_link;
- /**
- * List head for addrrange::ar_link.
- */
- cfs_list_t 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;
+ /**
+ * 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.
- */
- cfs_list_t ar_link;
- /**
- * List head for numaddr_range::nar_link.
- */
- cfs_list_t ar_numaddr_ranges;
-};
-
-/**
- * Structure to represent \<numaddr_range\> token of the syntax.
- */
-struct numaddr_range {
- /**
- * Link to addrrange::ar_numaddr_ranges.
- */
- cfs_list_t nar_link;
- /**
- * List head for range_expr::re_link.
- */
- cfs_list_t nar_range_exprs;
+ /**
+ * Link to nidrange::nr_addrranges.
+ */
+ struct list_head ar_link;
+ /**
+ * List head for cfs_expr_list::el_list.
+ */
+ struct list_head ar_numaddr_ranges;
};
/**
- * Structure to represent \<range_expr\> token of the syntax.
- */
-struct range_expr {
- /**
- * Link to numaddr_range::nar_range_exprs.
- */
- cfs_list_t re_link;
- __u32 re_lo;
- __u32 re_hi;
- __u32 re_stride;
-};
-
-int
-cfs_iswhite(char c)
-{
- switch (c) {
- case ' ':
- case '\t':
- case '\n':
- case '\r':
- return 1;
- default:
- break;
- }
- return 0;
-}
-
-/*
- * 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
- */
-static int
-gettok(struct lstr *next, char delim, struct lstr *res)
-{
- char *end;
-
- if (next->ls_str == NULL)
- return 0;
-
- /* skip leading white spaces */
- while (next->ls_len) {
- if (!cfs_iswhite(*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 (!cfs_iswhite(*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
- */
-static int
-libcfs_str2num_check(const char *str, int nob, unsigned *num,
- unsigned min, unsigned max)
-{
- int n;
- char nstr[12];
-
- n = nob;
- if (sscanf(str, "%u%n", num, &n) != 1 || n != nob)
- if (sscanf(str, "0x%x%n", num, &n) != 1 || n != nob)
- if (sscanf(str, "0X%x%n", num, &n) != 1 || n != nob)
- return 0;
- sprintf(nstr, "%u", *num);
- if (n != strlen(nstr) || memcmp(nstr, str, n)) {
- sprintf(nstr, "0x%x", *num);
- if (n != strlen(nstr) || memcmp(nstr, str, n)) {
- sprintf(nstr, "0X%x", *num);
- if (n != strlen(nstr) || memcmp(nstr, str, n))
- return 0;
- }
- }
- if (*num < min || *num > max)
- return 0;
- return 1;
-}
-
-/**
- * Parses \<range_expr\> token of the syntax.
- *
- * \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 NULL othersize
- */
-static struct range_expr *
-parse_range_expr(struct lstr *src, unsigned min, unsigned max)
-{
- struct lstr tok;
- struct range_expr *expr;
-
- LIBCFS_ALLOC(expr, sizeof(struct range_expr));
- if (expr == NULL)
- return NULL;
-
- if (libcfs_str2num_check(src->ls_str, src->ls_len, &expr->re_lo,
- min, max)) {
- /* <number> is parsed */
- expr->re_hi = expr->re_lo;
- expr->re_stride = 1;
- return expr;
- }
-
- if (!gettok(src, '-', &tok))
- goto failed;
- if (!libcfs_str2num_check(tok.ls_str, tok.ls_len, &expr->re_lo,
- min, max))
- goto failed;
- /* <number> - */
- if (libcfs_str2num_check(src->ls_str, src->ls_len, &expr->re_hi,
- min, max)) {
- /* <number> - <number> is parsed */
- expr->re_stride = 1;
- return expr;
- }
-
- /* go to check <number> '-' <number> '/' <number> */
- if (gettok(src, '/', &tok)) {
- if (!libcfs_str2num_check(tok.ls_str, tok.ls_len,
- &expr->re_hi, min, max))
- goto failed;
- /* <number> - <number> / ... */
- if (libcfs_str2num_check(src->ls_str, src->ls_len,
- &expr->re_stride, min, max))
- /* <number> - <number> / <number> is parsed */
- return expr;
- }
-
-failed:
- LIBCFS_FREE(expr, sizeof(struct range_expr));
- return NULL;
-}
-
-/**
- * Parses \<expr_list\> token of the syntax.
- *
- * \retval 1 if \a str parses to '[' \<range_expr\> [ ',' \<range_expr\>] ']'
- * \retval 0 otherwise
- */
-static int
-parse_expr_list(struct lstr *str, cfs_list_t *list,
- unsigned min, unsigned max)
-{
- struct lstr res;
- struct range_expr *range;
-
- if (str->ls_str[0] != '[' || str->ls_str[str->ls_len - 1] != ']')
- return 0;
- str->ls_str ++;
- str->ls_len -= 2;
-
- while (str->ls_str) {
- if (gettok(str, ',', &res) == 0)
- return 0;
- range = parse_range_expr(&res, min, max);
- if (range == NULL)
- return 0;
- cfs_list_add_tail(&range->re_link, list);
- }
- return 1;
-}
-
-/**
- * Parses \<numaddr_range\> token of the syntax.
- *
- * \retval 1 if \a str parses to \<number\> | \<expr_list\>
- * \retval 0 otherwise
- */
-static int
-num_parse(char *str, int len,
- cfs_list_t *list, unsigned min, unsigned max)
-{
- __u32 num;
- struct lstr src;
- struct numaddr_range *numaddr;
-
- src.ls_str = str;
- src.ls_len = len;
-
- LIBCFS_ALLOC(numaddr, sizeof(struct numaddr_range));
- if (numaddr == NULL)
- return 0;
- cfs_list_add_tail(&numaddr->nar_link, list);
- CFS_INIT_LIST_HEAD(&numaddr->nar_range_exprs);
-
- if (libcfs_str2num_check(src.ls_str, src.ls_len, &num, min, max)) {
- /* <number> */
- struct range_expr *expr;
-
- LIBCFS_ALLOC(expr, sizeof(struct range_expr));
- if (expr == NULL)
- return 0;
-
- expr->re_lo = expr->re_hi = num;
- expr->re_stride = 1;
- cfs_list_add_tail(&expr->re_link, &numaddr->nar_range_exprs);
- return 1;
- }
-
- return parse_expr_list(&src, &numaddr->nar_range_exprs, min, max);
-}
-
-/**
* Nf_parse_addrlist method for networks using numeric addresses.
*
* Examples of such networks are gm and elan.
*
- * \retval 1 if \a str parsed to numeric address
- * \retval 0 otherwise
+ * \retval 0 if \a str parsed to numeric address
+ * \retval errno otherwise
*/
static int
-libcfs_num_parse(char *str, int len, cfs_list_t *list)
+libcfs_num_parse(char *str, int len, struct list_head *list)
{
- return num_parse(str, len, list, 0, MAX_NUMERIC_VALUE);
-}
+ struct cfs_expr_list *el;
+ int rc;
-/**
- * Nf_parse_addrlist method for networks using ip addresses.
- *
- * Examples of such networks are tcp and o2ib.
- *
- * \retval 1 if \a str parsed to ip address
- * \retval 0 otherwise
- */
-static int
-libcfs_ip_parse(char *str, int len,
- cfs_list_t *list)
-{
- struct lstr src, res;
- int i;
-
- src.ls_str = str;
- src.ls_len = len;
- i = 0;
- while (src.ls_str) {
- if (gettok(&src, '.', &res) == 0)
- return 0;
- if (!num_parse(res.ls_str, res.ls_len, list, 0, 255))
- return 0;
- i ++;
- }
+ rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
+ if (rc == 0)
+ list_add_tail(&el->el_link, list);
- return (i == 4) ? 1 : 0;
+ return rc;
}
/**
* Allocates struct addrrange and links to \a nidrange via
* (nidrange::nr_addrranges)
*
- * \retval 1 if \a src parses to '*' | \<ipaddr_range\> | \<numaddr_range\>
- * \retval 0 otherwise
+ * \retval 0 if \a src parses to '*' | \<ipaddr_range\> | \<cfs_expr_list\>
+ * \retval -errno otherwise
*/
static int
-parse_addrange(const struct lstr *src, struct nidrange *nidrange)
+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 1;
- }
-
- LIBCFS_ALLOC(addrrange, sizeof(struct addrrange));
- if (addrrange == NULL)
- return 0;
- cfs_list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges);
- CFS_INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges);
-
- return nidrange->nr_netstrfns->nf_parse_addrlist(src->ls_str,
- src->ls_len,
- &addrrange->ar_numaddr_ranges);
+ struct addrrange *addrrange;
+
+ if (src->ls_len == 1 && src->ls_str[0] == '*') {
+ nidrange->nr_all = 1;
+ return 0;
+ }
+
+ LIBCFS_ALLOC(addrrange, sizeof(struct addrrange));
+ if (addrrange == NULL)
+ return -ENOMEM;
+ list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges);
+ INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges);
+
+ return nidrange->nr_netstrfns->nf_parse_addrlist(src->ls_str,
+ src->ls_len,
+ &addrrange->ar_numaddr_ranges);
}
/**
* \retval NULL if \a src does not match any network
*/
static struct nidrange *
-add_nidrange(const struct lstr *src,
- cfs_list_t *nidlist)
+add_nidrange(const struct cfs_lstr *src,
+ struct list_head *nidlist)
{
struct netstrfns *nf;
struct nidrange *nr;
/* e.g. "elan25" or "tcp23", refuse to parse if
* network name is not appended with decimal or
* hexadecimal number */
- if (!libcfs_str2num_check(src->ls_str + strlen(nf->nf_name),
- endlen, &netnum,
- 0, MAX_NUMERIC_VALUE))
+ if (!cfs_str2num_check(src->ls_str + strlen(nf->nf_name),
+ endlen, &netnum, 0, MAX_NUMERIC_VALUE))
return NULL;
}
- cfs_list_for_each_entry(nr, nidlist, nr_link) {
- if (nr->nr_netstrfns != nf)
- continue;
- if (nr->nr_netnum != netnum)
- continue;
- return nr;
- }
-
- LIBCFS_ALLOC(nr, sizeof(struct nidrange));
- if (nr == NULL)
- return NULL;
- cfs_list_add_tail(&nr->nr_link, nidlist);
- CFS_INIT_LIST_HEAD(&nr->nr_addrranges);
- nr->nr_netstrfns = nf;
- nr->nr_all = 0;
- nr->nr_netnum = netnum;
-
- return nr;
+ list_for_each_entry(nr, nidlist, nr_link) {
+ if (nr->nr_netstrfns != nf)
+ continue;
+ if (nr->nr_netnum != netnum)
+ continue;
+ return nr;
+ }
+
+ LIBCFS_ALLOC(nr, sizeof(struct nidrange));
+ if (nr == NULL)
+ return NULL;
+ list_add_tail(&nr->nr_link, nidlist);
+ INIT_LIST_HEAD(&nr->nr_addrranges);
+ nr->nr_netstrfns = nf;
+ nr->nr_all = 0;
+ nr->nr_netnum = netnum;
+
+ return nr;
}
/**
* \retval 0 otherwise
*/
static int
-parse_nidrange(struct lstr *src, cfs_list_t *nidlist)
+parse_nidrange(struct cfs_lstr *src, struct list_head *nidlist)
{
- struct lstr addrrange, net, tmp;
+ struct cfs_lstr addrrange;
+ struct cfs_lstr net;
+ struct cfs_lstr tmp;
struct nidrange *nr;
tmp = *src;
- if (gettok(src, '@', &addrrange) == 0)
+ if (cfs_gettok(src, '@', &addrrange) == 0)
goto failed;
- if (gettok(src, '@', &net) == 0 || src->ls_str != NULL)
+ 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))
+ if (parse_addrange(&addrrange, nr) != 0)
goto failed;
return 1;
}
/**
- * Frees range_expr structures of \a list.
- *
- * \retval none
- */
-static void
-free_range_exprs(cfs_list_t *list)
-{
- cfs_list_t *pos, *next;
-
- cfs_list_for_each_safe(pos, next, list) {
- cfs_list_del(pos);
- LIBCFS_FREE(cfs_list_entry(pos, struct range_expr, re_link),
- sizeof(struct range_expr));
- }
-}
-
-/**
- * Frees numaddr_range structures of \a list.
- *
- * For each struct numaddr_range structure found on \a list it frees
- * range_expr list attached to it and frees the numddr_range itself.
- *
- * \retval none
- */
-static void
-free_numaddr_ranges(cfs_list_t *list)
-{
- cfs_list_t *pos, *next;
- struct numaddr_range *numaddr;
-
- cfs_list_for_each_safe(pos, next, list) {
- numaddr = cfs_list_entry(pos, struct numaddr_range, nar_link);
- free_range_exprs(&numaddr->nar_range_exprs);
- cfs_list_del(pos);
- LIBCFS_FREE(numaddr, sizeof(struct numaddr_range));
- }
-}
-
-/**
* Frees addrrange structures of \a list.
*
* For each struct addrrange structure found on \a list it frees
- * numaddr_range list attached to it and frees the addrrange itself.
+ * cfs_expr_list list attached to it and frees the addrrange itself.
*
* \retval none
*/
static void
-free_addrranges(cfs_list_t *list)
+free_addrranges(struct list_head *list)
{
- cfs_list_t *pos, *next;
- struct addrrange *ar;
-
- cfs_list_for_each_safe(pos, next, list) {
- ar = cfs_list_entry(pos, struct addrrange, ar_link);
- free_numaddr_ranges(&ar->ar_numaddr_ranges);
- cfs_list_del(pos);
- LIBCFS_FREE(ar, sizeof(struct addrrange));
- }
+ while (!list_empty(list)) {
+ struct addrrange *ar;
+
+ ar = list_entry(list->next, struct addrrange, ar_link);
+
+ cfs_expr_list_free_list(&ar->ar_numaddr_ranges);
+ list_del(&ar->ar_link);
+ LIBCFS_FREE(ar, sizeof(struct addrrange));
+ }
}
/**
* \retval none
*/
void
-cfs_free_nidlist(cfs_list_t *list)
+cfs_free_nidlist(struct list_head *list)
{
- cfs_list_t *pos, *next;
- struct nidrange *nr;
-
- cfs_list_for_each_safe(pos, next, list) {
- nr = cfs_list_entry(pos, struct nidrange, nr_link);
- free_addrranges(&nr->nr_addrranges);
- cfs_list_del(pos);
- LIBCFS_FREE(nr, sizeof(struct nidrange));
- }
+ struct list_head *pos, *next;
+ struct nidrange *nr;
+
+ list_for_each_safe(pos, next, list) {
+ nr = list_entry(pos, struct nidrange, nr_link);
+ free_addrranges(&nr->nr_addrranges);
+ list_del(pos);
+ LIBCFS_FREE(nr, sizeof(struct nidrange));
+ }
}
/**
* \retval 0 otherwise
*/
int
-cfs_parse_nidlist(char *str, int len, cfs_list_t *nidlist)
+cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
{
- struct lstr src, res;
- int rc;
- ENTRY;
-
- src.ls_str = str;
- src.ls_len = len;
- CFS_INIT_LIST_HEAD(nidlist);
- while (src.ls_str) {
- rc = 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);
+ 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;
}
-/**
- * Matches address (\a addr) against address set encoded in \a list.
- *
- * \see libcfs_num_match(), libcfs_ip_match()
+/*
+ * Nf_match_addr method for networks using numeric addresses
*
- * \retval 1 if \a addr matches
+ * \retval 1 on match
* \retval 0 otherwise
*/
static int
-match_numaddr(__u32 addr, cfs_list_t *list, int shift, __u32 mask)
+libcfs_num_match(__u32 addr, struct list_head *numaddr)
{
- struct numaddr_range *numaddr;
- struct range_expr *expr;
- int ip, ok;
- ENTRY;
-
- cfs_list_for_each_entry(numaddr, list, nar_link) {
- ip = (addr >> shift) & mask;
- shift -= 8;
- ok = 0;
- cfs_list_for_each_entry(expr, &numaddr->nar_range_exprs,
- re_link) {
- if (ip >= expr->re_lo &&
- ip <= expr->re_hi &&
- ((ip - expr->re_lo) % expr->re_stride) == 0) {
- ok = 1;
- break;
- }
- }
- if (!ok)
- RETURN(0);
- }
- RETURN(1);
+ 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);
}
-/*
- * Nf_match_addr method for networks using numeric addresses
+/**
+ * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
+ *
+ * \see cfs_parse_nidlist()
*
* \retval 1 on match
- * \retval 0 otherwise
+ * \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_match(__u32 addr, cfs_list_t *numaddr)
+libcfs_num_addr_range_print(char *buffer, int count, struct list_head *list)
{
- return match_numaddr(addr, numaddr, 0, 0xffffffff);
+ int i = 0, j = 0;
+ struct cfs_expr_list *el;
+
+ list_for_each_entry(el, list, el_link) {
+ LASSERT(j++ < 1);
+ i += cfs_expr_list_print(buffer + i, count - i, el);
+ }
+ return i;
}
-/*
- * Nf_match_addr method for networks using ip addresses
+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 += cfs_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 1 on match
- * \retval 0 otherwise
+ * \retval number of characters written
*/
static int
-libcfs_ip_match(__u32 addr, cfs_list_t *numaddr)
+cfs_print_network(char *buffer, int count, struct nidrange *nr)
{
- return match_numaddr(addr, numaddr, 24, 0xff);
+ struct netstrfns *nf = nr->nr_netstrfns;
+
+ if (nr->nr_netnum == 0)
+ return cfs_snprintf(buffer, count, "@%s", nf->nf_name);
+ else
+ return cfs_snprintf(buffer, count, "@%s%u",
+ nf->nf_name, nr->nr_netnum);
}
+
/**
- * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
+ * Print a list of addrrange (\a addrranges) into the specified \a buffer.
+ * At max \a count characters can be printed into \a buffer.
*
- * \see cfs_parse_nidlist()
+ * \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 += cfs_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 1 on match
- * \retval 0 otherwises
+ * \retval number of characters written
*/
-int cfs_match_nid(lnet_nid_t nid, cfs_list_t *nidlist)
+int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist)
{
- struct nidrange *nr;
- struct addrrange *ar;
- ENTRY;
-
- cfs_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);
- cfs_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);
+ int i = 0;
+ struct nidrange *nr;
+
+ if (count <= 0)
+ return 0;
+
+ list_for_each_entry(nr, nidlist, nr_link) {
+ if (i != 0)
+ i += cfs_snprintf(buffer + i, count - i, " ");
+
+ if (nr->nr_all != 0) {
+ LASSERT(list_empty(&nr->nr_addrranges));
+ i += cfs_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;
+}
+EXPORT_SYMBOL(cfs_nidrange_is_contiguous);
+
+/**
+ * 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, ¤t_start_nid,
+ ¤t_end_nid);
+ if (last_end_nid != 0 &&
+ (current_start_nid - last_end_nid != 1))
+ return false;
+ last_end_nid = current_end_nid;
+ list_for_each_entry(el, &ar->ar_numaddr_ranges,
+ el_link) {
+ list_for_each_entry(re, &el->el_exprs,
+ re_link) {
+ if (re->re_stride > 1)
+ return false;
+ else if (last_hi != 0 &&
+ re->re_hi - last_hi != 1)
+ return false;
+ last_hi = re->re_hi;
+ }
+ }
+ }
+ }
+
+ 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, ¤t_start_nid,
+ ¤t_end_nid);
+ if (last_end_nid != 0 &&
+ (current_start_nid - last_end_nid != 1))
+ return false;
+ last_end_nid = current_end_nid;
+ list_for_each_entry(el,
+ &ar->ar_numaddr_ranges,
+ el_link) {
+ expr_count = 0;
+ list_for_each_entry(re, &el->el_exprs,
+ re_link) {
+ expr_count++;
+ if (re->re_stride > 1 ||
+ (last_diff > 0 && last_hi != 255) ||
+ (last_diff > 0 && last_hi == 255 &&
+ re->re_lo > 0))
+ return false;
+ last_hi = re->re_hi;
+ last_diff = re->re_hi - re->re_lo;
+ }
+ }
+ }
+ }
+
+ 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, int 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);
+ nf->nf_addr2str(max_addr, 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);
+}
+EXPORT_SYMBOL(cfs_nidrange_find_min_max);
+
+/**
+ * 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;
}
#ifdef __KERNEL__
EXPORT_SYMBOL(libcfs_str2nid);
EXPORT_SYMBOL(libcfs_id2str);
EXPORT_SYMBOL(libcfs_str2anynid);
-EXPORT_SYMBOL(cfs_iswhite);
EXPORT_SYMBOL(cfs_free_nidlist);
EXPORT_SYMBOL(cfs_parse_nidlist);
+EXPORT_SYMBOL(cfs_print_nidlist);
EXPORT_SYMBOL(cfs_match_nid);
#endif