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