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