Whamcloud - gitweb
LU-14487 libcfs: remove references to Sun Trademark.
[fs/lustre-release.git] / libcfs / libcfs / util / nidstrings.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
9  *
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).
15  *
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
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  *
31  * libcfs/libcfs/util/nidstrings.c
32  *
33  * Author: Phil Schwan <phil@clusterfs.com>
34  */
35
36 #define DEBUG_SUBSYSTEM S_LNET
37
38 #include <assert.h>
39 #include <errno.h>
40 #include <stdio.h>
41 #include <stdbool.h>
42 #include <stdlib.h>
43 #include <string.h>
44
45 #include <libcfs/util/string.h>
46 #include <linux/lnet/lnet-types.h>
47 #include <linux/lnet/nidstr.h>
48 #ifdef HAVE_NETDB_H
49 # include <netdb.h>
50 #endif
51
52 /* max value for numeric network address */
53 #define MAX_NUMERIC_VALUE 0xffffffff
54
55 #define IPSTRING_LENGTH 16
56
57 /* CAVEAT VENDITOR! Keep the canonical string representation of nets/nids
58  * consistent in all conversion functions.  Some code fragments are copied
59  * around for the sake of clarity...
60  */
61
62 /* CAVEAT EMPTOR! Racey temporary buffer allocation!
63  * Choose the number of nidstrings to support the MAXIMUM expected number of
64  * concurrent users.  If there are more, the returned string will be volatile.
65  * NB this number must allow for a process to be descheduled for a timeslice
66  * between getting its string and using it.
67  */
68
69 static char      libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE];
70 static int       libcfs_nidstring_idx;
71
72 char *
73 libcfs_next_nidstring(void)
74 {
75         char          *str;
76
77         str = libcfs_nidstrings[libcfs_nidstring_idx++];
78         if (libcfs_nidstring_idx ==
79             sizeof(libcfs_nidstrings)/sizeof(libcfs_nidstrings[0]))
80                 libcfs_nidstring_idx = 0;
81
82         return str;
83 }
84
85 static int
86 libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
87 {
88         *addr = 0;
89         return 1;
90 }
91
92 static void
93 libcfs_ip_addr2str(__u32 addr, char *str, size_t size)
94 {
95         snprintf(str, size, "%u.%u.%u.%u",
96                  (addr >> 24) & 0xff, (addr >> 16) & 0xff,
97                  (addr >> 8) & 0xff, addr & 0xff);
98 }
99
100 /* CAVEAT EMPTOR XscanfX
101  * I use "%n" at the end of a sscanf format to detect trailing junk.  However
102  * sscanf may return immediately if it sees the terminating '0' in a string, so
103  * I initialise the %n variable to the expected length.  If sscanf sets it;
104  * fine, if it doesn't, then the scan ended at the end of the string, which is
105  * fine too :) */
106 static int
107 libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
108 {
109         unsigned int    a;
110         unsigned int    b;
111         unsigned int    c;
112         unsigned int    d;
113         int             n = nob; /* XscanfX */
114
115         /* numeric IP? */
116         if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
117             n == nob &&
118             (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
119             (c & ~0xff) == 0 && (d & ~0xff) == 0) {
120                 *addr = ((a<<24)|(b<<16)|(c<<8)|d);
121                 return 1;
122         }
123
124 #ifdef HAVE_GETHOSTBYNAME
125         /* known hostname? */
126         if (('a' <= str[0] && str[0] <= 'z') ||
127             ('A' <= str[0] && str[0] <= 'Z')) {
128                 char *tmp;
129
130                 tmp = calloc(1, nob + 1);
131                 if (tmp != NULL) {
132                         struct hostent *he;
133
134                         memcpy(tmp, str, nob);
135                         tmp[nob] = 0;
136
137                         he = gethostbyname(tmp);
138
139                         free(tmp);
140
141                         if (he != NULL) {
142                                 __u32 ip = *(__u32 *)he->h_addr;
143
144                                 *addr = ntohl(ip);
145                                 return 1;
146                         }
147                 }
148         }
149 #endif
150         return 0;
151 }
152
153 int
154 cfs_ip_addr_parse(char *str, int len, struct list_head *list)
155 {
156         struct cfs_expr_list *el;
157         struct cfs_lstr src;
158         int rc;
159         int i;
160
161         src.ls_str = str;
162         src.ls_len = len;
163         i = 0;
164
165         while (src.ls_str != NULL) {
166                 struct cfs_lstr res;
167
168                 if (!cfs_gettok(&src, '.', &res)) {
169                         rc = -EINVAL;
170                         goto out;
171                 }
172
173                 rc = cfs_expr_list_parse(res.ls_str, res.ls_len, 0, 255, &el);
174                 if (rc != 0)
175                         goto out;
176
177                 list_add_tail(&el->el_link, list);
178                 i++;
179         }
180
181         if (i == 4)
182                 return 0;
183
184         rc = -EINVAL;
185 out:
186         cfs_expr_list_free_list(list);
187
188         return rc;
189 }
190
191 int
192 cfs_expr2str(struct list_head *list, char *str, size_t size)
193 {
194         struct cfs_expr_list *expr;
195         struct cfs_range_expr *range;
196         char tmp[LNET_NIDSTR_SIZE];
197         size_t len;
198         bool first;
199         bool bracket = false;
200         char *format;
201         char *tmpc;
202
203         list_for_each_entry(expr, list, el_link) {
204                 first = true;
205                 list_for_each_entry(range, &expr->el_exprs, re_link) {
206                         if (range->re_lo == range->re_hi) {
207                                 snprintf(tmp,
208                                          LNET_NIDSTR_SIZE,
209                                          "%u.", range->re_lo);
210                         } else if (range->re_lo < range->re_hi) {
211                                 if (range->re_stride > 1) {
212                                         if (first)
213                                                 format = "[%u-%u/%u,";
214                                         else
215                                                 format = "%u-%u/%u,";
216                                         snprintf(tmp, LNET_NIDSTR_SIZE,
217                                                 format, range->re_lo,
218                                                 range->re_hi, range->re_stride);
219                                         bracket = true;
220                                 } else {
221                                         if (first)
222                                                 format = "[%u-%u,";
223                                         else
224                                                 format = "%u-%u,";
225                                         snprintf(tmp, LNET_NIDSTR_SIZE,
226                                                 format, range->re_lo,
227                                                 range->re_hi);
228                                         bracket = true;
229                                 }
230                         } else {
231                                 return -EINVAL;
232                         }
233                         len = strlen(tmp);
234                         size -= (len + 1);
235                         if (size < 0)
236                                 return -ENOBUFS;
237
238                         strncat(str, tmp, size + len);
239                         first = false;
240                 }
241                 if (bracket) {
242                         tmpc = str + (strlen(str) - 1);
243                         size -= 1;
244                         if (size < 0)
245                                 return -ENOBUFS;
246                         *tmpc = ']';
247                         *(tmpc+1) = '.';
248                         bracket = false;
249                 }
250         }
251
252         /*
253          * get rid of the trailing '.' at the end of the string
254          * only if we actually had something on the list passed in.
255          * otherwise we could write outside the array
256          */
257         if (!list_empty(list))
258                 str[strlen(str)-1] = '\0';
259         return size;
260 }
261
262 static int
263 libcfs_num_addr_range_expand(struct list_head *addrranges, __u32 *addrs,
264                              int max_addrs)
265 {
266         struct cfs_expr_list *expr_list;
267         struct cfs_range_expr *range;
268         int i;
269         int max_idx = max_addrs - 1;
270         int addrs_idx = max_idx;
271
272         list_for_each_entry(expr_list, addrranges, el_link) {
273                 list_for_each_entry(range, &expr_list->el_exprs, re_link) {
274                         for (i = range->re_lo; i <= range->re_hi;
275                              i += range->re_stride) {
276                                 if (addrs_idx < 0)
277                                         return -1;
278
279                                 addrs[addrs_idx] = i;
280                                 addrs_idx--;
281                         }
282                 }
283         }
284
285         return max_idx - addrs_idx;
286 }
287
288 static int
289 libcfs_ip_addr_range_expand(struct list_head *addrranges, __u32 *addrs,
290                             int max_addrs)
291 {
292         int rc = 0;
293
294         rc = cfs_ip_addr_range_gen(addrs, max_addrs, addrranges);
295
296         if (rc == -1)
297                 return rc;
298         else
299                 return max_addrs - rc - 1;
300 }
301
302 static int
303 libcfs_ip_addr_range_print(char *buffer, int count, struct list_head *list)
304 {
305         int i = 0, j = 0;
306         struct cfs_expr_list *el;
307
308         list_for_each_entry(el, list, el_link) {
309                 assert(j++ < 4);
310                 if (i != 0)
311                         i += scnprintf(buffer + i, count - i, ".");
312                 i += cfs_expr_list_print(buffer + i, count - i, el);
313         }
314         return i;
315 }
316
317 static int
318 cfs_ip_addr_range_gen_recurse(__u32 *ip_list, int *count, int shift,
319                               __u32 result, struct list_head *head_el,
320                               struct cfs_expr_list *octet_el)
321 {
322         __u32 value = 0;
323         int i;
324         struct cfs_expr_list *next_octet_el;
325         struct cfs_range_expr *octet_expr;
326
327         /*
328          * each octet can have multiple expressions so we need to traverse
329          * all of the expressions
330          */
331         list_for_each_entry(octet_expr, &octet_el->el_exprs, re_link) {
332                 for (i = octet_expr->re_lo; i <= octet_expr->re_hi; i++) {
333                         if (((i - octet_expr->re_lo) % octet_expr->re_stride) == 0) {
334                                 /*
335                                  * we have a hit calculate the result and
336                                  * pass it forward to the next iteration
337                                  * of the recursion.
338                                  */
339                                 next_octet_el =
340                                         list_entry(octet_el->el_link.next,
341                                                         typeof(*next_octet_el),
342                                                         el_link);
343                                 value = result | (i << (shift * 8));
344                                 if (next_octet_el->el_link.next != head_el) {
345                                         /*
346                                          * We still have more octets in
347                                          * the IP address so traverse
348                                          * that. We're doing a depth first
349                                          * recursion here.
350                                          */
351                                         if (cfs_ip_addr_range_gen_recurse(ip_list, count,
352                                                                           shift - 1, value,
353                                                                           head_el,
354                                                                           next_octet_el) == -1)
355                                                 return -1;
356                                 } else {
357                                         /*
358                                          * We have hit a leaf so store the
359                                          * calculated IP address in the
360                                          * list. If we have run out of
361                                          * space stop the recursion.
362                                          */
363                                         if (*count == -1)
364                                                 return -1;
365                                         /* add ip to the list */
366                                         ip_list[*count] = value;
367                                         (*count)--;
368                                 }
369                         }
370                 }
371         }
372         return 0;
373 }
374
375 /*
376  * only generate maximum of count ip addresses from the given expression
377  */
378 int
379 cfs_ip_addr_range_gen(__u32 *ip_list, int count, struct list_head *ip_addr_expr)
380 {
381         struct cfs_expr_list *octet_el;
382         int idx = count - 1;
383
384         octet_el = list_entry(ip_addr_expr->next, typeof(*octet_el), el_link);
385
386         (void) cfs_ip_addr_range_gen_recurse(ip_list, &idx, 3, 0, &octet_el->el_link, octet_el);
387
388         return idx;
389 }
390
391 /**
392  * Matches address (\a addr) against address set encoded in \a list.
393  *
394  * \retval 1 if \a addr matches
395  * \retval 0 otherwise
396  */
397 int
398 cfs_ip_addr_match(__u32 addr, struct list_head *list)
399 {
400         struct cfs_expr_list *el;
401         int i = 0;
402
403         list_for_each_entry_reverse(el, list, el_link) {
404                 if (!cfs_expr_list_match(addr & 0xff, el))
405                         return 0;
406                 addr >>= 8;
407                 i++;
408         }
409
410         return i == 4;
411 }
412
413 static void
414 libcfs_decnum_addr2str(__u32 addr, char *str, size_t size)
415 {
416         snprintf(str, size, "%u", addr);
417 }
418
419 static int
420 libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
421 {
422         int     n;
423
424         n = nob;
425         if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
426                 return 1;
427
428         n = nob;
429         if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
430                 return 1;
431
432         n = nob;
433         if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
434                 return 1;
435
436         return 0;
437 }
438
439 /**
440  * Nf_parse_addrlist method for networks using numeric addresses.
441  *
442  * Examples of such networks are gm and elan.
443  *
444  * \retval 0 if \a str parsed to numeric address
445  * \retval errno otherwise
446  */
447 int
448 libcfs_num_parse(char *str, int len, struct list_head *list)
449 {
450         struct cfs_expr_list *el;
451         int     rc;
452
453         rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
454         if (rc == 0)
455                 list_add_tail(&el->el_link, list);
456
457         return rc;
458 }
459
460 static int
461 libcfs_num_addr_range_print(char *buffer, int count, struct list_head *list)
462 {
463         struct cfs_expr_list *el;
464         int i = 0, j = 0;
465
466         list_for_each_entry(el, list, el_link) {
467                 assert(j++ < 1);
468                 i += cfs_expr_list_print(buffer + i, count - i, el);
469         }
470         return i;
471 }
472
473 /*
474  * Nf_match_addr method for networks using numeric addresses
475  *
476  * \retval 1 on match
477  * \retval 0 otherwise
478  */
479 static int
480 libcfs_num_match(__u32 addr, struct list_head *numaddr)
481 {
482         struct cfs_expr_list *el;
483
484         assert(!list_empty(numaddr));
485         el = list_entry(numaddr->next, struct cfs_expr_list, el_link);
486
487         return cfs_expr_list_match(addr, el);
488 }
489
490 static int cfs_ip_min_max(struct list_head *nidlist, __u32 *min, __u32 *max);
491 static int cfs_num_min_max(struct list_head *nidlist, __u32 *min, __u32 *max);
492
493 static struct netstrfns libcfs_netstrfns[] = {
494         {
495                 .nf_type                = LOLND,
496                 .nf_name                = "lo",
497                 .nf_modname             = "klolnd",
498                 .nf_addr2str            = libcfs_decnum_addr2str,
499                 .nf_str2addr            = libcfs_lo_str2addr,
500                 .nf_parse_addrlist      = libcfs_num_parse,
501                 .nf_print_addrlist      = libcfs_num_addr_range_print,
502                 .nf_match_addr          = libcfs_num_match,
503                 .nf_min_max             = cfs_num_min_max,
504                 .nf_expand_addrrange    = libcfs_num_addr_range_expand
505         },
506         {
507                 .nf_type                = SOCKLND,
508                 .nf_name                = "tcp",
509                 .nf_modname             = "ksocklnd",
510                 .nf_addr2str            = libcfs_ip_addr2str,
511                 .nf_str2addr            = libcfs_ip_str2addr,
512                 .nf_parse_addrlist      = cfs_ip_addr_parse,
513                 .nf_print_addrlist      = libcfs_ip_addr_range_print,
514                 .nf_match_addr          = cfs_ip_addr_match,
515                 .nf_min_max             = cfs_ip_min_max,
516                 .nf_expand_addrrange    = libcfs_ip_addr_range_expand
517         },
518         {
519                 .nf_type                = O2IBLND,
520                 .nf_name                = "o2ib",
521                 .nf_modname             = "ko2iblnd",
522                 .nf_addr2str            = libcfs_ip_addr2str,
523                 .nf_str2addr            = libcfs_ip_str2addr,
524                 .nf_parse_addrlist      = cfs_ip_addr_parse,
525                 .nf_print_addrlist      = libcfs_ip_addr_range_print,
526                 .nf_match_addr          = cfs_ip_addr_match,
527                 .nf_min_max             = cfs_ip_min_max,
528                 .nf_expand_addrrange    = libcfs_ip_addr_range_expand
529         },
530         {
531                 .nf_type                = GNILND,
532                 .nf_name                = "gni",
533                 .nf_modname             = "kgnilnd",
534                 .nf_addr2str            = libcfs_decnum_addr2str,
535                 .nf_str2addr            = libcfs_num_str2addr,
536                 .nf_parse_addrlist      = libcfs_num_parse,
537                 .nf_print_addrlist      = libcfs_num_addr_range_print,
538                 .nf_match_addr          = libcfs_num_match,
539                 .nf_min_max             = cfs_num_min_max,
540                 .nf_expand_addrrange    = libcfs_num_addr_range_expand
541         },
542         {
543                 .nf_type                = GNIIPLND,
544                 .nf_name                = "gip",
545                 .nf_modname             = "kgnilnd",
546                 .nf_addr2str            = libcfs_ip_addr2str,
547                 .nf_str2addr            = libcfs_ip_str2addr,
548                 .nf_parse_addrlist      = cfs_ip_addr_parse,
549                 .nf_print_addrlist      = libcfs_ip_addr_range_print,
550                 .nf_match_addr          = cfs_ip_addr_match,
551                 .nf_min_max             = cfs_ip_min_max,
552                 .nf_expand_addrrange    = libcfs_ip_addr_range_expand
553         },
554         {
555                 .nf_type                = PTL4LND,
556                 .nf_name                = "ptlf",
557                 .nf_modname             = "kptl4lnd",
558                 .nf_addr2str            = libcfs_decnum_addr2str,
559                 .nf_str2addr            = libcfs_num_str2addr,
560                 .nf_parse_addrlist      = libcfs_num_parse,
561                 .nf_print_addrlist      = libcfs_num_addr_range_print,
562                 .nf_match_addr          = libcfs_num_match,
563                 .nf_min_max             = cfs_num_min_max,
564                 .nf_expand_addrrange    = libcfs_num_addr_range_expand
565         }
566 };
567
568 static const size_t libcfs_nnetstrfns =
569         sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
570
571 static struct netstrfns *
572 libcfs_lnd2netstrfns(__u32 lnd)
573 {
574         int     i;
575
576         for (i = 0; i < libcfs_nnetstrfns; i++)
577                 if (lnd == libcfs_netstrfns[i].nf_type)
578                         return &libcfs_netstrfns[i];
579
580         return NULL;
581 }
582
583 static struct netstrfns *
584 libcfs_namenum2netstrfns(const char *name)
585 {
586         struct netstrfns *nf;
587         int               i;
588
589         for (i = 0; i < libcfs_nnetstrfns; i++) {
590                 nf = &libcfs_netstrfns[i];
591                 if (!strncmp(name, nf->nf_name, strlen(nf->nf_name)))
592                         return nf;
593         }
594         return NULL;
595 }
596
597 static struct netstrfns *
598 libcfs_name2netstrfns(const char *name)
599 {
600         int    i;
601
602         for (i = 0; i < libcfs_nnetstrfns; i++)
603                 if (!strcmp(libcfs_netstrfns[i].nf_name, name))
604                         return &libcfs_netstrfns[i];
605
606         return NULL;
607 }
608
609 int
610 libcfs_isknown_lnd(__u32 lnd)
611 {
612         return libcfs_lnd2netstrfns(lnd) != NULL;
613 }
614
615 char *
616 libcfs_lnd2modname(__u32 lnd)
617 {
618         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
619
620         return (nf == NULL) ? NULL : nf->nf_modname;
621 }
622
623 int
624 libcfs_str2lnd(const char *str)
625 {
626         struct netstrfns *nf = libcfs_name2netstrfns(str);
627
628         if (nf != NULL)
629                 return nf->nf_type;
630
631         return -1;
632 }
633
634 char *
635 libcfs_lnd2str_r(__u32 lnd, char *buf, size_t buf_size)
636 {
637         struct netstrfns *nf;
638
639         nf = libcfs_lnd2netstrfns(lnd);
640         if (nf == NULL)
641                 snprintf(buf, buf_size, "?%u?", lnd);
642         else
643                 snprintf(buf, buf_size, "%s", nf->nf_name);
644
645         return buf;
646 }
647
648 char *
649 libcfs_net2str_r(__u32 net, char *buf, size_t buf_size)
650 {
651         __u32             nnum = LNET_NETNUM(net);
652         __u32             lnd  = LNET_NETTYP(net);
653         struct netstrfns *nf;
654
655         nf = libcfs_lnd2netstrfns(lnd);
656         if (nf == NULL)
657                 snprintf(buf, buf_size, "<%u:%u>", lnd, nnum);
658         else if (nnum == 0)
659                 snprintf(buf, buf_size, "%s", nf->nf_name);
660         else
661                 snprintf(buf, buf_size, "%s%u", nf->nf_name, nnum);
662
663         return buf;
664 }
665
666 char *
667 libcfs_nid2str_r(lnet_nid_t nid, char *buf, size_t buf_size)
668 {
669         __u32             addr = LNET_NIDADDR(nid);
670         __u32             net  = LNET_NIDNET(nid);
671         __u32             nnum = LNET_NETNUM(net);
672         __u32             lnd  = LNET_NETTYP(net);
673         struct netstrfns *nf;
674
675         if (nid == LNET_NID_ANY) {
676                 strncpy(buf, "<?>", buf_size);
677                 buf[buf_size - 1] = '\0';
678                 return buf;
679         }
680
681         nf = libcfs_lnd2netstrfns(lnd);
682         if (nf == NULL) {
683                 snprintf(buf, buf_size, "%x@<%u:%u>", addr, lnd, nnum);
684         } else {
685                 size_t addr_len;
686
687                 nf->nf_addr2str(addr, buf, buf_size);
688                 addr_len = strlen(buf);
689                 if (nnum == 0)
690                         snprintf(buf + addr_len, buf_size - addr_len, "@%s",
691                                  nf->nf_name);
692                 else
693                         snprintf(buf + addr_len, buf_size - addr_len, "@%s%u",
694                                  nf->nf_name, nnum);
695         }
696
697         return buf;
698 }
699
700 static struct netstrfns *
701 libcfs_str2net_internal(const char *str, __u32 *net)
702 {
703         struct netstrfns *nf = NULL;
704         int               nob;
705         unsigned int      netnum;
706         int               i;
707
708         for (i = 0; i < libcfs_nnetstrfns; i++) {
709                 nf = &libcfs_netstrfns[i];
710                 if (!strncmp(str, nf->nf_name, strlen(nf->nf_name)))
711                         break;
712         }
713
714         if (i == libcfs_nnetstrfns)
715                 return NULL;
716
717         nob = strlen(nf->nf_name);
718
719         if (strlen(str) == (unsigned int)nob) {
720                 netnum = 0;
721         } else {
722                 if (nf->nf_type == LOLND) /* net number not allowed */
723                         return NULL;
724
725                 str += nob;
726                 i = strlen(str);
727                 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
728                     i != (int)strlen(str))
729                         return NULL;
730         }
731
732         *net = LNET_MKNET(nf->nf_type, netnum);
733         return nf;
734 }
735
736 __u32
737 libcfs_str2net(const char *str)
738 {
739         __u32  net;
740
741         if (libcfs_str2net_internal(str, &net) != NULL)
742                 return net;
743
744         return LNET_NET_ANY;
745 }
746
747 lnet_nid_t
748 libcfs_str2nid(const char *str)
749 {
750         const char       *sep = strchr(str, '@');
751         struct netstrfns *nf;
752         __u32             net;
753         __u32             addr;
754
755         if (sep != NULL) {
756                 nf = libcfs_str2net_internal(sep + 1, &net);
757                 if (nf == NULL)
758                         return LNET_NID_ANY;
759         } else {
760                 sep = str + strlen(str);
761                 net = LNET_MKNET(SOCKLND, 0);
762                 nf = libcfs_lnd2netstrfns(SOCKLND);
763                 assert(nf != NULL);
764         }
765
766         if (!nf->nf_str2addr(str, (int)(sep - str), &addr))
767                 return LNET_NID_ANY;
768
769         return LNET_MKNID(net, addr);
770 }
771
772 char *
773 libcfs_id2str(struct lnet_process_id id)
774 {
775         char *str = libcfs_next_nidstring();
776
777         if (id.pid == LNET_PID_ANY) {
778                 snprintf(str, LNET_NIDSTR_SIZE,
779                          "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
780                 return str;
781         }
782
783         snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
784                  ((id.pid & LNET_PID_USERFLAG) != 0) ? "U" : "",
785                  (id.pid & ~LNET_PID_USERFLAG), libcfs_nid2str(id.nid));
786         return str;
787 }
788
789 int
790 libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
791 {
792         if (!strcmp(str, "*")) {
793                 *nidp = LNET_NID_ANY;
794                 return 1;
795         }
796
797         *nidp = libcfs_str2nid(str);
798         return *nidp != LNET_NID_ANY;
799 }
800
801 /**
802  * Nid range list syntax.
803  * \verbatim
804  *
805  * <nidlist>         :== <nidrange> [ ' ' <nidrange> ]
806  * <nidrange>        :== <addrrange> '@' <net>
807  * <addrrange>       :== '*' |
808  *                       <ipaddr_range> |
809  *                       <cfs_expr_list>
810  * <ipaddr_range>    :== <cfs_expr_list>.<cfs_expr_list>.<cfs_expr_list>.
811  *                       <cfs_expr_list>
812  * <cfs_expr_list>   :== <number> |
813  *                       <expr_list>
814  * <expr_list>       :== '[' <range_expr> [ ',' <range_expr>] ']'
815  * <range_expr>      :== <number> |
816  *                       <number> '-' <number> |
817  *                       <number> '-' <number> '/' <number>
818  * <net>             :== <netname> | <netname><number>
819  * <netname>         :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" |
820  *                       "vib" | "ra" | "elan" | "mx" | "ptl"
821  * \endverbatim
822  */
823
824 /**
825  * Structure to represent \<nidrange\> token of the syntax.
826  *
827  * One of this is created for each \<net\> parsed.
828  */
829 struct nidrange {
830         /**
831          * Link to list of this structures which is built on nid range
832          * list parsing.
833          */
834         struct list_head nr_link;
835         /**
836          * List head for addrrange::ar_link.
837          */
838         struct list_head nr_addrranges;
839         /**
840          * Flag indicating that *@<net> is found.
841          */
842         int nr_all;
843         /**
844          * Pointer to corresponding element of libcfs_netstrfns.
845          */
846         struct netstrfns *nr_netstrfns;
847         /**
848          * Number of network. E.g. 5 if \<net\> is "elan5".
849          */
850         int nr_netnum;
851 };
852
853 /**
854  * Structure to represent \<addrrange\> token of the syntax.
855  */
856 struct addrrange {
857         /**
858          * Link to nidrange::nr_addrranges.
859          */
860         struct list_head ar_link;
861         /**
862          * List head for cfs_expr_list::el_list.
863          */
864         struct list_head ar_numaddr_ranges;
865 };
866
867 /**
868  * Parses \<addrrange\> token on the syntax.
869  *
870  * Allocates struct addrrange and links to \a nidrange via
871  * (nidrange::nr_addrranges)
872  *
873  * \retval 0 if \a src parses to '*' | \<ipaddr_range\> | \<cfs_expr_list\>
874  * \retval -errno otherwise
875  */
876 static int
877 parse_addrange(const struct cfs_lstr *src, struct nidrange *nidrange)
878 {
879         struct addrrange *addrrange;
880
881         if (src->ls_len == 1 && src->ls_str[0] == '*') {
882                 nidrange->nr_all = 1;
883                 return 0;
884         }
885
886         addrrange = calloc(1, sizeof(struct addrrange));
887         if (addrrange == NULL)
888                 return -ENOMEM;
889         list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges);
890         INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges);
891
892         return nidrange->nr_netstrfns->nf_parse_addrlist(src->ls_str,
893                                                 src->ls_len,
894                                                 &addrrange->ar_numaddr_ranges);
895 }
896
897 /**
898  * Finds or creates struct nidrange.
899  *
900  * Checks if \a src is a valid network name, looks for corresponding
901  * nidrange on the ist of nidranges (\a nidlist), creates new struct
902  * nidrange if it is not found.
903  *
904  * \retval pointer to struct nidrange matching network specified via \a src
905  * \retval NULL if \a src does not match any network
906  */
907 static struct nidrange *
908 add_nidrange(const struct cfs_lstr *src,
909              struct list_head *nidlist)
910 {
911         struct netstrfns *nf;
912         struct nidrange *nr;
913         int endlen;
914         unsigned netnum;
915
916         if (src->ls_len >= LNET_NIDSTR_SIZE)
917                 return NULL;
918
919         nf = libcfs_namenum2netstrfns(src->ls_str);
920         if (nf == NULL)
921                 return NULL;
922         endlen = src->ls_len - strlen(nf->nf_name);
923         if (endlen == 0)
924                 /* network name only, e.g. "elan" or "tcp" */
925                 netnum = 0;
926         else {
927                 /* e.g. "elan25" or "tcp23", refuse to parse if
928                  * network name is not appended with decimal or
929                  * hexadecimal number */
930                 if (!cfs_str2num_check(src->ls_str + strlen(nf->nf_name),
931                                        endlen, &netnum, 0, MAX_NUMERIC_VALUE))
932                         return NULL;
933         }
934
935         list_for_each_entry(nr, nidlist, nr_link) {
936                 if (nr->nr_netstrfns != nf)
937                         continue;
938                 if (nr->nr_netnum != netnum)
939                         continue;
940                 return nr;
941         }
942
943         nr = calloc(1, sizeof(struct nidrange));
944         if (nr == NULL)
945                 return NULL;
946         list_add_tail(&nr->nr_link, nidlist);
947         INIT_LIST_HEAD(&nr->nr_addrranges);
948         nr->nr_netstrfns = nf;
949         nr->nr_all = 0;
950         nr->nr_netnum = netnum;
951
952         return nr;
953 }
954
955 /**
956  * Parses \<nidrange\> token of the syntax.
957  *
958  * \retval 1 if \a src parses to \<addrrange\> '@' \<net\>
959  * \retval 0 otherwise
960  */
961 static int
962 parse_nidrange(struct cfs_lstr *src, struct list_head *nidlist)
963 {
964         struct cfs_lstr addrrange;
965         struct cfs_lstr net;
966         struct cfs_lstr tmp;
967         struct nidrange *nr;
968
969         tmp = *src;
970         if (cfs_gettok(src, '@', &addrrange) == 0)
971                 goto failed;
972
973         if (cfs_gettok(src, '@', &net) == 0 || src->ls_str != NULL)
974                 goto failed;
975
976         nr = add_nidrange(&net, nidlist);
977         if (nr == NULL)
978                 goto failed;
979
980         if (parse_addrange(&addrrange, nr) != 0)
981                 goto failed;
982
983         return 1;
984  failed:
985         fprintf(stderr, "can't parse nidrange: \"%.*s\"\n",
986                 tmp.ls_len, tmp.ls_str);
987         return 0;
988 }
989
990 static __u32
991 libcfs_net_str_len(const char *str)
992 {
993         int i;
994         struct netstrfns *nf = NULL;
995
996         for (i = 0; i < libcfs_nnetstrfns; i++) {
997                 nf = &libcfs_netstrfns[i];
998                 if (!strncmp(str, nf->nf_name, strlen(nf->nf_name)))
999                         return strlen(nf->nf_name);
1000         }
1001
1002         return 0;
1003 }
1004
1005 int
1006 parse_net_range(char *str, __u32 len, struct list_head *net_num,
1007                 __u32 *net_type)
1008 {
1009         struct cfs_lstr next;
1010         __u32 net_type_len;
1011         __u32 net;
1012         char *bracket;
1013         char *star;
1014
1015         if (!str)
1016                 return -EINVAL;
1017
1018         next.ls_str = str;
1019         next.ls_len = len;
1020
1021         net_type_len = libcfs_net_str_len(str);
1022
1023         if (net_type_len < len) {
1024                 char c = str[net_type_len];
1025
1026                 str[net_type_len] = '\0';
1027                 net = libcfs_str2net(str);
1028                 str[net_type_len] = c;
1029         } else {
1030                 net = libcfs_str2net(str);
1031         }
1032
1033         if (net == LNET_NIDNET(LNET_NID_ANY))
1034                 return -EINVAL;
1035
1036         *net_type = LNET_NETTYP(net);
1037
1038         /*
1039          * the net is either followed with an absolute number, *, or an
1040          * expression enclosed in []
1041          */
1042         bracket = strchr(next.ls_str, '[');
1043         star = strchr(next.ls_str, '*');
1044
1045         /* "*[" pattern not allowed */
1046         if (bracket && star && star < bracket)
1047                 return -EINVAL;
1048
1049         if (!bracket) {
1050                 next.ls_str = str + net_type_len;
1051                 next.ls_len = strlen(next.ls_str);
1052         } else {
1053                 next.ls_str = bracket;
1054                 next.ls_len = strlen(bracket);
1055         }
1056
1057         /* if there is no net number just return */
1058         if (next.ls_len == 0)
1059                 return 0;
1060
1061         return libcfs_num_parse(next.ls_str, next.ls_len,
1062                                 net_num);
1063 }
1064
1065 int
1066 parse_address(struct cfs_lstr *src, const __u32 net_type,
1067               struct list_head *addr)
1068 {
1069         int i;
1070         struct netstrfns *nf = NULL;
1071
1072         for (i = 0; i < libcfs_nnetstrfns; i++) {
1073                 nf = &libcfs_netstrfns[i];
1074                 if (net_type == nf->nf_type)
1075                         return nf->nf_parse_addrlist(src->ls_str, src->ls_len,
1076                                                      addr);
1077         }
1078
1079         return -EINVAL;
1080 }
1081
1082 int
1083 cfs_parse_nid_parts(char *str, struct list_head *addr,
1084                     struct list_head *net_num, __u32 *net_type)
1085 {
1086         struct cfs_lstr next;
1087         struct cfs_lstr addrrange;
1088         bool found = false;
1089         int rc;
1090
1091         if (!str)
1092                 return -EINVAL;
1093
1094         next.ls_str = str;
1095         next.ls_len = strlen(str);
1096
1097         rc = cfs_gettok(&next, '@', &addrrange);
1098         if (!rc)
1099                 return -EINVAL;
1100
1101         if (!next.ls_str) {
1102                 /* only net is present */
1103                 next.ls_str = str;
1104                 next.ls_len = strlen(str);
1105         } else {
1106                 found = true;
1107         }
1108
1109         /* assume only net is present */
1110         rc = parse_net_range(next.ls_str, next.ls_len, net_num, net_type);
1111
1112         /*
1113          * if we successfully parsed the net range and there is no
1114          * address, or if we fail to parse the net range then return
1115          */
1116         if ((!rc && !found) || rc)
1117                 return rc;
1118
1119         return parse_address(&addrrange, *net_type, addr);
1120 }
1121
1122 /**
1123  * Frees addrrange structures of \a list.
1124  *
1125  * For each struct addrrange structure found on \a list it frees
1126  * cfs_expr_list list attached to it and frees the addrrange itself.
1127  *
1128  * \retval none
1129  */
1130 static void
1131 free_addrranges(struct list_head *list)
1132 {
1133         while (!list_empty(list)) {
1134                 struct addrrange *ar;
1135
1136                 ar = list_entry(list->next, struct addrrange, ar_link);
1137
1138                 cfs_expr_list_free_list(&ar->ar_numaddr_ranges);
1139                 list_del(&ar->ar_link);
1140                 free(ar);
1141         }
1142 }
1143
1144 /**
1145  * Frees nidrange strutures of \a list.
1146  *
1147  * For each struct nidrange structure found on \a list it frees
1148  * addrrange list attached to it and frees the nidrange itself.
1149  *
1150  * \retval none
1151  */
1152 void
1153 cfs_free_nidlist(struct list_head *list)
1154 {
1155         struct list_head *pos, *next;
1156         struct nidrange *nr;
1157
1158         list_for_each_safe(pos, next, list) {
1159                 nr = list_entry(pos, struct nidrange, nr_link);
1160                 free_addrranges(&nr->nr_addrranges);
1161                 list_del(pos);
1162                 free(nr);
1163         }
1164 }
1165
1166 /**
1167  * Parses nid range list.
1168  *
1169  * Parses with rigorous syntax and overflow checking \a str into
1170  * \<nidrange\> [ ' ' \<nidrange\> ], compiles \a str into set of
1171  * structures and links that structure to \a nidlist. The resulting
1172  * list can be used to match a NID againts set of NIDS defined by \a
1173  * str.
1174  * \see cfs_match_nid
1175  *
1176  * \retval 1 on success
1177  * \retval 0 otherwise
1178  */
1179 int
1180 cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
1181 {
1182         struct cfs_lstr src;
1183         struct cfs_lstr res;
1184         int rc;
1185
1186         src.ls_str = str;
1187         src.ls_len = len;
1188         INIT_LIST_HEAD(nidlist);
1189         while (src.ls_str) {
1190                 rc = cfs_gettok(&src, ' ', &res);
1191                 if (rc == 0) {
1192                         cfs_free_nidlist(nidlist);
1193                         return 0;
1194                 }
1195                 rc = parse_nidrange(&res, nidlist);
1196                 if (rc == 0) {
1197                         cfs_free_nidlist(nidlist);
1198                         return 0;
1199                 }
1200         }
1201         return 1;
1202 }
1203
1204 /**
1205  * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
1206  *
1207  * \see cfs_parse_nidlist()
1208  *
1209  * \retval 1 on match
1210  * \retval 0  otherwises
1211  */
1212 int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist)
1213 {
1214         struct nidrange *nr;
1215         struct addrrange *ar;
1216
1217         list_for_each_entry(nr, nidlist, nr_link) {
1218                 if (nr->nr_netstrfns->nf_type != LNET_NETTYP(LNET_NIDNET(nid)))
1219                         continue;
1220                 if (nr->nr_netnum != LNET_NETNUM(LNET_NIDNET(nid)))
1221                         continue;
1222                 if (nr->nr_all)
1223                         return 1;
1224                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
1225                         if (nr->nr_netstrfns->nf_match_addr(LNET_NIDADDR(nid),
1226                                                         &ar->ar_numaddr_ranges))
1227                                 return 1;
1228         }
1229         return 0;
1230 }
1231
1232 static struct netstrfns *
1233 type2net_info(__u32 net_type)
1234 {
1235         int i;
1236
1237         for (i = 0; i < libcfs_nnetstrfns; i++) {
1238                 if (libcfs_netstrfns[i].nf_type == net_type)
1239                         return &libcfs_netstrfns[i];
1240         }
1241
1242         return NULL;
1243 }
1244
1245 int
1246 cfs_match_net(__u32 net_id, __u32 net_type, struct list_head *net_num_list)
1247 {
1248         __u32 net_num;
1249
1250         if (!net_num_list)
1251                 return 0;
1252
1253         if (net_type != LNET_NETTYP(net_id))
1254                 return 0;
1255
1256         net_num = LNET_NETNUM(net_id);
1257
1258         /*
1259          * if there is a net number but the list passed in is empty, then
1260          * there is no match.
1261          */
1262         if (!net_num && list_empty(net_num_list))
1263                 return 1;
1264         else if (list_empty(net_num_list))
1265                 return 0;
1266
1267         if (!libcfs_num_match(net_num, net_num_list))
1268                 return 0;
1269
1270         return 1;
1271 }
1272
1273 int
1274 cfs_match_nid_net(lnet_nid_t nid, __u32 net_type,
1275                   struct list_head *net_num_list,
1276                   struct list_head *addr)
1277 {
1278         __u32 address;
1279         struct netstrfns *fns;
1280
1281         if (!addr || !net_num_list)
1282                 return 0;
1283
1284         fns = type2net_info(LNET_NETTYP(LNET_NIDNET(nid)));
1285         if (!fns || !net_num_list || !addr)
1286                 return 0;
1287
1288         address = LNET_NIDADDR(nid);
1289
1290         /* if either the address or net number don't match then no match */
1291         if (!fns->nf_match_addr(address, addr) ||
1292             !cfs_match_net(LNET_NIDNET(nid), net_type, net_num_list))
1293                 return 0;
1294
1295         return 1;
1296 }
1297 /**
1298  * Print the network part of the nidrange \a nr into the specified \a buffer.
1299  *
1300  * \retval number of characters written
1301  */
1302 static int
1303 cfs_print_network(char *buffer, int count, struct nidrange *nr)
1304 {
1305         struct netstrfns *nf = nr->nr_netstrfns;
1306
1307         if (nr->nr_netnum == 0)
1308                 return scnprintf(buffer, count, "@%s", nf->nf_name);
1309         else
1310                 return scnprintf(buffer, count, "@%s%u",
1311                                  nf->nf_name, nr->nr_netnum);
1312 }
1313
1314
1315 /**
1316  * Print a list of addrrange (\a addrranges) into the specified \a buffer.
1317  * At max \a count characters can be printed into \a buffer.
1318  *
1319  * \retval number of characters written
1320  */
1321 static int
1322 cfs_print_addrranges(char *buffer, int count, struct list_head *addrranges,
1323                      struct nidrange *nr)
1324 {
1325         int i = 0;
1326         struct addrrange *ar;
1327         struct netstrfns *nf = nr->nr_netstrfns;
1328
1329         list_for_each_entry(ar, addrranges, ar_link) {
1330                 if (i != 0)
1331                         i += scnprintf(buffer + i, count - i, " ");
1332                 i += nf->nf_print_addrlist(buffer + i, count - i,
1333                                            &ar->ar_numaddr_ranges);
1334                 i += cfs_print_network(buffer + i, count - i, nr);
1335         }
1336         return i;
1337 }
1338
1339 /**
1340  * Print a list of nidranges (\a nidlist) into the specified \a buffer.
1341  * At max \a count characters can be printed into \a buffer.
1342  * Nidranges are separated by a space character.
1343  *
1344  * \retval number of characters written
1345  */
1346 int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist)
1347 {
1348         int i = 0;
1349         struct nidrange *nr;
1350
1351         if (count <= 0)
1352                 return 0;
1353
1354         list_for_each_entry(nr, nidlist, nr_link) {
1355                 if (i != 0)
1356                         i += scnprintf(buffer + i, count - i, " ");
1357
1358                 if (nr->nr_all != 0) {
1359                         assert(list_empty(&nr->nr_addrranges));
1360                         i += scnprintf(buffer + i, count - i, "*");
1361                         i += cfs_print_network(buffer + i, count - i, nr);
1362                 } else {
1363                         i += cfs_print_addrranges(buffer + i, count - i,
1364                                                   &nr->nr_addrranges, nr);
1365                 }
1366         }
1367         return i;
1368 }
1369
1370 /**
1371  * Determines minimum and maximum addresses for a single
1372  * numeric address range
1373  *
1374  * \param       ar
1375  * \param[out]  *min_nid __u32 representation of min NID
1376  * \param[out]  *max_nid __u32 representation of max NID
1377  * \retval      -EINVAL unsupported LNET range
1378  * \retval      -ERANGE non-contiguous LNET range
1379  */
1380 static int cfs_ip_ar_min_max(struct addrrange *ar, __u32 *min_nid,
1381                               __u32 *max_nid)
1382 {
1383         struct cfs_expr_list *expr_list;
1384         struct cfs_range_expr *range;
1385         unsigned int min_ip[4] = {0};
1386         unsigned int max_ip[4] = {0};
1387         int cur_octet = 0;
1388         bool expect_full_octet = false;
1389
1390         list_for_each_entry(expr_list, &ar->ar_numaddr_ranges, el_link) {
1391                 int re_count = 0;
1392
1393                 list_for_each_entry(range, &expr_list->el_exprs, re_link) {
1394                         /* XXX: add support for multiple & non-contig. re's */
1395                         if (re_count > 0)
1396                                 return -EINVAL;
1397
1398                         /* if a previous octet was ranged, then all remaining
1399                          * octets must be full for contiguous range */
1400                         if (expect_full_octet && (range->re_lo != 0 ||
1401                                                   range->re_hi != 255))
1402                                 return -ERANGE;
1403
1404                         if (range->re_stride != 1)
1405                                 return -ERANGE;
1406
1407                         if (range->re_lo > range->re_hi)
1408                                 return -EINVAL;
1409
1410                         if (range->re_lo != range->re_hi)
1411                                 expect_full_octet = true;
1412
1413                         min_ip[cur_octet] = range->re_lo;
1414                         max_ip[cur_octet] = range->re_hi;
1415
1416                         re_count++;
1417                 }
1418
1419                 cur_octet++;
1420         }
1421
1422         if (min_nid != NULL)
1423                 *min_nid = ((min_ip[0] << 24) | (min_ip[1] << 16) |
1424                             (min_ip[2] << 8) | min_ip[3]);
1425
1426         if (max_nid != NULL)
1427                 *max_nid = ((max_ip[0] << 24) | (max_ip[1] << 16) |
1428                             (max_ip[2] << 8) | max_ip[3]);
1429
1430         return 0;
1431 }
1432
1433 /**
1434  * Determines minimum and maximum addresses for a single
1435  * numeric address range
1436  *
1437  * \param       ar
1438  * \param[out]  *min_nid __u32 representation of min NID
1439  * \param[out]  *max_nid __u32 representation of max NID
1440  * \retval      -EINVAL unsupported LNET range
1441  */
1442 static int cfs_num_ar_min_max(struct addrrange *ar, __u32 *min_nid,
1443                                __u32 *max_nid)
1444 {
1445         struct cfs_expr_list *el;
1446         struct cfs_range_expr *re;
1447         unsigned int min_addr = 0;
1448         unsigned int max_addr = 0;
1449
1450         list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) {
1451                 int re_count = 0;
1452
1453                 list_for_each_entry(re, &el->el_exprs, re_link) {
1454                         if (re_count > 0)
1455                                 return -EINVAL;
1456                         if (re->re_lo > re->re_hi)
1457                                 return -EINVAL;
1458
1459                         if (re->re_lo < min_addr || min_addr == 0)
1460                                 min_addr = re->re_lo;
1461                         if (re->re_hi > max_addr)
1462                                 max_addr = re->re_hi;
1463
1464                         re_count++;
1465                 }
1466         }
1467
1468         if (min_nid != NULL)
1469                 *min_nid = min_addr;
1470         if (max_nid != NULL)
1471                 *max_nid = max_addr;
1472
1473         return 0;
1474 }
1475
1476 /**
1477  * Takes a linked list of nidrange expressions, determines the minimum
1478  * and maximum nid and creates appropriate nid structures
1479  *
1480  * \param       *nidlist
1481  * \param[out]  *min_nid string representation of min NID
1482  * \param[out]  *max_nid string representation of max NID
1483  * \retval      -EINVAL unsupported LNET range
1484  * \retval      -ERANGE non-contiguous LNET range
1485  */
1486 int cfs_nidrange_find_min_max(struct list_head *nidlist, char *min_nid,
1487                               char *max_nid, size_t nidstr_length)
1488 {
1489         struct nidrange *first_nidrange;
1490         int netnum;
1491         struct netstrfns *nf;
1492         char *lndname;
1493         __u32 min_addr;
1494         __u32 max_addr;
1495         char min_addr_str[IPSTRING_LENGTH];
1496         char max_addr_str[IPSTRING_LENGTH];
1497         int rc;
1498
1499         first_nidrange = list_entry(nidlist->next, struct nidrange, nr_link);
1500
1501         netnum = first_nidrange->nr_netnum;
1502         nf = first_nidrange->nr_netstrfns;
1503         lndname = nf->nf_name;
1504
1505         rc = nf->nf_min_max(nidlist, &min_addr, &max_addr);
1506         if (rc < 0)
1507                 return rc;
1508
1509         nf->nf_addr2str(min_addr, min_addr_str, sizeof(min_addr_str));
1510         nf->nf_addr2str(max_addr, max_addr_str, sizeof(max_addr_str));
1511
1512         snprintf(min_nid, nidstr_length, "%s@%s%d", min_addr_str, lndname,
1513                  netnum);
1514         snprintf(max_nid, nidstr_length, "%s@%s%d", max_addr_str, lndname,
1515                  netnum);
1516
1517         return 0;
1518 }
1519
1520 /**
1521  * Determines the min and max NID values for num LNDs
1522  *
1523  * \param       *nidlist
1524  * \param[out]  *min_nid if provided, returns string representation of min NID
1525  * \param[out]  *max_nid if provided, returns string representation of max NID
1526  * \retval      -EINVAL unsupported LNET range
1527  * \retval      -ERANGE non-contiguous LNET range
1528  */
1529 static int cfs_num_min_max(struct list_head *nidlist, __u32 *min_nid,
1530                             __u32 *max_nid)
1531 {
1532         struct nidrange *nr;
1533         struct addrrange *ar;
1534         unsigned int tmp_min_addr = 0;
1535         unsigned int tmp_max_addr = 0;
1536         unsigned int min_addr = 0;
1537         unsigned int max_addr = 0;
1538         int nidlist_count = 0;
1539         int rc;
1540
1541         list_for_each_entry(nr, nidlist, nr_link) {
1542                 if (nidlist_count > 0)
1543                         return -EINVAL;
1544
1545                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1546                         rc = cfs_num_ar_min_max(ar, &tmp_min_addr,
1547                                                 &tmp_max_addr);
1548                         if (rc < 0)
1549                                 return rc;
1550
1551                         if (tmp_min_addr < min_addr || min_addr == 0)
1552                                 min_addr = tmp_min_addr;
1553                         if (tmp_max_addr > max_addr)
1554                                 max_addr = tmp_min_addr;
1555                 }
1556         }
1557         if (max_nid != NULL)
1558                 *max_nid = max_addr;
1559         if (min_nid != NULL)
1560                 *min_nid = min_addr;
1561
1562         return 0;
1563 }
1564
1565 /**
1566  * Takes an nidlist and determines the minimum and maximum
1567  * ip addresses.
1568  *
1569  * \param       *nidlist
1570  * \param[out]  *min_nid if provided, returns string representation of min NID
1571  * \param[out]  *max_nid if provided, returns string representation of max NID
1572  * \retval      -EINVAL unsupported LNET range
1573  * \retval      -ERANGE non-contiguous LNET range
1574  */
1575 static int cfs_ip_min_max(struct list_head *nidlist, __u32 *min_nid,
1576                            __u32 *max_nid)
1577 {
1578         struct nidrange *nr;
1579         struct addrrange *ar;
1580         __u32 tmp_min_ip_addr = 0;
1581         __u32 tmp_max_ip_addr = 0;
1582         __u32 min_ip_addr = 0;
1583         __u32 max_ip_addr = 0;
1584         int nidlist_count = 0;
1585         int rc;
1586
1587         list_for_each_entry(nr, nidlist, nr_link) {
1588                 if (nidlist_count > 0)
1589                         return -EINVAL;
1590
1591                 if (nr->nr_all) {
1592                         min_ip_addr = 0;
1593                         max_ip_addr = 0xffffffff;
1594                         break;
1595                 }
1596
1597                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1598                         rc = cfs_ip_ar_min_max(ar, &tmp_min_ip_addr,
1599                                                &tmp_max_ip_addr);
1600                         if (rc < 0)
1601                                 return rc;
1602
1603                         if (tmp_min_ip_addr < min_ip_addr || min_ip_addr == 0)
1604                                 min_ip_addr = tmp_min_ip_addr;
1605                         if (tmp_max_ip_addr > max_ip_addr)
1606                                 max_ip_addr = tmp_max_ip_addr;
1607                 }
1608
1609                 nidlist_count++;
1610         }
1611
1612         if (max_nid != NULL)
1613                 *max_nid = max_ip_addr;
1614         if (min_nid != NULL)
1615                 *min_nid = min_ip_addr;
1616
1617         return 0;
1618 }
1619
1620 static int
1621 libcfs_expand_nidrange(struct nidrange *nr, __u32 *addrs, int max_nids)
1622 {
1623         struct addrrange *ar;
1624         int rc = 0, count = max_nids;
1625         struct netstrfns *nf = nr->nr_netstrfns;
1626
1627         list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1628                 rc = nf->nf_expand_addrrange(&ar->ar_numaddr_ranges, addrs,
1629                                              count);
1630                 if (rc < 0)
1631                         return rc;
1632
1633                 count -= rc;
1634         }
1635
1636         return max_nids - count;
1637 }
1638
1639 int cfs_expand_nidlist(struct list_head *nidlist, lnet_nid_t *lnet_nidlist,
1640                        int max_nids)
1641 {
1642         struct nidrange *nr;
1643         int rc = 0, count = max_nids;
1644         int i, j = 0;
1645         __u32 *addrs;
1646         struct netstrfns *nf;
1647         __u32 net;
1648
1649         addrs = calloc(max_nids, sizeof(__u32));
1650         if (!addrs)
1651                 return -ENOMEM;
1652
1653         list_for_each_entry(nr, nidlist, nr_link) {
1654                 rc = libcfs_expand_nidrange(nr, addrs, count);
1655
1656                 if (rc < 0) {
1657                         free(addrs);
1658                         return rc;
1659                 }
1660
1661                 nf = nr->nr_netstrfns;
1662                 net = LNET_MKNET(nf->nf_type, nr->nr_netnum);
1663
1664                 for (i = count - 1; i >= count - rc; i--)
1665                         lnet_nidlist[j++] = LNET_MKNID(net, addrs[i]);
1666
1667                 count -= rc;
1668         }
1669
1670         free(addrs);
1671         return max_nids - count;
1672 }