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