4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, 2017, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
32 * libcfs/libcfs/util/nidstrings.c
34 * Author: Phil Schwan <phil@clusterfs.com>
37 #define DEBUG_SUBSYSTEM S_LNET
46 #include <libcfs/util/string.h>
47 #include <linux/lnet/lnet-types.h>
48 #include <linux/lnet/nidstr.h>
53 /* max value for numeric network address */
54 #define MAX_NUMERIC_VALUE 0xffffffff
56 #define IPSTRING_LENGTH 16
58 /* CAVEAT VENDITOR! Keep the canonical string representation of nets/nids
59 * consistent in all conversion functions. Some code fragments are copied
60 * around for the sake of clarity...
63 /* CAVEAT EMPTOR! Racey temporary buffer allocation!
64 * Choose the number of nidstrings to support the MAXIMUM expected number of
65 * concurrent users. If there are more, the returned string will be volatile.
66 * NB this number must allow for a process to be descheduled for a timeslice
67 * between getting its string and using it.
70 static char libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE];
71 static int libcfs_nidstring_idx;
74 libcfs_next_nidstring(void)
78 str = libcfs_nidstrings[libcfs_nidstring_idx++];
79 if (libcfs_nidstring_idx ==
80 sizeof(libcfs_nidstrings)/sizeof(libcfs_nidstrings[0]))
81 libcfs_nidstring_idx = 0;
87 libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
94 libcfs_ip_addr2str(__u32 addr, char *str, size_t size)
96 snprintf(str, size, "%u.%u.%u.%u",
97 (addr >> 24) & 0xff, (addr >> 16) & 0xff,
98 (addr >> 8) & 0xff, addr & 0xff);
101 /* CAVEAT EMPTOR XscanfX
102 * I use "%n" at the end of a sscanf format to detect trailing junk. However
103 * sscanf may return immediately if it sees the terminating '0' in a string, so
104 * I initialise the %n variable to the expected length. If sscanf sets it;
105 * fine, if it doesn't, then the scan ended at the end of the string, which is
108 libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
114 int n = nob; /* XscanfX */
117 if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
119 (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
120 (c & ~0xff) == 0 && (d & ~0xff) == 0) {
121 *addr = ((a<<24)|(b<<16)|(c<<8)|d);
125 #ifdef HAVE_GETHOSTBYNAME
126 /* known hostname? */
127 if (('a' <= str[0] && str[0] <= 'z') ||
128 ('A' <= str[0] && str[0] <= 'Z')) {
131 tmp = calloc(1, nob + 1);
135 memcpy(tmp, str, nob);
138 he = gethostbyname(tmp);
143 __u32 ip = *(__u32 *)he->h_addr;
155 cfs_ip_addr_parse(char *str, int len, struct list_head *list)
157 struct cfs_expr_list *el;
166 while (src.ls_str != NULL) {
169 if (!cfs_gettok(&src, '.', &res)) {
174 rc = cfs_expr_list_parse(res.ls_str, res.ls_len, 0, 255, &el);
178 list_add_tail(&el->el_link, list);
187 cfs_expr_list_free_list(list);
193 libcfs_ip_addr_range_print(char *buffer, int count, struct list_head *list)
196 struct cfs_expr_list *el;
198 list_for_each_entry(el, list, el_link) {
201 i += snprintf(buffer + i, count - i, ".");
202 i += cfs_expr_list_print(buffer + i, count - i, el);
208 cfs_ip_addr_range_gen_recurse(__u32 *ip_list, int *count, int shift,
209 __u32 result, struct list_head *head_el,
210 struct cfs_expr_list *octet_el)
214 struct cfs_expr_list *next_octet_el;
215 struct cfs_range_expr *octet_expr;
218 * each octet can have multiple expressions so we need to traverse
219 * all of the expressions
221 list_for_each_entry(octet_expr, &octet_el->el_exprs, re_link) {
222 for (i = octet_expr->re_lo; i <= octet_expr->re_hi; i++) {
223 if (((i - octet_expr->re_lo) % octet_expr->re_stride) == 0) {
225 * we have a hit calculate the result and
226 * pass it forward to the next iteration
230 list_entry(octet_el->el_link.next,
231 typeof(*next_octet_el),
233 value = result | (i << (shift * 8));
234 if (next_octet_el->el_link.next != head_el) {
236 * We still have more octets in
237 * the IP address so traverse
238 * that. We're doing a depth first
241 if (cfs_ip_addr_range_gen_recurse(ip_list, count,
244 next_octet_el) == -1)
248 * We have hit a leaf so store the
249 * calculated IP address in the
250 * list. If we have run out of
251 * space stop the recursion.
255 /* add ip to the list */
256 ip_list[*count] = value;
266 * only generate maximum of count ip addresses from the given expression
269 cfs_ip_addr_range_gen(__u32 *ip_list, int count, struct list_head *ip_addr_expr)
271 struct cfs_expr_list *octet_el;
274 octet_el = list_entry(ip_addr_expr->next, typeof(*octet_el), el_link);
276 (void) cfs_ip_addr_range_gen_recurse(ip_list, &idx, 3, 0, &octet_el->el_link, octet_el);
282 * Matches address (\a addr) against address set encoded in \a list.
284 * \retval 1 if \a addr matches
285 * \retval 0 otherwise
288 cfs_ip_addr_match(__u32 addr, struct list_head *list)
290 struct cfs_expr_list *el;
293 list_for_each_entry_reverse(el, list, el_link) {
294 if (!cfs_expr_list_match(addr & 0xff, el))
304 libcfs_decnum_addr2str(__u32 addr, char *str, size_t size)
306 snprintf(str, size, "%u", addr);
310 libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
315 if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
319 if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
323 if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
330 * Nf_parse_addrlist method for networks using numeric addresses.
332 * Examples of such networks are gm and elan.
334 * \retval 0 if \a str parsed to numeric address
335 * \retval errno otherwise
338 libcfs_num_parse(char *str, int len, struct list_head *list)
340 struct cfs_expr_list *el;
343 rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
345 list_add_tail(&el->el_link, list);
351 libcfs_num_addr_range_print(char *buffer, int count, struct list_head *list)
353 struct cfs_expr_list *el;
356 list_for_each_entry(el, list, el_link) {
358 i += cfs_expr_list_print(buffer + i, count - i, el);
364 * Nf_match_addr method for networks using numeric addresses
367 * \retval 0 otherwise
370 libcfs_num_match(__u32 addr, struct list_head *numaddr)
372 struct cfs_expr_list *el;
374 assert(!list_empty(numaddr));
375 el = list_entry(numaddr->next, struct cfs_expr_list, el_link);
377 return cfs_expr_list_match(addr, el);
380 static int cfs_ip_min_max(struct list_head *nidlist, __u32 *min, __u32 *max);
381 static int cfs_num_min_max(struct list_head *nidlist, __u32 *min, __u32 *max);
383 static struct netstrfns libcfs_netstrfns[] = {
387 .nf_modname = "klolnd",
388 .nf_addr2str = libcfs_decnum_addr2str,
389 .nf_str2addr = libcfs_lo_str2addr,
390 .nf_parse_addrlist = libcfs_num_parse,
391 .nf_print_addrlist = libcfs_num_addr_range_print,
392 .nf_match_addr = libcfs_num_match,
393 .nf_min_max = cfs_num_min_max
398 .nf_modname = "ksocklnd",
399 .nf_addr2str = libcfs_ip_addr2str,
400 .nf_str2addr = libcfs_ip_str2addr,
401 .nf_parse_addrlist = cfs_ip_addr_parse,
402 .nf_print_addrlist = libcfs_ip_addr_range_print,
403 .nf_match_addr = cfs_ip_addr_match,
404 .nf_min_max = cfs_ip_min_max
409 .nf_modname = "ko2iblnd",
410 .nf_addr2str = libcfs_ip_addr2str,
411 .nf_str2addr = libcfs_ip_str2addr,
412 .nf_parse_addrlist = cfs_ip_addr_parse,
413 .nf_print_addrlist = libcfs_ip_addr_range_print,
414 .nf_match_addr = cfs_ip_addr_match,
415 .nf_min_max = cfs_ip_min_max
420 .nf_modname = "kgnilnd",
421 .nf_addr2str = libcfs_decnum_addr2str,
422 .nf_str2addr = libcfs_num_str2addr,
423 .nf_parse_addrlist = libcfs_num_parse,
424 .nf_print_addrlist = libcfs_num_addr_range_print,
425 .nf_match_addr = libcfs_num_match,
426 .nf_min_max = cfs_num_min_max
431 .nf_modname = "kgnilnd",
432 .nf_addr2str = libcfs_ip_addr2str,
433 .nf_str2addr = libcfs_ip_str2addr,
434 .nf_parse_addrlist = cfs_ip_addr_parse,
435 .nf_print_addrlist = libcfs_ip_addr_range_print,
436 .nf_match_addr = cfs_ip_addr_match,
437 .nf_min_max = cfs_ip_min_max
442 .nf_modname = "kptl4lnd",
443 .nf_addr2str = libcfs_decnum_addr2str,
444 .nf_str2addr = libcfs_num_str2addr,
445 .nf_parse_addrlist = libcfs_num_parse,
446 .nf_print_addrlist = libcfs_num_addr_range_print,
447 .nf_match_addr = libcfs_num_match,
448 .nf_min_max = cfs_num_min_max
452 static const size_t libcfs_nnetstrfns =
453 sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
455 static struct netstrfns *
456 libcfs_lnd2netstrfns(__u32 lnd)
460 for (i = 0; i < libcfs_nnetstrfns; i++)
461 if (lnd == libcfs_netstrfns[i].nf_type)
462 return &libcfs_netstrfns[i];
467 static struct netstrfns *
468 libcfs_namenum2netstrfns(const char *name)
470 struct netstrfns *nf;
473 for (i = 0; i < libcfs_nnetstrfns; i++) {
474 nf = &libcfs_netstrfns[i];
475 if (!strncmp(name, nf->nf_name, strlen(nf->nf_name)))
481 static struct netstrfns *
482 libcfs_name2netstrfns(const char *name)
486 for (i = 0; i < libcfs_nnetstrfns; i++)
487 if (!strcmp(libcfs_netstrfns[i].nf_name, name))
488 return &libcfs_netstrfns[i];
494 libcfs_isknown_lnd(__u32 lnd)
496 return libcfs_lnd2netstrfns(lnd) != NULL;
500 libcfs_lnd2modname(__u32 lnd)
502 struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
504 return (nf == NULL) ? NULL : nf->nf_modname;
508 libcfs_str2lnd(const char *str)
510 struct netstrfns *nf = libcfs_name2netstrfns(str);
519 libcfs_lnd2str_r(__u32 lnd, char *buf, size_t buf_size)
521 struct netstrfns *nf;
523 nf = libcfs_lnd2netstrfns(lnd);
525 snprintf(buf, buf_size, "?%u?", lnd);
527 snprintf(buf, buf_size, "%s", nf->nf_name);
533 libcfs_net2str_r(__u32 net, char *buf, size_t buf_size)
535 __u32 nnum = LNET_NETNUM(net);
536 __u32 lnd = LNET_NETTYP(net);
537 struct netstrfns *nf;
539 nf = libcfs_lnd2netstrfns(lnd);
541 snprintf(buf, buf_size, "<%u:%u>", lnd, nnum);
543 snprintf(buf, buf_size, "%s", nf->nf_name);
545 snprintf(buf, buf_size, "%s%u", nf->nf_name, nnum);
551 libcfs_nid2str_r(lnet_nid_t nid, char *buf, size_t buf_size)
553 __u32 addr = LNET_NIDADDR(nid);
554 __u32 net = LNET_NIDNET(nid);
555 __u32 nnum = LNET_NETNUM(net);
556 __u32 lnd = LNET_NETTYP(net);
557 struct netstrfns *nf;
559 if (nid == LNET_NID_ANY) {
560 strncpy(buf, "<?>", buf_size);
561 buf[buf_size - 1] = '\0';
565 nf = libcfs_lnd2netstrfns(lnd);
567 snprintf(buf, buf_size, "%x@<%u:%u>", addr, lnd, nnum);
571 nf->nf_addr2str(addr, buf, buf_size);
572 addr_len = strlen(buf);
574 snprintf(buf + addr_len, buf_size - addr_len, "@%s",
577 snprintf(buf + addr_len, buf_size - addr_len, "@%s%u",
584 static struct netstrfns *
585 libcfs_str2net_internal(const char *str, __u32 *net)
587 struct netstrfns *nf = NULL;
592 for (i = 0; i < libcfs_nnetstrfns; i++) {
593 nf = &libcfs_netstrfns[i];
594 if (!strncmp(str, nf->nf_name, strlen(nf->nf_name)))
598 if (i == libcfs_nnetstrfns)
601 nob = strlen(nf->nf_name);
603 if (strlen(str) == (unsigned int)nob) {
606 if (nf->nf_type == LOLND) /* net number not allowed */
611 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
612 i != (int)strlen(str))
616 *net = LNET_MKNET(nf->nf_type, netnum);
621 libcfs_str2net(const char *str)
625 if (libcfs_str2net_internal(str, &net) != NULL)
628 return LNET_NIDNET(LNET_NID_ANY);
632 libcfs_str2nid(const char *str)
634 const char *sep = strchr(str, '@');
635 struct netstrfns *nf;
640 nf = libcfs_str2net_internal(sep + 1, &net);
644 sep = str + strlen(str);
645 net = LNET_MKNET(SOCKLND, 0);
646 nf = libcfs_lnd2netstrfns(SOCKLND);
650 if (!nf->nf_str2addr(str, (int)(sep - str), &addr))
653 return LNET_MKNID(net, addr);
657 libcfs_id2str(struct lnet_process_id id)
659 char *str = libcfs_next_nidstring();
661 if (id.pid == LNET_PID_ANY) {
662 snprintf(str, LNET_NIDSTR_SIZE,
663 "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
667 snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
668 ((id.pid & LNET_PID_USERFLAG) != 0) ? "U" : "",
669 (id.pid & ~LNET_PID_USERFLAG), libcfs_nid2str(id.nid));
674 libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
676 if (!strcmp(str, "*")) {
677 *nidp = LNET_NID_ANY;
681 *nidp = libcfs_str2nid(str);
682 return *nidp != LNET_NID_ANY;
686 * Nid range list syntax.
689 * <nidlist> :== <nidrange> [ ' ' <nidrange> ]
690 * <nidrange> :== <addrrange> '@' <net>
691 * <addrrange> :== '*' |
694 * <ipaddr_range> :== <cfs_expr_list>.<cfs_expr_list>.<cfs_expr_list>.
696 * <cfs_expr_list> :== <number> |
698 * <expr_list> :== '[' <range_expr> [ ',' <range_expr>] ']'
699 * <range_expr> :== <number> |
700 * <number> '-' <number> |
701 * <number> '-' <number> '/' <number>
702 * <net> :== <netname> | <netname><number>
703 * <netname> :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" |
704 * "vib" | "ra" | "elan" | "mx" | "ptl"
709 * Structure to represent \<nidrange\> token of the syntax.
711 * One of this is created for each \<net\> parsed.
715 * Link to list of this structures which is built on nid range
718 struct list_head nr_link;
720 * List head for addrrange::ar_link.
722 struct list_head nr_addrranges;
724 * Flag indicating that *@<net> is found.
728 * Pointer to corresponding element of libcfs_netstrfns.
730 struct netstrfns *nr_netstrfns;
732 * Number of network. E.g. 5 if \<net\> is "elan5".
738 * Structure to represent \<addrrange\> token of the syntax.
742 * Link to nidrange::nr_addrranges.
744 struct list_head ar_link;
746 * List head for cfs_expr_list::el_list.
748 struct list_head ar_numaddr_ranges;
752 * Parses \<addrrange\> token on the syntax.
754 * Allocates struct addrrange and links to \a nidrange via
755 * (nidrange::nr_addrranges)
757 * \retval 0 if \a src parses to '*' | \<ipaddr_range\> | \<cfs_expr_list\>
758 * \retval -errno otherwise
761 parse_addrange(const struct cfs_lstr *src, struct nidrange *nidrange)
763 struct addrrange *addrrange;
765 if (src->ls_len == 1 && src->ls_str[0] == '*') {
766 nidrange->nr_all = 1;
770 addrrange = calloc(1, sizeof(struct addrrange));
771 if (addrrange == NULL)
773 list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges);
774 INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges);
776 return nidrange->nr_netstrfns->nf_parse_addrlist(src->ls_str,
778 &addrrange->ar_numaddr_ranges);
782 * Finds or creates struct nidrange.
784 * Checks if \a src is a valid network name, looks for corresponding
785 * nidrange on the ist of nidranges (\a nidlist), creates new struct
786 * nidrange if it is not found.
788 * \retval pointer to struct nidrange matching network specified via \a src
789 * \retval NULL if \a src does not match any network
791 static struct nidrange *
792 add_nidrange(const struct cfs_lstr *src,
793 struct list_head *nidlist)
795 struct netstrfns *nf;
800 if (src->ls_len >= LNET_NIDSTR_SIZE)
803 nf = libcfs_namenum2netstrfns(src->ls_str);
806 endlen = src->ls_len - strlen(nf->nf_name);
808 /* network name only, e.g. "elan" or "tcp" */
811 /* e.g. "elan25" or "tcp23", refuse to parse if
812 * network name is not appended with decimal or
813 * hexadecimal number */
814 if (!cfs_str2num_check(src->ls_str + strlen(nf->nf_name),
815 endlen, &netnum, 0, MAX_NUMERIC_VALUE))
819 list_for_each_entry(nr, nidlist, nr_link) {
820 if (nr->nr_netstrfns != nf)
822 if (nr->nr_netnum != netnum)
827 nr = calloc(1, sizeof(struct nidrange));
830 list_add_tail(&nr->nr_link, nidlist);
831 INIT_LIST_HEAD(&nr->nr_addrranges);
832 nr->nr_netstrfns = nf;
834 nr->nr_netnum = netnum;
840 * Parses \<nidrange\> token of the syntax.
842 * \retval 1 if \a src parses to \<addrrange\> '@' \<net\>
843 * \retval 0 otherwise
846 parse_nidrange(struct cfs_lstr *src, struct list_head *nidlist)
848 struct cfs_lstr addrrange;
854 if (cfs_gettok(src, '@', &addrrange) == 0)
857 if (cfs_gettok(src, '@', &net) == 0 || src->ls_str != NULL)
860 nr = add_nidrange(&net, nidlist);
864 if (parse_addrange(&addrrange, nr) != 0)
869 fprintf(stderr, "can't parse nidrange: \"%.*s\"\n",
870 tmp.ls_len, tmp.ls_str);
875 * Frees addrrange structures of \a list.
877 * For each struct addrrange structure found on \a list it frees
878 * cfs_expr_list list attached to it and frees the addrrange itself.
883 free_addrranges(struct list_head *list)
885 while (!list_empty(list)) {
886 struct addrrange *ar;
888 ar = list_entry(list->next, struct addrrange, ar_link);
890 cfs_expr_list_free_list(&ar->ar_numaddr_ranges);
891 list_del(&ar->ar_link);
897 * Frees nidrange strutures of \a list.
899 * For each struct nidrange structure found on \a list it frees
900 * addrrange list attached to it and frees the nidrange itself.
905 cfs_free_nidlist(struct list_head *list)
907 struct list_head *pos, *next;
910 list_for_each_safe(pos, next, list) {
911 nr = list_entry(pos, struct nidrange, nr_link);
912 free_addrranges(&nr->nr_addrranges);
919 * Parses nid range list.
921 * Parses with rigorous syntax and overflow checking \a str into
922 * \<nidrange\> [ ' ' \<nidrange\> ], compiles \a str into set of
923 * structures and links that structure to \a nidlist. The resulting
924 * list can be used to match a NID againts set of NIDS defined by \a
928 * \retval 1 on success
929 * \retval 0 otherwise
932 cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
940 INIT_LIST_HEAD(nidlist);
942 rc = cfs_gettok(&src, ' ', &res);
944 cfs_free_nidlist(nidlist);
947 rc = parse_nidrange(&res, nidlist);
949 cfs_free_nidlist(nidlist);
957 * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
959 * \see cfs_parse_nidlist()
962 * \retval 0 otherwises
964 int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist)
967 struct addrrange *ar;
969 list_for_each_entry(nr, nidlist, nr_link) {
970 if (nr->nr_netstrfns->nf_type != LNET_NETTYP(LNET_NIDNET(nid)))
972 if (nr->nr_netnum != LNET_NETNUM(LNET_NIDNET(nid)))
976 list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
977 if (nr->nr_netstrfns->nf_match_addr(LNET_NIDADDR(nid),
978 &ar->ar_numaddr_ranges))
985 * Print the network part of the nidrange \a nr into the specified \a buffer.
987 * \retval number of characters written
990 cfs_print_network(char *buffer, int count, struct nidrange *nr)
992 struct netstrfns *nf = nr->nr_netstrfns;
994 if (nr->nr_netnum == 0)
995 return snprintf(buffer, count, "@%s", nf->nf_name);
997 return snprintf(buffer, count, "@%s%u",
998 nf->nf_name, nr->nr_netnum);
1003 * Print a list of addrrange (\a addrranges) into the specified \a buffer.
1004 * At max \a count characters can be printed into \a buffer.
1006 * \retval number of characters written
1009 cfs_print_addrranges(char *buffer, int count, struct list_head *addrranges,
1010 struct nidrange *nr)
1013 struct addrrange *ar;
1014 struct netstrfns *nf = nr->nr_netstrfns;
1016 list_for_each_entry(ar, addrranges, ar_link) {
1018 i += snprintf(buffer + i, count - i, " ");
1019 i += nf->nf_print_addrlist(buffer + i, count - i,
1020 &ar->ar_numaddr_ranges);
1021 i += cfs_print_network(buffer + i, count - i, nr);
1027 * Print a list of nidranges (\a nidlist) into the specified \a buffer.
1028 * At max \a count characters can be printed into \a buffer.
1029 * Nidranges are separated by a space character.
1031 * \retval number of characters written
1033 int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist)
1036 struct nidrange *nr;
1041 list_for_each_entry(nr, nidlist, nr_link) {
1043 i += snprintf(buffer + i, count - i, " ");
1045 if (nr->nr_all != 0) {
1046 assert(list_empty(&nr->nr_addrranges));
1047 i += snprintf(buffer + i, count - i, "*");
1048 i += cfs_print_network(buffer + i, count - i, nr);
1050 i += cfs_print_addrranges(buffer + i, count - i,
1051 &nr->nr_addrranges, nr);
1058 * Determines minimum and maximum addresses for a single
1059 * numeric address range
1062 * \param[out] *min_nid __u32 representation of min NID
1063 * \param[out] *max_nid __u32 representation of max NID
1064 * \retval -EINVAL unsupported LNET range
1065 * \retval -ERANGE non-contiguous LNET range
1067 static int cfs_ip_ar_min_max(struct addrrange *ar, __u32 *min_nid,
1070 struct cfs_expr_list *expr_list;
1071 struct cfs_range_expr *range;
1072 unsigned int min_ip[4] = {0};
1073 unsigned int max_ip[4] = {0};
1075 bool expect_full_octet = false;
1077 list_for_each_entry(expr_list, &ar->ar_numaddr_ranges, el_link) {
1080 list_for_each_entry(range, &expr_list->el_exprs, re_link) {
1081 /* XXX: add support for multiple & non-contig. re's */
1085 /* if a previous octet was ranged, then all remaining
1086 * octets must be full for contiguous range */
1087 if (expect_full_octet && (range->re_lo != 0 ||
1088 range->re_hi != 255))
1091 if (range->re_stride != 1)
1094 if (range->re_lo > range->re_hi)
1097 if (range->re_lo != range->re_hi)
1098 expect_full_octet = true;
1100 min_ip[cur_octet] = range->re_lo;
1101 max_ip[cur_octet] = range->re_hi;
1109 if (min_nid != NULL)
1110 *min_nid = ((min_ip[0] << 24) | (min_ip[1] << 16) |
1111 (min_ip[2] << 8) | min_ip[3]);
1113 if (max_nid != NULL)
1114 *max_nid = ((max_ip[0] << 24) | (max_ip[1] << 16) |
1115 (max_ip[2] << 8) | max_ip[3]);
1121 * Determines minimum and maximum addresses for a single
1122 * numeric address range
1125 * \param[out] *min_nid __u32 representation of min NID
1126 * \param[out] *max_nid __u32 representation of max NID
1127 * \retval -EINVAL unsupported LNET range
1129 static int cfs_num_ar_min_max(struct addrrange *ar, __u32 *min_nid,
1132 struct cfs_expr_list *el;
1133 struct cfs_range_expr *re;
1134 unsigned int min_addr = 0;
1135 unsigned int max_addr = 0;
1137 list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) {
1140 list_for_each_entry(re, &el->el_exprs, re_link) {
1143 if (re->re_lo > re->re_hi)
1146 if (re->re_lo < min_addr || min_addr == 0)
1147 min_addr = re->re_lo;
1148 if (re->re_hi > max_addr)
1149 max_addr = re->re_hi;
1155 if (min_nid != NULL)
1156 *min_nid = min_addr;
1157 if (max_nid != NULL)
1158 *max_nid = max_addr;
1164 * Takes a linked list of nidrange expressions, determines the minimum
1165 * and maximum nid and creates appropriate nid structures
1168 * \param[out] *min_nid string representation of min NID
1169 * \param[out] *max_nid string representation of max NID
1170 * \retval -EINVAL unsupported LNET range
1171 * \retval -ERANGE non-contiguous LNET range
1173 int cfs_nidrange_find_min_max(struct list_head *nidlist, char *min_nid,
1174 char *max_nid, size_t nidstr_length)
1176 struct nidrange *first_nidrange;
1178 struct netstrfns *nf;
1182 char min_addr_str[IPSTRING_LENGTH];
1183 char max_addr_str[IPSTRING_LENGTH];
1186 first_nidrange = list_entry(nidlist->next, struct nidrange, nr_link);
1188 netnum = first_nidrange->nr_netnum;
1189 nf = first_nidrange->nr_netstrfns;
1190 lndname = nf->nf_name;
1192 rc = nf->nf_min_max(nidlist, &min_addr, &max_addr);
1196 nf->nf_addr2str(min_addr, min_addr_str, sizeof(min_addr_str));
1197 nf->nf_addr2str(max_addr, max_addr_str, sizeof(max_addr_str));
1199 snprintf(min_nid, nidstr_length, "%s@%s%d", min_addr_str, lndname,
1201 snprintf(max_nid, nidstr_length, "%s@%s%d", max_addr_str, lndname,
1208 * Determines the min and max NID values for num LNDs
1211 * \param[out] *min_nid if provided, returns string representation of min NID
1212 * \param[out] *max_nid if provided, returns string representation of max NID
1213 * \retval -EINVAL unsupported LNET range
1214 * \retval -ERANGE non-contiguous LNET range
1216 static int cfs_num_min_max(struct list_head *nidlist, __u32 *min_nid,
1219 struct nidrange *nr;
1220 struct addrrange *ar;
1221 unsigned int tmp_min_addr = 0;
1222 unsigned int tmp_max_addr = 0;
1223 unsigned int min_addr = 0;
1224 unsigned int max_addr = 0;
1225 int nidlist_count = 0;
1228 list_for_each_entry(nr, nidlist, nr_link) {
1229 if (nidlist_count > 0)
1232 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1233 rc = cfs_num_ar_min_max(ar, &tmp_min_addr,
1238 if (tmp_min_addr < min_addr || min_addr == 0)
1239 min_addr = tmp_min_addr;
1240 if (tmp_max_addr > max_addr)
1241 max_addr = tmp_min_addr;
1244 if (max_nid != NULL)
1245 *max_nid = max_addr;
1246 if (min_nid != NULL)
1247 *min_nid = min_addr;
1253 * Takes an nidlist and determines the minimum and maximum
1257 * \param[out] *min_nid if provided, returns string representation of min NID
1258 * \param[out] *max_nid if provided, returns string representation of max NID
1259 * \retval -EINVAL unsupported LNET range
1260 * \retval -ERANGE non-contiguous LNET range
1262 static int cfs_ip_min_max(struct list_head *nidlist, __u32 *min_nid,
1265 struct nidrange *nr;
1266 struct addrrange *ar;
1267 __u32 tmp_min_ip_addr = 0;
1268 __u32 tmp_max_ip_addr = 0;
1269 __u32 min_ip_addr = 0;
1270 __u32 max_ip_addr = 0;
1271 int nidlist_count = 0;
1274 list_for_each_entry(nr, nidlist, nr_link) {
1275 if (nidlist_count > 0)
1280 max_ip_addr = 0xffffffff;
1284 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1285 rc = cfs_ip_ar_min_max(ar, &tmp_min_ip_addr,
1290 if (tmp_min_ip_addr < min_ip_addr || min_ip_addr == 0)
1291 min_ip_addr = tmp_min_ip_addr;
1292 if (tmp_max_ip_addr > max_ip_addr)
1293 max_ip_addr = tmp_max_ip_addr;
1299 if (max_nid != NULL)
1300 *max_nid = max_ip_addr;
1301 if (min_nid != NULL)
1302 *min_nid = min_ip_addr;