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