From: vs Date: Thu, 27 Nov 2008 01:55:35 +0000 (+0000) Subject: Branch HEAD X-Git-Tag: v1_9_120~60 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=320bc2f5e1250948790282e156583ccf98bedc33 Branch HEAD b=12749 i=maxim,isaac First of three patches for the root squash feature This adds three functions to manipulate with lists of NID ranges: cfs_parse_nidlist - parses nid range list and creates structure of lists of [lo,hi,stride,net] which can be used to check matching a NID to set of NIDs cfs_free_nidlist - frees structures allocated on nidlist parsing cfs_match_nid - check whether a NID matches to set of NIDs cfs_iswhite - auxiliary function to check if a character is a whitespace These functions have prefixes cfs_ instead of libcfs_ because of bug #17167. Example of NID range list: 10.2.0.[1-20/2]@tcp [0,2,6]@elan0 [1,2,4-100/4]@elan1 nidlist syntax: :== [ ' ' ] :== '@' :== '*' | | :== ... :== | :== '[' [ ',' ] ']' :== | '-' | '-' '/' :== | :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" | "vib" | "ra" | "elan" | "gm" | "mx" | "ptl" :== | --- diff --git a/libcfs/include/libcfs/libcfs_private.h b/libcfs/include/libcfs/libcfs_private.h index 9e3fe71..a791c32 100644 --- a/libcfs/include/libcfs/libcfs_private.h +++ b/libcfs/include/libcfs/libcfs_private.h @@ -312,6 +312,10 @@ __u32 libcfs_str2net(const char *str); lnet_nid_t libcfs_str2nid(const char *str); int libcfs_str2anynid(lnet_nid_t *nid, const char *str); char *libcfs_id2str(lnet_process_id_t id); +int cfs_iswhite(char c); +void cfs_free_nidlist(struct list_head *list); +int cfs_parse_nidlist(char *str, int len, struct list_head *list); +int cfs_match_nid(lnet_nid_t nid, struct list_head *list); /* how an LNET NID encodes net:address */ #define LNET_NIDADDR(nid) ((__u32)((nid) & 0xffffffff)) @@ -322,6 +326,9 @@ char *libcfs_id2str(lnet_process_id_t id); #define LNET_NETTYP(net) (((net) >> 16) & 0xffff) #define LNET_MKNET(typ,num) ((((__u32)(typ))<<16)|((__u32)(num))) +/* max value for numeric network address */ +#define MAX_NUMERIC_VALUE 0xffffffff + /* implication */ #define ergo(a, b) (!(a) || (b)) /* logical equivalence */ diff --git a/libcfs/libcfs/nidstrings.c b/libcfs/libcfs/nidstrings.c index df02584..28796e7 100644 --- a/libcfs/libcfs/nidstrings.c +++ b/libcfs/libcfs/nidstrings.c @@ -108,6 +108,10 @@ static int libcfs_ip_str2addr(const char *str, int nob, __u32 *addr); 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, struct list_head *list); +static int libcfs_num_parse(char *str, int len, struct list_head *list); +static int libcfs_ip_match(__u32 addr, struct list_head *list); +static int libcfs_num_match(__u32 addr, struct list_head *list); struct netstrfns { int nf_type; @@ -115,6 +119,9 @@ struct netstrfns { 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_match_addr)(__u32 addr, struct list_head *list); }; static struct netstrfns libcfs_netstrfns[] = { @@ -122,62 +129,86 @@ static struct netstrfns libcfs_netstrfns[] = { /* .nf_name */ "lo", /* .nf_modname */ "klolnd", /* .nf_addr2str */ libcfs_decnum_addr2str, - /* .nf_str2addr */ libcfs_lo_str2addr}, + /* .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_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_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_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_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_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_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_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_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_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_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_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}, }; @@ -310,6 +341,21 @@ libcfs_lnd2netstrfns(int lnd) } 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 * libcfs_name2netstrfns(const char *name) { int i; @@ -514,6 +560,708 @@ libcfs_str2anynid(lnet_nid_t *nidp, const char *str) return *nidp != LNET_NID_ANY; } +/** + * Nid range list syntax. + * + * :== [ ' ' ] + * :== '@' + * :== '*' | + * | + * + * :== ... + * + * :== | + * + * :== '[' [ ',' ] ']' + * :== | + * '-' | + * '-' '/' + * :== | + * :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" | + * "vib" | "ra" | "elan" | "gm" | "mx" | "ptl" + */ + +/** + * Structure to represent NULL-less strings. + */ +struct lstr { + char *ls_str; + int ls_len; +}; + +/** + * Structure to represent token of the syntax. + * + * One of this is created for each parsed. + */ +struct nidrange { + /** + * Link to list of this structures which is built on nid range + * list parsing. + */ + struct list_head nr_link; + /** + * List head for addrrange::ar_link. + */ + struct list_head nr_addrranges; + /** + * Flag indicating that *@ is found. + */ + int nr_all; + /** + * Pointer to corresponding element of libcfs_netstrfns. + */ + struct netstrfns *nr_netstrfns; + /** + * Number of network. E.g. 5 if is "elan5". + */ + int nr_netnum; +}; + +/** + * Structure to represent token of the syntax. + */ +struct addrrange { + /** + * Link to nidrange::nr_addrranges. + */ + struct list_head ar_link; + /** + * List head for numaddr_range::nar_link. + */ + struct list_head ar_numaddr_ranges; +}; + +/** + * Structure to represent token of the syntax. + */ +struct numaddr_range { + /** + * Link to addrrange::ar_numaddr_ranges. + */ + struct list_head nar_link; + /** + * List head for range_expr::re_link. + */ + struct list_head nar_range_exprs; +}; + +/** + * Structure to represent token of the syntax. + */ +struct range_expr { + /** + * Link to numaddr_range::nar_range_exprs. + */ + struct list_head 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 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 + * | + * '-' | + * '-' '/' + * \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)) { + /* 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; + /* - */ + if (libcfs_str2num_check(src->ls_str, src->ls_len, &expr->re_hi, + min, max)) { + /* - is parsed */ + expr->re_stride = 1; + return expr; + } + + /* go to check '-' '/' */ + if (gettok(src, '/', &tok)) { + if (!libcfs_str2num_check(tok.ls_str, tok.ls_len, + &expr->re_hi, min, max)) + goto failed; + /* - / ... */ + if (libcfs_str2num_check(src->ls_str, src->ls_len, + &expr->re_stride, min, max)) + /* - / is parsed */ + return expr; + } + +failed: + LIBCFS_FREE(expr, sizeof(struct range_expr)); + return NULL; +} + +/** + * Parsed token of the syntax. + * + * \retval 1 if \a str parses to '[' [ ',' ] ']' + * \return 0 otherwise + */ +static int +parse_expr_list(struct lstr *str, struct list_head *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; + list_add_tail(&range->re_link, list); + } + return 1; +} + +/** + * Parses token of the syntax. + * + * \retval 1 if \a str parses to | + * \retval 0 otherwise + */ +static int +num_parse(char *str, int len, + struct list_head *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; + 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)) { + /* */ + 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; + 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 + */ +static int +libcfs_num_parse(char *str, int len, struct list_head *list) +{ + return num_parse(str, len, list, 0, MAX_NUMERIC_VALUE); +} + +/** + * 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, + struct list_head *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 ++; + } + + return (i == 4) ? 1 : 0; +} + +/** + * Parses token on the syntax. + * + * Allocates struct addrrange and links to \a nidrange via + * (nidrange::nr_addrranges) + * + * \retval 1 if \a src parses to '*' | | + * \retval 0 otherwise + */ +static int +parse_addrange(const struct 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; + 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); +} + +/** + * 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 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 (!libcfs_str2num_check(src->ls_str + strlen(nf->nf_name), + endlen, &netnum, + 0, MAX_NUMERIC_VALUE)) + return NULL; + } + + list_for_each_entry(nr, nidlist, nr_link) { + if (nr->nr_netstrfns != nf) + continue; + if (nr->nr_netnum != netnum) + continue; + return nr; + } + + LIBCFS_ALLOC(nr, sizeof(struct nidrange)); + if (nr == NULL) + return NULL; + list_add_tail(&nr->nr_link, nidlist); + CFS_INIT_LIST_HEAD(&nr->nr_addrranges); + nr->nr_netstrfns = nf; + nr->nr_all = 0; + nr->nr_netnum = netnum; + + return nr; +} + +/** + * Parses token of the syntax. + * + * \retval 1 if \a src parses to '@' + * \retval 0 otherwise + */ +static int +parse_nidrange(struct lstr *src, struct list_head *nidlist) +{ + struct lstr addrrange, net, tmp; + struct nidrange *nr; + + tmp = *src; + if (gettok(src, '@', &addrrange) == 0) + goto failed; + + if (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)) + goto failed; + + return 1; + failed: + CWARN("can't parse nidrange: \"%.*s\"\n", tmp.ls_len, tmp.ls_str); + return 0; +} + +/** + * Frees range_expr structures of \a list. + * + * \retval none + */ +static void +free_range_exprs(struct list_head *list) +{ + struct list_head *pos, *next; + + list_for_each_safe(pos, next, list) { + list_del(pos); + LIBCFS_FREE(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(struct list_head *list) +{ + struct list_head *pos, *next; + struct numaddr_range *numaddr; + + list_for_each_safe(pos, next, list) { + numaddr = list_entry(pos, struct numaddr_range, nar_link); + free_range_exprs(&numaddr->nar_range_exprs); + 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. + * + * \retval none + */ +static void +free_addrranges(struct list_head *list) +{ + struct list_head *pos, *next; + struct addrrange *ar; + + list_for_each_safe(pos, next, list) { + ar = list_entry(pos, struct addrrange, ar_link); + free_numaddr_ranges(&ar->ar_numaddr_ranges); + list_del(pos); + LIBCFS_FREE(ar, sizeof(struct addrrange)); + } +} + +/** + * Frees nidrange strutures of \a list. + * + * For each struct nidrange structure found on \a list it frees + * addrrange list attached to it and frees the nidrange itself. + * + * \retval none + */ +void +cfs_free_nidlist(struct list_head *list) +{ + struct list_head *pos, *next; + struct nidrange *nr; + + list_for_each_safe(pos, next, list) { + nr = list_entry(pos, struct nidrange, nr_link); + free_addrranges(&nr->nr_addrranges); + list_del(pos); + LIBCFS_FREE(nr, sizeof(struct nidrange)); + } +} + +/** + * Parses nid range list. + * + * Parses with rigorous syntax and overflow checking \a str into + * [ ' ' ], 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 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); +} + +/** + * Matches address (\a addr) against address set encoded in \a list. + * + * \see libcfs_num_match(), libcfs_ip_match() + * + * \retval 1 if \a addr matches + * \retval 0 otherwise + */ +static int +match_numaddr(__u32 addr, struct list_head *list, int shift, __u32 mask) +{ + struct numaddr_range *numaddr; + struct range_expr *expr; + int ip, ok; + ENTRY; + + list_for_each_entry(numaddr, list, nar_link) { + ip = (addr >> shift) & mask; + shift -= 8; + ok = 0; + 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); +} + +/* + * 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) +{ + return match_numaddr(addr, numaddr, 0, 0xffffffff); +} + +/* + * Nf_match_addr method for networks using ip addresses + * + * \retval 1 on match + * \retval 0 otherwise + */ +static int +libcfs_ip_match(__u32 addr, struct list_head *numaddr) +{ + return match_numaddr(addr, numaddr, 24, 0xff); +} + +/** + * 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; + ENTRY; + + 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); +} + #ifdef __KERNEL__ EXPORT_SYMBOL(libcfs_isknown_lnd); @@ -526,5 +1274,9 @@ EXPORT_SYMBOL(libcfs_str2net); 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_match_nid); #endif diff --git a/lnet/lnet/config.c b/lnet/lnet/config.c index 43303dd..45bd89f 100644 --- a/lnet/lnet/config.c +++ b/lnet/lnet/config.c @@ -86,31 +86,17 @@ lnet_issep (char c) } } -int -lnet_iswhite (char c) -{ - switch (c) { - case ' ': - case '\t': - case '\n': - case '\r': - return 1; - default: - return 0; - } -} - char * lnet_trimwhite(char *str) { char *end; - while (lnet_iswhite(*str)) + while (cfs_iswhite(*str)) str++; end = str + strlen(str); while (end > str) { - if (!lnet_iswhite(end[-1])) + if (!cfs_iswhite(end[-1])) break; end--; } @@ -394,7 +380,7 @@ lnet_str2tbs_sep (struct list_head *tbs, char *str) /* Split 'str' into separate commands */ for (;;) { /* skip leading whitespace */ - while (lnet_iswhite(*str)) + while (cfs_iswhite(*str)) str++; /* scan for separator or comment */ @@ -411,7 +397,7 @@ lnet_str2tbs_sep (struct list_head *tbs, char *str) } for (i = 0; i < nob; i++) - if (lnet_iswhite(str[i])) + if (cfs_iswhite(str[i])) ltb->ltb_text[i] = ' '; else ltb->ltb_text[i] = str[i]; @@ -586,7 +572,7 @@ lnet_parse_route (char *str, int *im_a_router) sep = str; for (;;) { /* scan for token start */ - while (lnet_iswhite(*sep)) + while (cfs_iswhite(*sep)) sep++; if (*sep == 0) { if (ntokens < (got_hops ? 3 : 2)) @@ -598,7 +584,7 @@ lnet_parse_route (char *str, int *im_a_router) token = sep++; /* scan for token end */ - while (*sep != 0 && !lnet_iswhite(*sep)) + while (*sep != 0 && !cfs_iswhite(*sep)) sep++; if (*sep != 0) *sep++ = 0; @@ -946,7 +932,7 @@ lnet_match_network_tokens(char *net_entry, __u32 *ipaddrs, int nip) sep = tokens; for (;;) { /* scan for token start */ - while (lnet_iswhite(*sep)) + while (cfs_iswhite(*sep)) sep++; if (*sep == 0) break; @@ -954,7 +940,7 @@ lnet_match_network_tokens(char *net_entry, __u32 *ipaddrs, int nip) token = sep++; /* scan for token end */ - while (*sep != 0 && !lnet_iswhite(*sep)) + while (*sep != 0 && !cfs_iswhite(*sep)) sep++; if (*sep != 0) *sep++ = 0;