Whamcloud - gitweb
780a8ab1ac21fc1fe5b3aad691eb9b7e45478941
[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                 .nf_type                = KFILND,
568                 .nf_name                = "kfi",
569                 .nf_modname             = "kkfilnd",
570                 .nf_addr2str            = libcfs_decnum_addr2str,
571                 .nf_str2addr            = libcfs_num_str2addr,
572                 .nf_parse_addrlist      = libcfs_num_parse,
573                 .nf_print_addrlist      = libcfs_num_addr_range_print,
574                 .nf_match_addr          = libcfs_num_match,
575                 .nf_min_max             = cfs_num_min_max,
576                 .nf_expand_addrrange    = libcfs_num_addr_range_expand
577         }
578 };
579
580 static const size_t libcfs_nnetstrfns =
581         sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
582
583 static struct netstrfns *
584 libcfs_lnd2netstrfns(__u32 lnd)
585 {
586         int     i;
587
588         for (i = 0; i < libcfs_nnetstrfns; i++)
589                 if (lnd == libcfs_netstrfns[i].nf_type)
590                         return &libcfs_netstrfns[i];
591
592         return NULL;
593 }
594
595 static struct netstrfns *
596 libcfs_namenum2netstrfns(const char *name)
597 {
598         struct netstrfns *nf;
599         int               i;
600
601         for (i = 0; i < libcfs_nnetstrfns; i++) {
602                 nf = &libcfs_netstrfns[i];
603                 if (!strncmp(name, nf->nf_name, strlen(nf->nf_name)))
604                         return nf;
605         }
606         return NULL;
607 }
608
609 static struct netstrfns *
610 libcfs_name2netstrfns(const char *name)
611 {
612         int    i;
613
614         for (i = 0; i < libcfs_nnetstrfns; i++)
615                 if (!strcmp(libcfs_netstrfns[i].nf_name, name))
616                         return &libcfs_netstrfns[i];
617
618         return NULL;
619 }
620
621 int
622 libcfs_isknown_lnd(__u32 lnd)
623 {
624         return libcfs_lnd2netstrfns(lnd) != NULL;
625 }
626
627 char *
628 libcfs_lnd2modname(__u32 lnd)
629 {
630         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
631
632         return (nf == NULL) ? NULL : nf->nf_modname;
633 }
634
635 int
636 libcfs_str2lnd(const char *str)
637 {
638         struct netstrfns *nf = libcfs_name2netstrfns(str);
639
640         if (nf != NULL)
641                 return nf->nf_type;
642
643         return -1;
644 }
645
646 char *
647 libcfs_lnd2str_r(__u32 lnd, char *buf, size_t buf_size)
648 {
649         struct netstrfns *nf;
650
651         nf = libcfs_lnd2netstrfns(lnd);
652         if (nf == NULL)
653                 snprintf(buf, buf_size, "?%u?", lnd);
654         else
655                 snprintf(buf, buf_size, "%s", nf->nf_name);
656
657         return buf;
658 }
659
660 char *
661 libcfs_net2str_r(__u32 net, char *buf, size_t buf_size)
662 {
663         __u32             nnum = LNET_NETNUM(net);
664         __u32             lnd  = LNET_NETTYP(net);
665         struct netstrfns *nf;
666
667         nf = libcfs_lnd2netstrfns(lnd);
668         if (nf == NULL)
669                 snprintf(buf, buf_size, "<%u:%u>", lnd, nnum);
670         else if (nnum == 0)
671                 snprintf(buf, buf_size, "%s", nf->nf_name);
672         else
673                 snprintf(buf, buf_size, "%s%u", nf->nf_name, nnum);
674
675         return buf;
676 }
677
678 char *
679 libcfs_nid2str_r(lnet_nid_t nid, char *buf, size_t buf_size)
680 {
681         __u32             addr = LNET_NIDADDR(nid);
682         __u32             net  = LNET_NIDNET(nid);
683         __u32             nnum = LNET_NETNUM(net);
684         __u32             lnd  = LNET_NETTYP(net);
685         struct netstrfns *nf;
686
687         if (nid == LNET_NID_ANY) {
688                 strncpy(buf, "<?>", buf_size);
689                 buf[buf_size - 1] = '\0';
690                 return buf;
691         }
692
693         nf = libcfs_lnd2netstrfns(lnd);
694         if (nf == NULL) {
695                 snprintf(buf, buf_size, "%x@<%u:%u>", addr, lnd, nnum);
696         } else {
697                 size_t addr_len;
698
699                 nf->nf_addr2str(addr, buf, buf_size);
700                 addr_len = strlen(buf);
701                 if (nnum == 0)
702                         snprintf(buf + addr_len, buf_size - addr_len, "@%s",
703                                  nf->nf_name);
704                 else
705                         snprintf(buf + addr_len, buf_size - addr_len, "@%s%u",
706                                  nf->nf_name, nnum);
707         }
708
709         return buf;
710 }
711
712 static struct netstrfns *
713 libcfs_str2net_internal(const char *str, __u32 *net)
714 {
715         struct netstrfns *nf = NULL;
716         int               nob;
717         unsigned int      netnum;
718         int               i;
719
720         for (i = 0; i < libcfs_nnetstrfns; i++) {
721                 nf = &libcfs_netstrfns[i];
722                 if (!strncmp(str, nf->nf_name, strlen(nf->nf_name)))
723                         break;
724         }
725
726         if (i == libcfs_nnetstrfns)
727                 return NULL;
728
729         nob = strlen(nf->nf_name);
730
731         if (strlen(str) == (unsigned int)nob) {
732                 netnum = 0;
733         } else {
734                 if (nf->nf_type == LOLND) /* net number not allowed */
735                         return NULL;
736
737                 str += nob;
738                 i = strlen(str);
739                 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
740                     i != (int)strlen(str))
741                         return NULL;
742         }
743
744         *net = LNET_MKNET(nf->nf_type, netnum);
745         return nf;
746 }
747
748 __u32
749 libcfs_str2net(const char *str)
750 {
751         __u32  net;
752
753         if (libcfs_str2net_internal(str, &net) != NULL)
754                 return net;
755
756         return LNET_NET_ANY;
757 }
758
759 lnet_nid_t
760 libcfs_str2nid(const char *str)
761 {
762         const char       *sep = strchr(str, '@');
763         struct netstrfns *nf;
764         __u32             net;
765         __u32             addr;
766
767         if (sep != NULL) {
768                 nf = libcfs_str2net_internal(sep + 1, &net);
769                 if (nf == NULL)
770                         return LNET_NID_ANY;
771         } else {
772                 sep = str + strlen(str);
773                 net = LNET_MKNET(SOCKLND, 0);
774                 nf = libcfs_lnd2netstrfns(SOCKLND);
775                 assert(nf != NULL);
776         }
777
778         if (!nf->nf_str2addr(str, (int)(sep - str), &addr))
779                 return LNET_NID_ANY;
780
781         return LNET_MKNID(net, addr);
782 }
783
784 char *
785 libcfs_id2str(struct lnet_process_id id)
786 {
787         char *str = libcfs_next_nidstring();
788
789         if (id.pid == LNET_PID_ANY) {
790                 snprintf(str, LNET_NIDSTR_SIZE,
791                          "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
792                 return str;
793         }
794
795         snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
796                  ((id.pid & LNET_PID_USERFLAG) != 0) ? "U" : "",
797                  (id.pid & ~LNET_PID_USERFLAG), libcfs_nid2str(id.nid));
798         return str;
799 }
800
801 int
802 libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
803 {
804         if (!strcmp(str, "*")) {
805                 *nidp = LNET_NID_ANY;
806                 return 1;
807         }
808
809         *nidp = libcfs_str2nid(str);
810         return *nidp != LNET_NID_ANY;
811 }
812
813 /**
814  * Nid range list syntax.
815  * \verbatim
816  *
817  * <nidlist>         :== <nidrange> [ ' ' <nidrange> ]
818  * <nidrange>        :== <addrrange> '@' <net>
819  * <addrrange>       :== '*' |
820  *                       <ipaddr_range> |
821  *                       <cfs_expr_list>
822  * <ipaddr_range>    :== <cfs_expr_list>.<cfs_expr_list>.<cfs_expr_list>.
823  *                       <cfs_expr_list>
824  * <cfs_expr_list>   :== <number> |
825  *                       <expr_list>
826  * <expr_list>       :== '[' <range_expr> [ ',' <range_expr>] ']'
827  * <range_expr>      :== <number> |
828  *                       <number> '-' <number> |
829  *                       <number> '-' <number> '/' <number>
830  * <net>             :== <netname> | <netname><number>
831  * <netname>         :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" |
832  *                       "vib" | "ra" | "elan" | "mx" | "ptl"
833  * \endverbatim
834  */
835
836 /**
837  * Structure to represent \<nidrange\> token of the syntax.
838  *
839  * One of this is created for each \<net\> parsed.
840  */
841 struct nidrange {
842         /**
843          * Link to list of this structures which is built on nid range
844          * list parsing.
845          */
846         struct list_head nr_link;
847         /**
848          * List head for addrrange::ar_link.
849          */
850         struct list_head nr_addrranges;
851         /**
852          * Flag indicating that *@<net> is found.
853          */
854         int nr_all;
855         /**
856          * Pointer to corresponding element of libcfs_netstrfns.
857          */
858         struct netstrfns *nr_netstrfns;
859         /**
860          * Number of network. E.g. 5 if \<net\> is "elan5".
861          */
862         int nr_netnum;
863 };
864
865 /**
866  * Structure to represent \<addrrange\> token of the syntax.
867  */
868 struct addrrange {
869         /**
870          * Link to nidrange::nr_addrranges.
871          */
872         struct list_head ar_link;
873         /**
874          * List head for cfs_expr_list::el_list.
875          */
876         struct list_head ar_numaddr_ranges;
877 };
878
879 /**
880  * Parses \<addrrange\> token on the syntax.
881  *
882  * Allocates struct addrrange and links to \a nidrange via
883  * (nidrange::nr_addrranges)
884  *
885  * \retval 0 if \a src parses to '*' | \<ipaddr_range\> | \<cfs_expr_list\>
886  * \retval -errno otherwise
887  */
888 static int
889 parse_addrange(const struct cfs_lstr *src, struct nidrange *nidrange)
890 {
891         struct addrrange *addrrange;
892
893         if (src->ls_len == 1 && src->ls_str[0] == '*') {
894                 nidrange->nr_all = 1;
895                 return 0;
896         }
897
898         addrrange = calloc(1, sizeof(struct addrrange));
899         if (addrrange == NULL)
900                 return -ENOMEM;
901         list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges);
902         INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges);
903
904         return nidrange->nr_netstrfns->nf_parse_addrlist(src->ls_str,
905                                                 src->ls_len,
906                                                 &addrrange->ar_numaddr_ranges);
907 }
908
909 /**
910  * Finds or creates struct nidrange.
911  *
912  * Checks if \a src is a valid network name, looks for corresponding
913  * nidrange on the ist of nidranges (\a nidlist), creates new struct
914  * nidrange if it is not found.
915  *
916  * \retval pointer to struct nidrange matching network specified via \a src
917  * \retval NULL if \a src does not match any network
918  */
919 static struct nidrange *
920 add_nidrange(const struct cfs_lstr *src,
921              struct list_head *nidlist)
922 {
923         struct netstrfns *nf;
924         struct nidrange *nr;
925         int endlen;
926         unsigned netnum;
927
928         if (src->ls_len >= LNET_NIDSTR_SIZE)
929                 return NULL;
930
931         nf = libcfs_namenum2netstrfns(src->ls_str);
932         if (nf == NULL)
933                 return NULL;
934         endlen = src->ls_len - strlen(nf->nf_name);
935         if (endlen == 0)
936                 /* network name only, e.g. "elan" or "tcp" */
937                 netnum = 0;
938         else {
939                 /* e.g. "elan25" or "tcp23", refuse to parse if
940                  * network name is not appended with decimal or
941                  * hexadecimal number */
942                 if (!cfs_str2num_check(src->ls_str + strlen(nf->nf_name),
943                                        endlen, &netnum, 0, MAX_NUMERIC_VALUE))
944                         return NULL;
945         }
946
947         list_for_each_entry(nr, nidlist, nr_link) {
948                 if (nr->nr_netstrfns != nf)
949                         continue;
950                 if (nr->nr_netnum != netnum)
951                         continue;
952                 return nr;
953         }
954
955         nr = calloc(1, sizeof(struct nidrange));
956         if (nr == NULL)
957                 return NULL;
958         list_add_tail(&nr->nr_link, nidlist);
959         INIT_LIST_HEAD(&nr->nr_addrranges);
960         nr->nr_netstrfns = nf;
961         nr->nr_all = 0;
962         nr->nr_netnum = netnum;
963
964         return nr;
965 }
966
967 /**
968  * Parses \<nidrange\> token of the syntax.
969  *
970  * \retval 1 if \a src parses to \<addrrange\> '@' \<net\>
971  * \retval 0 otherwise
972  */
973 static int
974 parse_nidrange(struct cfs_lstr *src, struct list_head *nidlist)
975 {
976         struct cfs_lstr addrrange;
977         struct cfs_lstr net;
978         struct cfs_lstr tmp;
979         struct nidrange *nr;
980
981         tmp = *src;
982         if (cfs_gettok(src, '@', &addrrange) == 0)
983                 goto failed;
984
985         if (cfs_gettok(src, '@', &net) == 0 || src->ls_str != NULL)
986                 goto failed;
987
988         nr = add_nidrange(&net, nidlist);
989         if (nr == NULL)
990                 goto failed;
991
992         if (parse_addrange(&addrrange, nr) != 0)
993                 goto failed;
994
995         return 1;
996  failed:
997         fprintf(stderr, "can't parse nidrange: \"%.*s\"\n",
998                 tmp.ls_len, tmp.ls_str);
999         return 0;
1000 }
1001
1002 static __u32
1003 libcfs_net_str_len(const char *str)
1004 {
1005         int i;
1006         struct netstrfns *nf = NULL;
1007
1008         for (i = 0; i < libcfs_nnetstrfns; i++) {
1009                 nf = &libcfs_netstrfns[i];
1010                 if (!strncmp(str, nf->nf_name, strlen(nf->nf_name)))
1011                         return strlen(nf->nf_name);
1012         }
1013
1014         return 0;
1015 }
1016
1017 int
1018 parse_net_range(char *str, __u32 len, struct list_head *net_num,
1019                 __u32 *net_type)
1020 {
1021         struct cfs_lstr next;
1022         __u32 net_type_len;
1023         __u32 net;
1024         char *bracket;
1025         char *star;
1026
1027         if (!str)
1028                 return -EINVAL;
1029
1030         next.ls_str = str;
1031         next.ls_len = len;
1032
1033         net_type_len = libcfs_net_str_len(str);
1034
1035         if (net_type_len < len) {
1036                 char c = str[net_type_len];
1037
1038                 str[net_type_len] = '\0';
1039                 net = libcfs_str2net(str);
1040                 str[net_type_len] = c;
1041         } else {
1042                 net = libcfs_str2net(str);
1043         }
1044
1045         if (net == LNET_NIDNET(LNET_NID_ANY))
1046                 return -EINVAL;
1047
1048         *net_type = LNET_NETTYP(net);
1049
1050         /*
1051          * the net is either followed with an absolute number, *, or an
1052          * expression enclosed in []
1053          */
1054         bracket = strchr(next.ls_str, '[');
1055         star = strchr(next.ls_str, '*');
1056
1057         /* "*[" pattern not allowed */
1058         if (bracket && star && star < bracket)
1059                 return -EINVAL;
1060
1061         if (!bracket) {
1062                 next.ls_str = str + net_type_len;
1063                 next.ls_len = strlen(next.ls_str);
1064         } else {
1065                 next.ls_str = bracket;
1066                 next.ls_len = strlen(bracket);
1067         }
1068
1069         /* if there is no net number just return */
1070         if (next.ls_len == 0)
1071                 return 0;
1072
1073         return libcfs_num_parse(next.ls_str, next.ls_len,
1074                                 net_num);
1075 }
1076
1077 int
1078 parse_address(struct cfs_lstr *src, const __u32 net_type,
1079               struct list_head *addr)
1080 {
1081         int i;
1082         struct netstrfns *nf = NULL;
1083
1084         for (i = 0; i < libcfs_nnetstrfns; i++) {
1085                 nf = &libcfs_netstrfns[i];
1086                 if (net_type == nf->nf_type)
1087                         return nf->nf_parse_addrlist(src->ls_str, src->ls_len,
1088                                                      addr);
1089         }
1090
1091         return -EINVAL;
1092 }
1093
1094 int
1095 cfs_parse_nid_parts(char *str, struct list_head *addr,
1096                     struct list_head *net_num, __u32 *net_type)
1097 {
1098         struct cfs_lstr next;
1099         struct cfs_lstr addrrange;
1100         bool found = false;
1101         int rc;
1102
1103         if (!str)
1104                 return -EINVAL;
1105
1106         next.ls_str = str;
1107         next.ls_len = strlen(str);
1108
1109         rc = cfs_gettok(&next, '@', &addrrange);
1110         if (!rc)
1111                 return -EINVAL;
1112
1113         if (!next.ls_str) {
1114                 /* only net is present */
1115                 next.ls_str = str;
1116                 next.ls_len = strlen(str);
1117         } else {
1118                 found = true;
1119         }
1120
1121         /* assume only net is present */
1122         rc = parse_net_range(next.ls_str, next.ls_len, net_num, net_type);
1123
1124         /*
1125          * if we successfully parsed the net range and there is no
1126          * address, or if we fail to parse the net range then return
1127          */
1128         if ((!rc && !found) || rc)
1129                 return rc;
1130
1131         return parse_address(&addrrange, *net_type, addr);
1132 }
1133
1134 /**
1135  * Frees addrrange structures of \a list.
1136  *
1137  * For each struct addrrange structure found on \a list it frees
1138  * cfs_expr_list list attached to it and frees the addrrange itself.
1139  *
1140  * \retval none
1141  */
1142 static void
1143 free_addrranges(struct list_head *list)
1144 {
1145         while (!list_empty(list)) {
1146                 struct addrrange *ar;
1147
1148                 ar = list_entry(list->next, struct addrrange, ar_link);
1149
1150                 cfs_expr_list_free_list(&ar->ar_numaddr_ranges);
1151                 list_del(&ar->ar_link);
1152                 free(ar);
1153         }
1154 }
1155
1156 /**
1157  * Frees nidrange strutures of \a list.
1158  *
1159  * For each struct nidrange structure found on \a list it frees
1160  * addrrange list attached to it and frees the nidrange itself.
1161  *
1162  * \retval none
1163  */
1164 void
1165 cfs_free_nidlist(struct list_head *list)
1166 {
1167         struct list_head *pos, *next;
1168         struct nidrange *nr;
1169
1170         list_for_each_safe(pos, next, list) {
1171                 nr = list_entry(pos, struct nidrange, nr_link);
1172                 free_addrranges(&nr->nr_addrranges);
1173                 list_del(pos);
1174                 free(nr);
1175         }
1176 }
1177
1178 /**
1179  * Parses nid range list.
1180  *
1181  * Parses with rigorous syntax and overflow checking \a str into
1182  * \<nidrange\> [ ' ' \<nidrange\> ], compiles \a str into set of
1183  * structures and links that structure to \a nidlist. The resulting
1184  * list can be used to match a NID againts set of NIDS defined by \a
1185  * str.
1186  * \see cfs_match_nid
1187  *
1188  * \retval 1 on success
1189  * \retval 0 otherwise
1190  */
1191 int
1192 cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
1193 {
1194         struct cfs_lstr src;
1195         struct cfs_lstr res;
1196         int rc;
1197
1198         src.ls_str = str;
1199         src.ls_len = len;
1200         INIT_LIST_HEAD(nidlist);
1201         while (src.ls_str) {
1202                 rc = cfs_gettok(&src, ' ', &res);
1203                 if (rc == 0) {
1204                         cfs_free_nidlist(nidlist);
1205                         return 0;
1206                 }
1207                 rc = parse_nidrange(&res, nidlist);
1208                 if (rc == 0) {
1209                         cfs_free_nidlist(nidlist);
1210                         return 0;
1211                 }
1212         }
1213         return 1;
1214 }
1215
1216 /**
1217  * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
1218  *
1219  * \see cfs_parse_nidlist()
1220  *
1221  * \retval 1 on match
1222  * \retval 0  otherwises
1223  */
1224 int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist)
1225 {
1226         struct nidrange *nr;
1227         struct addrrange *ar;
1228
1229         list_for_each_entry(nr, nidlist, nr_link) {
1230                 if (nr->nr_netstrfns->nf_type != LNET_NETTYP(LNET_NIDNET(nid)))
1231                         continue;
1232                 if (nr->nr_netnum != LNET_NETNUM(LNET_NIDNET(nid)))
1233                         continue;
1234                 if (nr->nr_all)
1235                         return 1;
1236                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
1237                         if (nr->nr_netstrfns->nf_match_addr(LNET_NIDADDR(nid),
1238                                                         &ar->ar_numaddr_ranges))
1239                                 return 1;
1240         }
1241         return 0;
1242 }
1243
1244 int
1245 cfs_match_net(__u32 net_id, __u32 net_type, struct list_head *net_num_list)
1246 {
1247         __u32 net_num;
1248
1249         if (!net_num_list)
1250                 return 0;
1251
1252         if (net_type != LNET_NETTYP(net_id))
1253                 return 0;
1254
1255         net_num = LNET_NETNUM(net_id);
1256
1257         /*
1258          * if there is a net number but the list passed in is empty, then
1259          * there is no match.
1260          */
1261         if (!net_num && list_empty(net_num_list))
1262                 return 1;
1263         else if (list_empty(net_num_list))
1264                 return 0;
1265
1266         if (!libcfs_num_match(net_num, net_num_list))
1267                 return 0;
1268
1269         return 1;
1270 }
1271
1272 /**
1273  * Print the network part of the nidrange \a nr into the specified \a buffer.
1274  *
1275  * \retval number of characters written
1276  */
1277 static int
1278 cfs_print_network(char *buffer, int count, struct nidrange *nr)
1279 {
1280         struct netstrfns *nf = nr->nr_netstrfns;
1281
1282         if (nr->nr_netnum == 0)
1283                 return scnprintf(buffer, count, "@%s", nf->nf_name);
1284         else
1285                 return scnprintf(buffer, count, "@%s%u",
1286                                  nf->nf_name, nr->nr_netnum);
1287 }
1288
1289
1290 /**
1291  * Print a list of addrrange (\a addrranges) into the specified \a buffer.
1292  * At max \a count characters can be printed into \a buffer.
1293  *
1294  * \retval number of characters written
1295  */
1296 static int
1297 cfs_print_addrranges(char *buffer, int count, struct list_head *addrranges,
1298                      struct nidrange *nr)
1299 {
1300         int i = 0;
1301         struct addrrange *ar;
1302         struct netstrfns *nf = nr->nr_netstrfns;
1303
1304         list_for_each_entry(ar, addrranges, ar_link) {
1305                 if (i != 0)
1306                         i += scnprintf(buffer + i, count - i, " ");
1307                 i += nf->nf_print_addrlist(buffer + i, count - i,
1308                                            &ar->ar_numaddr_ranges);
1309                 i += cfs_print_network(buffer + i, count - i, nr);
1310         }
1311         return i;
1312 }
1313
1314 /**
1315  * Print a list of nidranges (\a nidlist) into the specified \a buffer.
1316  * At max \a count characters can be printed into \a buffer.
1317  * Nidranges are separated by a space character.
1318  *
1319  * \retval number of characters written
1320  */
1321 int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist)
1322 {
1323         int i = 0;
1324         struct nidrange *nr;
1325
1326         if (count <= 0)
1327                 return 0;
1328
1329         list_for_each_entry(nr, nidlist, nr_link) {
1330                 if (i != 0)
1331                         i += scnprintf(buffer + i, count - i, " ");
1332
1333                 if (nr->nr_all != 0) {
1334                         assert(list_empty(&nr->nr_addrranges));
1335                         i += scnprintf(buffer + i, count - i, "*");
1336                         i += cfs_print_network(buffer + i, count - i, nr);
1337                 } else {
1338                         i += cfs_print_addrranges(buffer + i, count - i,
1339                                                   &nr->nr_addrranges, nr);
1340                 }
1341         }
1342         return i;
1343 }
1344
1345 /**
1346  * Determines minimum and maximum addresses for a single
1347  * numeric address range
1348  *
1349  * \param       ar
1350  * \param[out]  *min_nid __u32 representation of min NID
1351  * \param[out]  *max_nid __u32 representation of max NID
1352  * \retval      -EINVAL unsupported LNET range
1353  * \retval      -ERANGE non-contiguous LNET range
1354  */
1355 static int cfs_ip_ar_min_max(struct addrrange *ar, __u32 *min_nid,
1356                               __u32 *max_nid)
1357 {
1358         struct cfs_expr_list *expr_list;
1359         struct cfs_range_expr *range;
1360         unsigned int min_ip[4] = {0};
1361         unsigned int max_ip[4] = {0};
1362         int cur_octet = 0;
1363         bool expect_full_octet = false;
1364
1365         list_for_each_entry(expr_list, &ar->ar_numaddr_ranges, el_link) {
1366                 int re_count = 0;
1367
1368                 list_for_each_entry(range, &expr_list->el_exprs, re_link) {
1369                         /* XXX: add support for multiple & non-contig. re's */
1370                         if (re_count > 0)
1371                                 return -EINVAL;
1372
1373                         /* if a previous octet was ranged, then all remaining
1374                          * octets must be full for contiguous range */
1375                         if (expect_full_octet && (range->re_lo != 0 ||
1376                                                   range->re_hi != 255))
1377                                 return -ERANGE;
1378
1379                         if (range->re_stride != 1)
1380                                 return -ERANGE;
1381
1382                         if (range->re_lo > range->re_hi)
1383                                 return -EINVAL;
1384
1385                         if (range->re_lo != range->re_hi)
1386                                 expect_full_octet = true;
1387
1388                         min_ip[cur_octet] = range->re_lo;
1389                         max_ip[cur_octet] = range->re_hi;
1390
1391                         re_count++;
1392                 }
1393
1394                 cur_octet++;
1395         }
1396
1397         if (min_nid != NULL)
1398                 *min_nid = ((min_ip[0] << 24) | (min_ip[1] << 16) |
1399                             (min_ip[2] << 8) | min_ip[3]);
1400
1401         if (max_nid != NULL)
1402                 *max_nid = ((max_ip[0] << 24) | (max_ip[1] << 16) |
1403                             (max_ip[2] << 8) | max_ip[3]);
1404
1405         return 0;
1406 }
1407
1408 /**
1409  * Determines minimum and maximum addresses for a single
1410  * numeric address range
1411  *
1412  * \param       ar
1413  * \param[out]  *min_nid __u32 representation of min NID
1414  * \param[out]  *max_nid __u32 representation of max NID
1415  * \retval      -EINVAL unsupported LNET range
1416  */
1417 static int cfs_num_ar_min_max(struct addrrange *ar, __u32 *min_nid,
1418                                __u32 *max_nid)
1419 {
1420         struct cfs_expr_list *el;
1421         struct cfs_range_expr *re;
1422         unsigned int min_addr = 0;
1423         unsigned int max_addr = 0;
1424
1425         list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) {
1426                 int re_count = 0;
1427
1428                 list_for_each_entry(re, &el->el_exprs, re_link) {
1429                         if (re_count > 0)
1430                                 return -EINVAL;
1431                         if (re->re_lo > re->re_hi)
1432                                 return -EINVAL;
1433
1434                         if (re->re_lo < min_addr || min_addr == 0)
1435                                 min_addr = re->re_lo;
1436                         if (re->re_hi > max_addr)
1437                                 max_addr = re->re_hi;
1438
1439                         re_count++;
1440                 }
1441         }
1442
1443         if (min_nid != NULL)
1444                 *min_nid = min_addr;
1445         if (max_nid != NULL)
1446                 *max_nid = max_addr;
1447
1448         return 0;
1449 }
1450
1451 /**
1452  * Takes a linked list of nidrange expressions, determines the minimum
1453  * and maximum nid and creates appropriate nid structures
1454  *
1455  * \param       *nidlist
1456  * \param[out]  *min_nid string representation of min NID
1457  * \param[out]  *max_nid string representation of max NID
1458  * \retval      -EINVAL unsupported LNET range
1459  * \retval      -ERANGE non-contiguous LNET range
1460  */
1461 int cfs_nidrange_find_min_max(struct list_head *nidlist, char *min_nid,
1462                               char *max_nid, size_t nidstr_length)
1463 {
1464         struct nidrange *first_nidrange;
1465         int netnum;
1466         struct netstrfns *nf;
1467         char *lndname;
1468         __u32 min_addr;
1469         __u32 max_addr;
1470         char min_addr_str[IPSTRING_LENGTH];
1471         char max_addr_str[IPSTRING_LENGTH];
1472         int rc;
1473
1474         first_nidrange = list_entry(nidlist->next, struct nidrange, nr_link);
1475
1476         netnum = first_nidrange->nr_netnum;
1477         nf = first_nidrange->nr_netstrfns;
1478         lndname = nf->nf_name;
1479
1480         rc = nf->nf_min_max(nidlist, &min_addr, &max_addr);
1481         if (rc < 0)
1482                 return rc;
1483
1484         nf->nf_addr2str(min_addr, min_addr_str, sizeof(min_addr_str));
1485         nf->nf_addr2str(max_addr, max_addr_str, sizeof(max_addr_str));
1486
1487         snprintf(min_nid, nidstr_length, "%s@%s%d", min_addr_str, lndname,
1488                  netnum);
1489         snprintf(max_nid, nidstr_length, "%s@%s%d", max_addr_str, lndname,
1490                  netnum);
1491
1492         return 0;
1493 }
1494
1495 /**
1496  * Determines the min and max NID values for num LNDs
1497  *
1498  * \param       *nidlist
1499  * \param[out]  *min_nid if provided, returns string representation of min NID
1500  * \param[out]  *max_nid if provided, returns string representation of max NID
1501  * \retval      -EINVAL unsupported LNET range
1502  * \retval      -ERANGE non-contiguous LNET range
1503  */
1504 static int cfs_num_min_max(struct list_head *nidlist, __u32 *min_nid,
1505                             __u32 *max_nid)
1506 {
1507         struct nidrange *nr;
1508         struct addrrange *ar;
1509         unsigned int tmp_min_addr = 0;
1510         unsigned int tmp_max_addr = 0;
1511         unsigned int min_addr = 0;
1512         unsigned int max_addr = 0;
1513         int nidlist_count = 0;
1514         int rc;
1515
1516         list_for_each_entry(nr, nidlist, nr_link) {
1517                 if (nidlist_count > 0)
1518                         return -EINVAL;
1519
1520                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1521                         rc = cfs_num_ar_min_max(ar, &tmp_min_addr,
1522                                                 &tmp_max_addr);
1523                         if (rc < 0)
1524                                 return rc;
1525
1526                         if (tmp_min_addr < min_addr || min_addr == 0)
1527                                 min_addr = tmp_min_addr;
1528                         if (tmp_max_addr > max_addr)
1529                                 max_addr = tmp_min_addr;
1530                 }
1531         }
1532         if (max_nid != NULL)
1533                 *max_nid = max_addr;
1534         if (min_nid != NULL)
1535                 *min_nid = min_addr;
1536
1537         return 0;
1538 }
1539
1540 /**
1541  * Takes an nidlist and determines the minimum and maximum
1542  * ip addresses.
1543  *
1544  * \param       *nidlist
1545  * \param[out]  *min_nid if provided, returns string representation of min NID
1546  * \param[out]  *max_nid if provided, returns string representation of max NID
1547  * \retval      -EINVAL unsupported LNET range
1548  * \retval      -ERANGE non-contiguous LNET range
1549  */
1550 static int cfs_ip_min_max(struct list_head *nidlist, __u32 *min_nid,
1551                            __u32 *max_nid)
1552 {
1553         struct nidrange *nr;
1554         struct addrrange *ar;
1555         __u32 tmp_min_ip_addr = 0;
1556         __u32 tmp_max_ip_addr = 0;
1557         __u32 min_ip_addr = 0;
1558         __u32 max_ip_addr = 0;
1559         int nidlist_count = 0;
1560         int rc;
1561
1562         list_for_each_entry(nr, nidlist, nr_link) {
1563                 if (nidlist_count > 0)
1564                         return -EINVAL;
1565
1566                 if (nr->nr_all) {
1567                         min_ip_addr = 0;
1568                         max_ip_addr = 0xffffffff;
1569                         break;
1570                 }
1571
1572                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1573                         rc = cfs_ip_ar_min_max(ar, &tmp_min_ip_addr,
1574                                                &tmp_max_ip_addr);
1575                         if (rc < 0)
1576                                 return rc;
1577
1578                         if (tmp_min_ip_addr < min_ip_addr || min_ip_addr == 0)
1579                                 min_ip_addr = tmp_min_ip_addr;
1580                         if (tmp_max_ip_addr > max_ip_addr)
1581                                 max_ip_addr = tmp_max_ip_addr;
1582                 }
1583
1584                 nidlist_count++;
1585         }
1586
1587         if (max_nid != NULL)
1588                 *max_nid = max_ip_addr;
1589         if (min_nid != NULL)
1590                 *min_nid = min_ip_addr;
1591
1592         return 0;
1593 }
1594
1595 static int
1596 libcfs_expand_nidrange(struct nidrange *nr, __u32 *addrs, int max_nids)
1597 {
1598         struct addrrange *ar;
1599         int rc = 0, count = max_nids;
1600         struct netstrfns *nf = nr->nr_netstrfns;
1601
1602         list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1603                 rc = nf->nf_expand_addrrange(&ar->ar_numaddr_ranges, addrs,
1604                                              count);
1605                 if (rc < 0)
1606                         return rc;
1607
1608                 count -= rc;
1609         }
1610
1611         return max_nids - count;
1612 }
1613
1614 int cfs_expand_nidlist(struct list_head *nidlist, lnet_nid_t *lnet_nidlist,
1615                        int max_nids)
1616 {
1617         struct nidrange *nr;
1618         int rc = 0, count = max_nids;
1619         int i, j = 0;
1620         __u32 *addrs;
1621         struct netstrfns *nf;
1622         __u32 net;
1623
1624         addrs = calloc(max_nids, sizeof(__u32));
1625         if (!addrs)
1626                 return -ENOMEM;
1627
1628         list_for_each_entry(nr, nidlist, nr_link) {
1629                 rc = libcfs_expand_nidrange(nr, addrs, count);
1630
1631                 if (rc < 0) {
1632                         free(addrs);
1633                         return rc;
1634                 }
1635
1636                 nf = nr->nr_netstrfns;
1637                 net = LNET_MKNET(nf->nf_type, nr->nr_netnum);
1638
1639                 for (i = count - 1; i >= count - rc; i--)
1640                         lnet_nidlist[j++] = LNET_MKNID(net, addrs[i]);
1641
1642                 count -= rc;
1643         }
1644
1645         free(addrs);
1646         return max_nids - count;
1647 }