Whamcloud - gitweb
d5830f3a23639454857f804a08b9c22f79a009c6
[fs/lustre-release.git] / libcfs / libcfs / 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.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2012, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * libcfs/libcfs/nidstrings.c
37  *
38  * Author: Phil Schwan <phil@clusterfs.com>
39  */
40
41 #define DEBUG_SUBSYSTEM S_LNET
42
43 #include <libcfs/libcfs.h>
44 #include <lnet/lnet.h>
45 #ifndef __KERNEL__
46 #ifdef HAVE_GETHOSTBYNAME
47 # include <netdb.h>
48 #endif
49 #endif
50
51 #define IPSTRING_LENGTH 16
52
53 /* CAVEAT VENDITOR! Keep the canonical string representation of nets/nids
54  * consistent in all conversion functions.  Some code fragments are copied
55  * around for the sake of clarity...
56  */
57
58 /* CAVEAT EMPTOR! Racey temporary buffer allocation!
59  * Choose the number of nidstrings to support the MAXIMUM expected number of
60  * concurrent users.  If there are more, the returned string will be volatile.
61  * NB this number must allow for a process to be descheduled for a timeslice
62  * between getting its string and using it.
63  */
64
65 static char      libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE];
66 static int       libcfs_nidstring_idx = 0;
67
68 #ifdef __KERNEL__
69 static spinlock_t libcfs_nidstring_lock;
70
71 void libcfs_init_nidstrings (void)
72 {
73         spin_lock_init(&libcfs_nidstring_lock);
74 }
75
76 # define NIDSTR_LOCK(f)   spin_lock_irqsave(&libcfs_nidstring_lock, f)
77 # define NIDSTR_UNLOCK(f) spin_unlock_irqrestore(&libcfs_nidstring_lock, f)
78 #else
79 # define NIDSTR_LOCK(f)   (f=sizeof(f))  /* avoid set-but-unused warnings */
80 # define NIDSTR_UNLOCK(f) (f=sizeof(f))
81 #endif
82
83 static char *
84 libcfs_next_nidstring (void)
85 {
86         char          *str;
87         unsigned long  flags;
88
89         NIDSTR_LOCK(flags);
90
91         str = libcfs_nidstrings[libcfs_nidstring_idx++];
92         if (libcfs_nidstring_idx ==
93             sizeof(libcfs_nidstrings)/sizeof(libcfs_nidstrings[0]))
94                 libcfs_nidstring_idx = 0;
95
96         NIDSTR_UNLOCK(flags);
97         return str;
98 }
99
100 static int  libcfs_lo_str2addr(const char *str, int nob, __u32 *addr);
101 static void libcfs_ip_addr2str(__u32 addr, char *str);
102 static int  libcfs_ip_str2addr(const char *str, int nob, __u32 *addr);
103 static bool cfs_ip_is_contiguous(struct list_head *nidlist);
104 static void cfs_ip_min_max(struct list_head *nidlist, __u32 *min, __u32 *max);
105 static void libcfs_decnum_addr2str(__u32 addr, char *str);
106 static void libcfs_hexnum_addr2str(__u32 addr, char *str);
107 static int  libcfs_num_str2addr(const char *str, int nob, __u32 *addr);
108 static int  libcfs_num_parse(char *str, int len, struct list_head *list);
109 static int  libcfs_num_match(__u32 addr, struct list_head *list);
110 static int  libcfs_num_addr_range_print(char *buffer, int count,
111                                         struct list_head *list);
112 static int  libcfs_ip_addr_range_print(char *buffer, int count,
113                                        struct list_head *list);
114 static bool cfs_num_is_contiguous(struct list_head *nidlist);
115 static void cfs_num_min_max(struct list_head *nidlist, __u32 *min, __u32 *max);
116
117 struct netstrfns {
118         int      nf_type;
119         char    *nf_name;
120         char    *nf_modname;
121         void    (*nf_addr2str)(__u32 addr, char *str);
122         int     (*nf_str2addr)(const char *str, int nob, __u32 *addr);
123         int     (*nf_parse_addrlist)(char *str, int len,
124                                         struct list_head *list);
125         int     (*nf_print_addrlist)(char *buffer, int count,
126                                      struct list_head *list);
127         int     (*nf_match_addr)(__u32 addr, struct list_head *list);
128         bool    (*nf_is_contiguous)(struct list_head *nidlist);
129         void    (*nf_min_max)(struct list_head *nidlist, __u32 *min_nid,
130                                 __u32 *max_nid);
131 };
132
133 static struct netstrfns  libcfs_netstrfns[] = {
134         {/* .nf_type      */  LOLND,
135          /* .nf_name      */  "lo",
136          /* .nf_modname   */  "klolnd",
137          /* .nf_addr2str  */  libcfs_decnum_addr2str,
138          /* .nf_str2addr  */  libcfs_lo_str2addr,
139          /* .nf_parse_addr*/  libcfs_num_parse,
140          /* .nf_print_addrlist*/  libcfs_num_addr_range_print,
141          /* .nf_match_addr*/      libcfs_num_match,
142          /* .nf_is_contiguous */  cfs_num_is_contiguous,
143          /* .nf_min_max   */      cfs_num_min_max},
144         {/* .nf_type      */  SOCKLND,
145          /* .nf_name      */  "tcp",
146          /* .nf_modname   */  "ksocklnd",
147          /* .nf_addr2str  */  libcfs_ip_addr2str,
148          /* .nf_str2addr  */  libcfs_ip_str2addr,
149          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
150          /* .nf_print_addrlist*/  libcfs_ip_addr_range_print,
151          /* .nf_match_addr*/      cfs_ip_addr_match,
152          /* .nf_is_contiguous */  cfs_ip_is_contiguous,
153          /* .nf_min_max   */      cfs_ip_min_max},
154         {/* .nf_type      */  O2IBLND,
155          /* .nf_name      */  "o2ib",
156          /* .nf_modname   */  "ko2iblnd",
157          /* .nf_addr2str  */  libcfs_ip_addr2str,
158          /* .nf_str2addr  */  libcfs_ip_str2addr,
159          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
160          /* .nf_print_addrlist*/  libcfs_ip_addr_range_print,
161          /* .nf_match_addr*/      cfs_ip_addr_match,
162          /* .nf_is_contiguous */  cfs_ip_is_contiguous,
163          /* .nf_min_max   */      cfs_ip_min_max},
164         {/* .nf_type      */  CIBLND,
165          /* .nf_name      */  "cib",
166          /* .nf_modname   */  "kciblnd",
167          /* .nf_addr2str  */  libcfs_ip_addr2str,
168          /* .nf_str2addr  */  libcfs_ip_str2addr,
169          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
170          /* .nf_print_addrlist*/  libcfs_ip_addr_range_print,
171          /* .nf_match_addr*/      cfs_ip_addr_match,
172          /* .nf_is_contiguous */  cfs_ip_is_contiguous,
173          /* .nf_min_max   */      cfs_ip_min_max},
174         {/* .nf_type      */  OPENIBLND,
175          /* .nf_name      */  "openib",
176          /* .nf_modname   */  "kopeniblnd",
177          /* .nf_addr2str  */  libcfs_ip_addr2str,
178          /* .nf_str2addr  */  libcfs_ip_str2addr,
179          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
180          /* .nf_print_addrlist*/  libcfs_ip_addr_range_print,
181          /* .nf_match_addr*/      cfs_ip_addr_match,
182          /* .nf_is_contiguous */  cfs_ip_is_contiguous,
183          /* .nf_min_max   */      cfs_ip_min_max},
184         {/* .nf_type      */  IIBLND,
185          /* .nf_name      */  "iib",
186          /* .nf_modname   */  "kiiblnd",
187          /* .nf_addr2str  */  libcfs_ip_addr2str,
188          /* .nf_str2addr  */  libcfs_ip_str2addr,
189          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
190          /* .nf_print_addrlist*/  libcfs_ip_addr_range_print,
191          /* .nf_match_addr*/      cfs_ip_addr_match,
192          /* .nf_is_contiguous */  cfs_ip_is_contiguous,
193          /* .nf_min_max   */      cfs_ip_min_max},
194         {/* .nf_type      */  VIBLND,
195          /* .nf_name      */  "vib",
196          /* .nf_modname   */  "kviblnd",
197          /* .nf_addr2str  */  libcfs_ip_addr2str,
198          /* .nf_str2addr  */  libcfs_ip_str2addr,
199          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
200          /* .nf_print_addrlist*/  libcfs_ip_addr_range_print,
201          /* .nf_match_addr*/      cfs_ip_addr_match,
202          /* .nf_is_contiguous */  cfs_ip_is_contiguous,
203          /* .nf_min_max   */      cfs_ip_min_max},
204         {/* .nf_type      */  RALND,
205          /* .nf_name      */  "ra",
206          /* .nf_modname   */  "kralnd",
207          /* .nf_addr2str  */  libcfs_ip_addr2str,
208          /* .nf_str2addr  */  libcfs_ip_str2addr,
209          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
210          /* .nf_print_addrlist*/  libcfs_ip_addr_range_print,
211          /* .nf_match_addr*/      cfs_ip_addr_match,
212          /* .nf_is_contiguous */  cfs_ip_is_contiguous,
213          /* .nf_min_max   */      cfs_ip_min_max},
214         {/* .nf_type      */      QSWLND,
215          /* .nf_name      */      "elan",
216          /* .nf_modname   */      "kqswlnd",
217          /* .nf_addr2str  */      libcfs_decnum_addr2str,
218          /* .nf_str2addr  */      libcfs_num_str2addr,
219          /* .nf_parse_addrlist*/  libcfs_num_parse,
220          /* .nf_print_addrlist*/  libcfs_num_addr_range_print,
221          /* .nf_match_addr*/      libcfs_num_match,
222          /* .nf_is_contiguous */  cfs_num_is_contiguous,
223          /* .nf_min_max   */      cfs_num_min_max},
224         {/* .nf_type      */      GMLND,
225          /* .nf_name      */      "gm",
226          /* .nf_modname   */      "kgmlnd",
227          /* .nf_addr2str  */      libcfs_hexnum_addr2str,
228          /* .nf_str2addr  */      libcfs_num_str2addr,
229          /* .nf_parse_addrlist*/  libcfs_num_parse,
230          /* .nf_print_addrlist*/  libcfs_num_addr_range_print,
231          /* .nf_match_addr*/      libcfs_num_match,
232          /* .nf_is_contiguous */  cfs_num_is_contiguous,
233          /* .nf_min_max   */      cfs_num_min_max},
234         {/* .nf_type      */      MXLND,
235          /* .nf_name      */      "mx",
236          /* .nf_modname   */      "kmxlnd",
237          /* .nf_addr2str  */      libcfs_ip_addr2str,
238          /* .nf_str2addr  */      libcfs_ip_str2addr,
239          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
240          /* .nf_print_addrlist*/  libcfs_ip_addr_range_print,
241          /* .nf_match_addr*/      cfs_ip_addr_match,
242          /* .nf_is_contiguous */  cfs_ip_is_contiguous,
243          /* .nf_min_max   */      cfs_ip_min_max},
244         {/* .nf_type      */      PTLLND,
245          /* .nf_name      */      "ptl",
246          /* .nf_modname   */      "kptllnd",
247          /* .nf_addr2str  */      libcfs_decnum_addr2str,
248          /* .nf_str2addr  */      libcfs_num_str2addr,
249          /* .nf_parse_addrlist*/  libcfs_num_parse,
250          /* .nf_print_addrlist*/  libcfs_num_addr_range_print,
251          /* .nf_match_addr*/      libcfs_num_match,
252          /* .nf_is_contiguous */  cfs_num_is_contiguous,
253          /* .nf_min_max   */      cfs_num_min_max},
254         {/* .nf_type      */      GNILND,
255          /* .nf_name      */      "gni",
256          /* .nf_modname   */      "kgnilnd",
257          /* .nf_addr2str  */      libcfs_decnum_addr2str,
258          /* .nf_str2addr  */      libcfs_num_str2addr,
259          /* .nf_parse_addrlist*/  libcfs_num_parse,
260          /* .nf_print_addrlist*/  libcfs_num_addr_range_print,
261          /* .nf_match_addr*/      libcfs_num_match,
262          /* .nf_is_contiguous */  cfs_num_is_contiguous,
263          /* .nf_min_max   */      cfs_num_min_max},
264         {/* .nf_type      */      GNIIPLND,
265          /* .nf_name      */      "gip",
266          /* .nf_modname   */      "kgnilnd",
267          /* .nf_addr2str  */      libcfs_ip_addr2str,
268          /* .nf_str2addr  */      libcfs_ip_str2addr,
269          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
270          /* .nf_print_addrlist*/  libcfs_ip_addr_range_print,
271          /* .nf_match_addr*/      cfs_ip_addr_match,
272          /* .nf_is_contiguous */  cfs_ip_is_contiguous,
273          /* .nf_min_max   */      cfs_ip_min_max},
274          /* placeholder for net0 alias.  It MUST BE THE LAST ENTRY */
275         {/* .nf_type      */  -1},
276 };
277
278 const int libcfs_nnetstrfns = sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
279
280 int
281 libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
282 {
283         *addr = 0;
284         return 1;
285 }
286
287 void
288 libcfs_ip_addr2str(__u32 addr, char *str)
289 {
290 #if 0   /* never lookup */
291 #if !defined(__KERNEL__) && defined HAVE_GETHOSTBYNAME
292         __u32           netip = htonl(addr);
293         struct hostent *he = gethostbyaddr(&netip, sizeof(netip), AF_INET);
294
295         if (he != NULL) {
296                 snprintf(str, LNET_NIDSTR_SIZE, "%s", he->h_name);
297                 return;
298         }
299 #endif
300 #endif
301         snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u",
302                  (addr >> 24) & 0xff, (addr >> 16) & 0xff,
303                  (addr >> 8) & 0xff, addr & 0xff);
304 }
305
306 /* CAVEAT EMPTOR XscanfX
307  * I use "%n" at the end of a sscanf format to detect trailing junk.  However
308  * sscanf may return immediately if it sees the terminating '0' in a string, so
309  * I initialise the %n variable to the expected length.  If sscanf sets it;
310  * fine, if it doesn't, then the scan ended at the end of the string, which is
311  * fine too :) */
312
313 int
314 libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
315 {
316         unsigned int    a;
317         unsigned int    b;
318         unsigned int    c;
319         unsigned int    d;
320         int             n = nob; /* XscanfX */
321
322         /* numeric IP? */
323         if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
324             n == nob &&
325             (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
326             (c & ~0xff) == 0 && (d & ~0xff) == 0) {
327                 *addr = ((a<<24)|(b<<16)|(c<<8)|d);
328                 return 1;
329         }
330
331 #if !defined(__KERNEL__) && defined HAVE_GETHOSTBYNAME
332         /* known hostname? */
333         if (('a' <= str[0] && str[0] <= 'z') ||
334             ('A' <= str[0] && str[0] <= 'Z')) {
335                 char *tmp;
336
337                 LIBCFS_ALLOC(tmp, nob + 1);
338                 if (tmp != NULL) {
339                         struct hostent *he;
340
341                         memcpy(tmp, str, nob);
342                         tmp[nob] = 0;
343
344                         he = gethostbyname(tmp);
345
346                         LIBCFS_FREE(tmp, nob);
347
348                         if (he != NULL) {
349                                 __u32 ip = *(__u32 *)he->h_addr;
350
351                                 *addr = ntohl(ip);
352                                 return 1;
353                         }
354                 }
355         }
356 #endif
357         return 0;
358 }
359
360 void
361 libcfs_decnum_addr2str(__u32 addr, char *str)
362 {
363         snprintf(str, LNET_NIDSTR_SIZE, "%u", addr);
364 }
365
366 void
367 libcfs_hexnum_addr2str(__u32 addr, char *str)
368 {
369         snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr);
370 }
371
372 int
373 libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
374 {
375         int     n;
376
377         n = nob;
378         if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
379                 return 1;
380
381         n = nob;
382         if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
383                 return 1;
384
385         n = nob;
386         if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
387                 return 1;
388
389         return 0;
390 }
391
392 struct netstrfns *
393 libcfs_lnd2netstrfns(int lnd)
394 {
395         int    i;
396
397         if (lnd >= 0)
398                 for (i = 0; i < libcfs_nnetstrfns; i++)
399                         if (lnd == libcfs_netstrfns[i].nf_type)
400                                 return &libcfs_netstrfns[i];
401
402         return NULL;
403 }
404
405 struct netstrfns *
406 libcfs_namenum2netstrfns(const char *name)
407 {
408         struct netstrfns *nf;
409         int               i;
410
411         for (i = 0; i < libcfs_nnetstrfns; i++) {
412                 nf = &libcfs_netstrfns[i];
413                 if (nf->nf_type >= 0 &&
414                     !strncmp(name, nf->nf_name, strlen(nf->nf_name)))
415                         return nf;
416         }
417         return NULL;
418 }
419
420 struct netstrfns *
421 libcfs_name2netstrfns(const char *name)
422 {
423         int    i;
424
425         for (i = 0; i < libcfs_nnetstrfns; i++)
426                 if (libcfs_netstrfns[i].nf_type >= 0 &&
427                     !strcmp(libcfs_netstrfns[i].nf_name, name))
428                         return &libcfs_netstrfns[i];
429
430         return NULL;
431 }
432
433 int
434 libcfs_isknown_lnd(int type)
435 {
436         return libcfs_lnd2netstrfns(type) != NULL;
437 }
438
439 char *
440 libcfs_lnd2modname(int lnd)
441 {
442         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
443
444         return (nf == NULL) ? NULL : nf->nf_modname;
445 }
446
447 char *
448 libcfs_lnd2str(int lnd)
449 {
450         char           *str;
451         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
452
453         if (nf != NULL)
454                 return nf->nf_name;
455
456         str = libcfs_next_nidstring();
457         snprintf(str, LNET_NIDSTR_SIZE, "?%u?", lnd);
458         return str;
459 }
460
461 int
462 libcfs_str2lnd(const char *str)
463 {
464         struct netstrfns *nf = libcfs_name2netstrfns(str);
465
466         if (nf != NULL)
467                 return nf->nf_type;
468
469         return -1;
470 }
471
472 char *
473 libcfs_net2str(__u32 net)
474 {
475         int               lnd = LNET_NETTYP(net);
476         int               num = LNET_NETNUM(net);
477         struct netstrfns *nf  = libcfs_lnd2netstrfns(lnd);
478         char             *str = libcfs_next_nidstring();
479
480         if (nf == NULL)
481                 snprintf(str, LNET_NIDSTR_SIZE, "<%u:%u>", lnd, num);
482         else if (num == 0)
483                 snprintf(str, LNET_NIDSTR_SIZE, "%s", nf->nf_name);
484         else
485                 snprintf(str, LNET_NIDSTR_SIZE, "%s%u", nf->nf_name, num);
486
487         return str;
488 }
489
490 char *
491 libcfs_nid2str(lnet_nid_t nid)
492 {
493         __u32             addr = LNET_NIDADDR(nid);
494         __u32             net = LNET_NIDNET(nid);
495         int               lnd = LNET_NETTYP(net);
496         int               nnum = LNET_NETNUM(net);
497         struct netstrfns *nf;
498         char             *str;
499         int               nob;
500
501         if (nid == LNET_NID_ANY)
502                 return "<?>";
503
504         nf = libcfs_lnd2netstrfns(lnd);
505         str = libcfs_next_nidstring();
506
507         if (nf == NULL)
508                 snprintf(str, LNET_NIDSTR_SIZE, "%x@<%u:%u>", addr, lnd, nnum);
509         else {
510                 nf->nf_addr2str(addr, str);
511                 nob = strlen(str);
512                 if (nnum == 0)
513                         snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s",
514                                  nf->nf_name);
515                 else
516                         snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s%u",
517                                  nf->nf_name, nnum);
518         }
519
520         return str;
521 }
522
523 static struct netstrfns *
524 libcfs_str2net_internal(const char *str, __u32 *net)
525 {
526         struct netstrfns *nf = NULL;
527         int               nob;
528         unsigned int      netnum;
529         int               i;
530
531         for (i = 0; i < libcfs_nnetstrfns; i++) {
532                 nf = &libcfs_netstrfns[i];
533                 if (nf->nf_type >= 0 &&
534                     !strncmp(str, nf->nf_name, strlen(nf->nf_name)))
535                         break;
536         }
537
538         if (i == libcfs_nnetstrfns)
539                 return NULL;
540
541         nob = strlen(nf->nf_name);
542
543         if (strlen(str) == (unsigned int)nob) {
544                 netnum = 0;
545         } else {
546                 if (nf->nf_type == LOLND) /* net number not allowed */
547                         return NULL;
548
549                 str += nob;
550                 i = strlen(str);
551                 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
552                     i != (int)strlen(str))
553                         return NULL;
554         }
555
556         *net = LNET_MKNET(nf->nf_type, netnum);
557         return nf;
558 }
559
560 __u32
561 libcfs_str2net(const char *str)
562 {
563         __u32  net;
564
565         if (libcfs_str2net_internal(str, &net) != NULL)
566                 return net;
567
568         return LNET_NIDNET(LNET_NID_ANY);
569 }
570
571 lnet_nid_t
572 libcfs_str2nid(const char *str)
573 {
574         const char       *sep = strchr(str, '@');
575         struct netstrfns *nf;
576         __u32             net;
577         __u32             addr;
578
579         if (sep != NULL) {
580                 nf = libcfs_str2net_internal(sep + 1, &net);
581                 if (nf == NULL)
582                         return LNET_NID_ANY;
583         } else {
584                 sep = str + strlen(str);
585                 net = LNET_MKNET(SOCKLND, 0);
586                 nf = libcfs_lnd2netstrfns(SOCKLND);
587                 LASSERT (nf != NULL);
588         }
589
590         if (!nf->nf_str2addr(str, (int)(sep - str), &addr))
591                 return LNET_NID_ANY;
592
593         return LNET_MKNID(net, addr);
594 }
595
596 char *
597 libcfs_id2str(lnet_process_id_t id)
598 {
599         char *str = libcfs_next_nidstring();
600
601         if (id.pid == LNET_PID_ANY) {
602                 snprintf(str, LNET_NIDSTR_SIZE,
603                          "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
604                 return str;
605         }
606
607         snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
608                  ((id.pid & LNET_PID_USERFLAG) != 0) ? "U" : "",
609                  (id.pid & ~LNET_PID_USERFLAG), libcfs_nid2str(id.nid));
610         return str;
611 }
612
613 int
614 libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
615 {
616         if (!strcmp(str, "*")) {
617                 *nidp = LNET_NID_ANY;
618                 return 1;
619         }
620
621         *nidp = libcfs_str2nid(str);
622         return *nidp != LNET_NID_ANY;
623 }
624
625 /**
626  * Nid range list syntax.
627  * \verbatim
628  *
629  * <nidlist>         :== <nidrange> [ ' ' <nidrange> ]
630  * <nidrange>        :== <addrrange> '@' <net>
631  * <addrrange>       :== '*' |
632  *                       <ipaddr_range> |
633  *                       <cfs_expr_list>
634  * <ipaddr_range>    :== <cfs_expr_list>.<cfs_expr_list>.<cfs_expr_list>.
635  *                       <cfs_expr_list>
636  * <cfs_expr_list>   :== <number> |
637  *                       <expr_list>
638  * <expr_list>       :== '[' <range_expr> [ ',' <range_expr>] ']'
639  * <range_expr>      :== <number> |
640  *                       <number> '-' <number> |
641  *                       <number> '-' <number> '/' <number>
642  * <net>             :== <netname> | <netname><number>
643  * <netname>         :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" |
644  *                       "vib" | "ra" | "elan" | "mx" | "ptl"
645  * \endverbatim
646  */
647
648 /**
649  * Structure to represent \<nidrange\> token of the syntax.
650  *
651  * One of this is created for each \<net\> parsed.
652  */
653 struct nidrange {
654         /**
655          * Link to list of this structures which is built on nid range
656          * list parsing.
657          */
658         struct list_head nr_link;
659         /**
660          * List head for addrrange::ar_link.
661          */
662         struct list_head nr_addrranges;
663         /**
664          * Flag indicating that *@<net> is found.
665          */
666         int nr_all;
667         /**
668          * Pointer to corresponding element of libcfs_netstrfns.
669          */
670         struct netstrfns *nr_netstrfns;
671         /**
672          * Number of network. E.g. 5 if \<net\> is "elan5".
673          */
674         int nr_netnum;
675 };
676
677 /**
678  * Structure to represent \<addrrange\> token of the syntax.
679  */
680 struct addrrange {
681         /**
682          * Link to nidrange::nr_addrranges.
683          */
684         struct list_head ar_link;
685         /**
686          * List head for cfs_expr_list::el_list.
687          */
688         struct list_head ar_numaddr_ranges;
689 };
690
691 /**
692  * Nf_parse_addrlist method for networks using numeric addresses.
693  *
694  * Examples of such networks are gm and elan.
695  *
696  * \retval 0 if \a str parsed to numeric address
697  * \retval errno otherwise
698  */
699 static int
700 libcfs_num_parse(char *str, int len, struct list_head *list)
701 {
702         struct cfs_expr_list *el;
703         int     rc;
704
705         rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
706         if (rc == 0)
707                 list_add_tail(&el->el_link, list);
708
709         return rc;
710 }
711
712 /**
713  * Parses \<addrrange\> token on the syntax.
714  *
715  * Allocates struct addrrange and links to \a nidrange via
716  * (nidrange::nr_addrranges)
717  *
718  * \retval 0 if \a src parses to '*' | \<ipaddr_range\> | \<cfs_expr_list\>
719  * \retval -errno otherwise
720  */
721 static int
722 parse_addrange(const struct cfs_lstr *src, struct nidrange *nidrange)
723 {
724         struct addrrange *addrrange;
725
726         if (src->ls_len == 1 && src->ls_str[0] == '*') {
727                 nidrange->nr_all = 1;
728                 return 0;
729         }
730
731         LIBCFS_ALLOC(addrrange, sizeof(struct addrrange));
732         if (addrrange == NULL)
733                 return -ENOMEM;
734         list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges);
735         INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges);
736
737         return nidrange->nr_netstrfns->nf_parse_addrlist(src->ls_str,
738                                                 src->ls_len,
739                                                 &addrrange->ar_numaddr_ranges);
740 }
741
742 /**
743  * Finds or creates struct nidrange.
744  *
745  * Checks if \a src is a valid network name, looks for corresponding
746  * nidrange on the ist of nidranges (\a nidlist), creates new struct
747  * nidrange if it is not found.
748  *
749  * \retval pointer to struct nidrange matching network specified via \a src
750  * \retval NULL if \a src does not match any network
751  */
752 static struct nidrange *
753 add_nidrange(const struct cfs_lstr *src,
754              struct list_head *nidlist)
755 {
756         struct netstrfns *nf;
757         struct nidrange *nr;
758         int endlen;
759         unsigned netnum;
760
761         if (src->ls_len >= LNET_NIDSTR_SIZE)
762                 return NULL;
763
764         nf = libcfs_namenum2netstrfns(src->ls_str);
765         if (nf == NULL)
766                 return NULL;
767         endlen = src->ls_len - strlen(nf->nf_name);
768         if (endlen == 0)
769                 /* network name only, e.g. "elan" or "tcp" */
770                 netnum = 0;
771         else {
772                 /* e.g. "elan25" or "tcp23", refuse to parse if
773                  * network name is not appended with decimal or
774                  * hexadecimal number */
775                 if (!cfs_str2num_check(src->ls_str + strlen(nf->nf_name),
776                                        endlen, &netnum, 0, MAX_NUMERIC_VALUE))
777                         return NULL;
778         }
779
780         list_for_each_entry(nr, nidlist, nr_link) {
781                 if (nr->nr_netstrfns != nf)
782                         continue;
783                 if (nr->nr_netnum != netnum)
784                         continue;
785                 return nr;
786         }
787
788         LIBCFS_ALLOC(nr, sizeof(struct nidrange));
789         if (nr == NULL)
790                 return NULL;
791         list_add_tail(&nr->nr_link, nidlist);
792         INIT_LIST_HEAD(&nr->nr_addrranges);
793         nr->nr_netstrfns = nf;
794         nr->nr_all = 0;
795         nr->nr_netnum = netnum;
796
797         return nr;
798 }
799
800 /**
801  * Parses \<nidrange\> token of the syntax.
802  *
803  * \retval 1 if \a src parses to \<addrrange\> '@' \<net\>
804  * \retval 0 otherwise
805  */
806 static int
807 parse_nidrange(struct cfs_lstr *src, struct list_head *nidlist)
808 {
809         struct cfs_lstr addrrange;
810         struct cfs_lstr net;
811         struct cfs_lstr tmp;
812         struct nidrange *nr;
813
814         tmp = *src;
815         if (cfs_gettok(src, '@', &addrrange) == 0)
816                 goto failed;
817
818         if (cfs_gettok(src, '@', &net) == 0 || src->ls_str != NULL)
819                 goto failed;
820
821         nr = add_nidrange(&net, nidlist);
822         if (nr == NULL)
823                 goto failed;
824
825         if (parse_addrange(&addrrange, nr) != 0)
826                 goto failed;
827
828         return 1;
829  failed:
830         CWARN("can't parse nidrange: \"%.*s\"\n", tmp.ls_len, tmp.ls_str);
831         return 0;
832 }
833
834 /**
835  * Frees addrrange structures of \a list.
836  *
837  * For each struct addrrange structure found on \a list it frees
838  * cfs_expr_list list attached to it and frees the addrrange itself.
839  *
840  * \retval none
841  */
842 static void
843 free_addrranges(struct list_head *list)
844 {
845         while (!list_empty(list)) {
846                 struct addrrange *ar;
847
848                 ar = list_entry(list->next, struct addrrange, ar_link);
849
850                 cfs_expr_list_free_list(&ar->ar_numaddr_ranges);
851                 list_del(&ar->ar_link);
852                 LIBCFS_FREE(ar, sizeof(struct addrrange));
853         }
854 }
855
856 /**
857  * Frees nidrange strutures of \a list.
858  *
859  * For each struct nidrange structure found on \a list it frees
860  * addrrange list attached to it and frees the nidrange itself.
861  *
862  * \retval none
863  */
864 void
865 cfs_free_nidlist(struct list_head *list)
866 {
867         struct list_head *pos, *next;
868         struct nidrange *nr;
869
870         list_for_each_safe(pos, next, list) {
871                 nr = list_entry(pos, struct nidrange, nr_link);
872                 free_addrranges(&nr->nr_addrranges);
873                 list_del(pos);
874                 LIBCFS_FREE(nr, sizeof(struct nidrange));
875         }
876 }
877
878 /**
879  * Parses nid range list.
880  *
881  * Parses with rigorous syntax and overflow checking \a str into
882  * \<nidrange\> [ ' ' \<nidrange\> ], compiles \a str into set of
883  * structures and links that structure to \a nidlist. The resulting
884  * list can be used to match a NID againts set of NIDS defined by \a
885  * str.
886  * \see cfs_match_nid
887  *
888  * \retval 1 on success
889  * \retval 0 otherwise
890  */
891 int
892 cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
893 {
894         struct cfs_lstr src;
895         struct cfs_lstr res;
896         int rc;
897
898         src.ls_str = str;
899         src.ls_len = len;
900         INIT_LIST_HEAD(nidlist);
901         while (src.ls_str) {
902                 rc = cfs_gettok(&src, ' ', &res);
903                 if (rc == 0) {
904                         cfs_free_nidlist(nidlist);
905                         return 0;
906                 }
907                 rc = parse_nidrange(&res, nidlist);
908                 if (rc == 0) {
909                         cfs_free_nidlist(nidlist);
910                         return 0;
911                 }
912         }
913         return 1;
914 }
915
916 /*
917  * Nf_match_addr method for networks using numeric addresses
918  *
919  * \retval 1 on match
920  * \retval 0 otherwise
921  */
922 static int
923 libcfs_num_match(__u32 addr, struct list_head *numaddr)
924 {
925         struct cfs_expr_list *el;
926
927         LASSERT(!list_empty(numaddr));
928         el = list_entry(numaddr->next, struct cfs_expr_list, el_link);
929
930         return cfs_expr_list_match(addr, el);
931 }
932
933 /**
934  * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
935  *
936  * \see cfs_parse_nidlist()
937  *
938  * \retval 1 on match
939  * \retval 0  otherwises
940  */
941 int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist)
942 {
943         struct nidrange *nr;
944         struct addrrange *ar;
945
946         list_for_each_entry(nr, nidlist, nr_link) {
947                 if (nr->nr_netstrfns->nf_type != LNET_NETTYP(LNET_NIDNET(nid)))
948                         continue;
949                 if (nr->nr_netnum != LNET_NETNUM(LNET_NIDNET(nid)))
950                         continue;
951                 if (nr->nr_all)
952                         return 1;
953                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
954                         if (nr->nr_netstrfns->nf_match_addr(LNET_NIDADDR(nid),
955                                                         &ar->ar_numaddr_ranges))
956                                 return 1;
957         }
958         return 0;
959 }
960
961 static int
962 libcfs_num_addr_range_print(char *buffer, int count, struct list_head *list)
963 {
964         int i = 0, j = 0;
965         struct cfs_expr_list *el;
966
967         list_for_each_entry(el, list, el_link) {
968                 LASSERT(j++ < 1);
969                 i += cfs_expr_list_print(buffer + i, count - i, el);
970         }
971         return i;
972 }
973
974 static int
975 libcfs_ip_addr_range_print(char *buffer, int count, struct list_head *list)
976 {
977         int i = 0, j = 0;
978         struct cfs_expr_list *el;
979
980         list_for_each_entry(el, list, el_link) {
981                 LASSERT(j++ < 4);
982                 if (i != 0)
983                         i += cfs_snprintf(buffer + i, count - i, ".");
984                 i += cfs_expr_list_print(buffer + i, count - i, el);
985         }
986         return i;
987 }
988
989
990 /**
991  * Print the network part of the nidrange \a nr into the specified \a buffer.
992  *
993  * \retval number of characters written
994  */
995 static int
996 cfs_print_network(char *buffer, int count, struct nidrange *nr)
997 {
998         struct netstrfns *nf = nr->nr_netstrfns;
999
1000         if (nr->nr_netnum == 0)
1001                 return cfs_snprintf(buffer, count, "@%s", nf->nf_name);
1002         else
1003                 return cfs_snprintf(buffer, count, "@%s%u",
1004                                     nf->nf_name, nr->nr_netnum);
1005 }
1006
1007
1008 /**
1009  * Print a list of addrrange (\a addrranges) into the specified \a buffer.
1010  * At max \a count characters can be printed into \a buffer.
1011  *
1012  * \retval number of characters written
1013  */
1014 static int
1015 cfs_print_addrranges(char *buffer, int count, struct list_head *addrranges,
1016                      struct nidrange *nr)
1017 {
1018         int i = 0;
1019         struct addrrange *ar;
1020         struct netstrfns *nf = nr->nr_netstrfns;
1021
1022         list_for_each_entry(ar, addrranges, ar_link) {
1023                 if (i != 0)
1024                         i += cfs_snprintf(buffer + i, count - i, " ");
1025                 i += nf->nf_print_addrlist(buffer + i, count - i,
1026                                            &ar->ar_numaddr_ranges);
1027                 i += cfs_print_network(buffer + i, count - i, nr);
1028         }
1029         return i;
1030 }
1031
1032
1033 /**
1034  * Print a list of nidranges (\a nidlist) into the specified \a buffer.
1035  * At max \a count characters can be printed into \a buffer.
1036  * Nidranges are separated by a space character.
1037  *
1038  * \retval number of characters written
1039  */
1040 int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist)
1041 {
1042         int i = 0;
1043         struct nidrange *nr;
1044
1045         if (count <= 0)
1046                 return 0;
1047
1048         list_for_each_entry(nr, nidlist, nr_link) {
1049                 if (i != 0)
1050                         i += cfs_snprintf(buffer + i, count - i, " ");
1051
1052                 if (nr->nr_all != 0) {
1053                         LASSERT(list_empty(&nr->nr_addrranges));
1054                         i += cfs_snprintf(buffer + i, count - i, "*");
1055                         i += cfs_print_network(buffer + i, count - i, nr);
1056                 } else {
1057                         i += cfs_print_addrranges(buffer + i, count - i,
1058                                                   &nr->nr_addrranges, nr);
1059                 }
1060         }
1061         return i;
1062 }
1063
1064 /**
1065  * Determines minimum and maximum addresses for a single
1066  * numeric address range
1067  *
1068  * \param       ar
1069  * \param       min_nid
1070  * \param       max_nid
1071  */
1072 static void cfs_ip_ar_min_max(struct addrrange *ar, __u32 *min_nid,
1073                               __u32 *max_nid)
1074 {
1075         struct cfs_expr_list    *el;
1076         struct cfs_range_expr   *re;
1077         __u32                   tmp_ip_addr = 0;
1078         unsigned int            min_ip[4] = {0};
1079         unsigned int            max_ip[4] = {0};
1080         int                     re_count = 0;
1081
1082         list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) {
1083                 list_for_each_entry(re, &el->el_exprs, re_link) {
1084                         min_ip[re_count] = re->re_lo;
1085                         max_ip[re_count] = re->re_hi;
1086                         re_count++;
1087                 }
1088         }
1089
1090         tmp_ip_addr = ((min_ip[0] << 24) | (min_ip[1] << 16) |
1091                        (min_ip[2] << 8) | min_ip[3]);
1092
1093         if (min_nid != NULL)
1094                 *min_nid = tmp_ip_addr;
1095
1096         tmp_ip_addr = ((max_ip[0] << 24) | (max_ip[1] << 16) |
1097                        (max_ip[2] << 8) | max_ip[3]);
1098
1099         if (max_nid != NULL)
1100                 *max_nid = tmp_ip_addr;
1101 }
1102
1103 /**
1104  * Determines minimum and maximum addresses for a single
1105  * numeric address range
1106  *
1107  * \param       ar
1108  * \param       min_nid
1109  * \param       max_nid
1110  */
1111 static void cfs_num_ar_min_max(struct addrrange *ar, __u32 *min_nid,
1112                                __u32 *max_nid)
1113 {
1114         struct cfs_expr_list    *el;
1115         struct cfs_range_expr   *re;
1116         unsigned int            min_addr = 0;
1117         unsigned int            max_addr = 0;
1118
1119         list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) {
1120                 list_for_each_entry(re, &el->el_exprs, re_link) {
1121                         if (re->re_lo < min_addr || min_addr == 0)
1122                                 min_addr = re->re_lo;
1123                         if (re->re_hi > max_addr)
1124                                 max_addr = re->re_hi;
1125                 }
1126         }
1127
1128         if (min_nid != NULL)
1129                 *min_nid = min_addr;
1130         if (max_nid != NULL)
1131                 *max_nid = max_addr;
1132 }
1133
1134 /**
1135  * Determines whether an expression list in an nidrange contains exactly
1136  * one contiguous address range. Calls the correct netstrfns for the LND
1137  *
1138  * \param       *nidlist
1139  *
1140  * \retval      true if contiguous
1141  * \retval      false if not contiguous
1142  */
1143 bool cfs_nidrange_is_contiguous(struct list_head *nidlist)
1144 {
1145         struct nidrange         *nr;
1146         struct netstrfns        *nf = NULL;
1147         char                    *lndname = NULL;
1148         int                     netnum = -1;
1149
1150         list_for_each_entry(nr, nidlist, nr_link) {
1151                 nf = nr->nr_netstrfns;
1152                 if (lndname == NULL)
1153                         lndname = nf->nf_name;
1154                 if (netnum == -1)
1155                         netnum = nr->nr_netnum;
1156
1157                 if (strcmp(lndname, nf->nf_name) != 0 ||
1158                     netnum != nr->nr_netnum)
1159                         return false;
1160         }
1161
1162         if (nf == NULL)
1163                 return false;
1164
1165         if (!nf->nf_is_contiguous(nidlist))
1166                 return false;
1167
1168         return true;
1169 }
1170 EXPORT_SYMBOL(cfs_nidrange_is_contiguous);
1171
1172 /**
1173  * Determines whether an expression list in an num nidrange contains exactly
1174  * one contiguous address range.
1175  *
1176  * \param       *nidlist
1177  *
1178  * \retval      true if contiguous
1179  * \retval      false if not contiguous
1180  */
1181 static bool cfs_num_is_contiguous(struct list_head *nidlist)
1182 {
1183         struct nidrange         *nr;
1184         struct addrrange        *ar;
1185         struct cfs_expr_list    *el;
1186         struct cfs_range_expr   *re;
1187         int                     last_hi = 0;
1188         __u32                   last_end_nid = 0;
1189         __u32                   current_start_nid = 0;
1190         __u32                   current_end_nid = 0;
1191
1192         list_for_each_entry(nr, nidlist, nr_link) {
1193                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1194                         cfs_num_ar_min_max(ar, &current_start_nid,
1195                                            &current_end_nid);
1196                         if (last_end_nid != 0 &&
1197                             (current_start_nid - last_end_nid != 1))
1198                                         return false;
1199                         last_end_nid = current_end_nid;
1200                         list_for_each_entry(el, &ar->ar_numaddr_ranges,
1201                                             el_link) {
1202                                 list_for_each_entry(re, &el->el_exprs,
1203                                                     re_link) {
1204                                         if (re->re_stride > 1)
1205                                                 return false;
1206                                         else if (last_hi != 0 &&
1207                                                  re->re_hi - last_hi != 1)
1208                                                 return false;
1209                                         last_hi = re->re_hi;
1210                                 }
1211                         }
1212                 }
1213         }
1214
1215         return true;
1216 }
1217
1218 /**
1219  * Determines whether an expression list in an ip nidrange contains exactly
1220  * one contiguous address range.
1221  *
1222  * \param       *nidlist
1223  *
1224  * \retval      true if contiguous
1225  * \retval      false if not contiguous
1226  */
1227 static bool cfs_ip_is_contiguous(struct list_head *nidlist)
1228 {
1229         struct nidrange         *nr;
1230         struct addrrange        *ar;
1231         struct cfs_expr_list    *el;
1232         struct cfs_range_expr   *re;
1233         int                     expr_count;
1234         int                     last_hi = 255;
1235         int                     last_diff = 0;
1236         __u32                   last_end_nid = 0;
1237         __u32                   current_start_nid = 0;
1238         __u32                   current_end_nid = 0;
1239
1240         list_for_each_entry(nr, nidlist, nr_link) {
1241                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1242                         last_hi = 255;
1243                         last_diff = 0;
1244                         cfs_ip_ar_min_max(ar, &current_start_nid,
1245                                           &current_end_nid);
1246                         if (last_end_nid != 0 &&
1247                             (current_start_nid - last_end_nid != 1))
1248                                         return false;
1249                         last_end_nid = current_end_nid;
1250                         list_for_each_entry(el,
1251                                             &ar->ar_numaddr_ranges,
1252                                             el_link) {
1253                                 expr_count = 0;
1254                                 list_for_each_entry(re, &el->el_exprs,
1255                                                     re_link) {
1256                                         expr_count++;
1257                                         if (re->re_stride > 1 ||
1258                                             (last_diff > 0 && last_hi != 255) ||
1259                                             (last_diff > 0 && last_hi == 255 &&
1260                                              re->re_lo > 0))
1261                                                 return false;
1262                                         last_hi = re->re_hi;
1263                                         last_diff = re->re_hi - re->re_lo;
1264                                 }
1265                         }
1266                 }
1267         }
1268
1269         return true;
1270 }
1271
1272 /**
1273  * Takes a linked list of nidrange expressions, determines the minimum
1274  * and maximum nid and creates appropriate nid structures
1275  *
1276  * \param       *nidlist
1277  * \param       *min_nid
1278  * \param       *max_nid
1279  */
1280 void cfs_nidrange_find_min_max(struct list_head *nidlist, char *min_nid,
1281                                char *max_nid, int nidstr_length)
1282 {
1283         struct nidrange         *nr;
1284         struct netstrfns        *nf = NULL;
1285         int                     netnum = -1;
1286         __u32                   min_addr;
1287         __u32                   max_addr;
1288         char                    *lndname = NULL;
1289         char                    min_addr_str[IPSTRING_LENGTH];
1290         char                    max_addr_str[IPSTRING_LENGTH];
1291
1292         list_for_each_entry(nr, nidlist, nr_link) {
1293                 nf = nr->nr_netstrfns;
1294                 lndname = nf->nf_name;
1295                 if (netnum == -1)
1296                         netnum = nr->nr_netnum;
1297
1298                 nf->nf_min_max(nidlist, &min_addr, &max_addr);
1299         }
1300         nf->nf_addr2str(min_addr, min_addr_str);
1301         nf->nf_addr2str(max_addr, max_addr_str);
1302
1303         snprintf(min_nid, nidstr_length, "%s@%s%d", min_addr_str, lndname,
1304                  netnum);
1305         snprintf(max_nid, nidstr_length, "%s@%s%d", max_addr_str, lndname,
1306                  netnum);
1307 }
1308 EXPORT_SYMBOL(cfs_nidrange_find_min_max);
1309
1310 /**
1311  * Determines the min and max NID values for num LNDs
1312  *
1313  * \param       *nidlist
1314  * \param       *min_nid
1315  * \param       *max_nid
1316  */
1317 static void cfs_num_min_max(struct list_head *nidlist, __u32 *min_nid,
1318                             __u32 *max_nid)
1319 {
1320         struct nidrange         *nr;
1321         struct addrrange        *ar;
1322         unsigned int            tmp_min_addr = 0;
1323         unsigned int            tmp_max_addr = 0;
1324         unsigned int            min_addr = 0;
1325         unsigned int            max_addr = 0;
1326
1327         list_for_each_entry(nr, nidlist, nr_link) {
1328                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1329                         cfs_num_ar_min_max(ar, &tmp_min_addr,
1330                                            &tmp_max_addr);
1331                         if (tmp_min_addr < min_addr || min_addr == 0)
1332                                 min_addr = tmp_min_addr;
1333                         if (tmp_max_addr > max_addr)
1334                                 max_addr = tmp_min_addr;
1335                 }
1336         }
1337         *max_nid = max_addr;
1338         *min_nid = min_addr;
1339 }
1340
1341 /**
1342  * Takes an nidlist and determines the minimum and maximum
1343  * ip addresses.
1344  *
1345  * \param       *nidlist
1346  * \param       *min_nid
1347  * \param       *max_nid
1348  */
1349 static void cfs_ip_min_max(struct list_head *nidlist, __u32 *min_nid,
1350                            __u32 *max_nid)
1351 {
1352         struct nidrange         *nr;
1353         struct addrrange        *ar;
1354         __u32                   tmp_min_ip_addr = 0;
1355         __u32                   tmp_max_ip_addr = 0;
1356         __u32                   min_ip_addr = 0;
1357         __u32                   max_ip_addr = 0;
1358
1359         list_for_each_entry(nr, nidlist, nr_link) {
1360                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1361                         cfs_ip_ar_min_max(ar, &tmp_min_ip_addr,
1362                                           &tmp_max_ip_addr);
1363                         if (tmp_min_ip_addr < min_ip_addr || min_ip_addr == 0)
1364                                 min_ip_addr = tmp_min_ip_addr;
1365                         if (tmp_max_ip_addr > max_ip_addr)
1366                                 max_ip_addr = tmp_max_ip_addr;
1367                 }
1368         }
1369
1370         if (min_nid != NULL)
1371                 *min_nid = min_ip_addr;
1372         if (max_nid != NULL)
1373                 *max_nid = max_ip_addr;
1374 }
1375
1376 #ifdef __KERNEL__
1377
1378 EXPORT_SYMBOL(libcfs_isknown_lnd);
1379 EXPORT_SYMBOL(libcfs_lnd2modname);
1380 EXPORT_SYMBOL(libcfs_lnd2str);
1381 EXPORT_SYMBOL(libcfs_str2lnd);
1382 EXPORT_SYMBOL(libcfs_net2str);
1383 EXPORT_SYMBOL(libcfs_nid2str);
1384 EXPORT_SYMBOL(libcfs_str2net);
1385 EXPORT_SYMBOL(libcfs_str2nid);
1386 EXPORT_SYMBOL(libcfs_id2str);
1387 EXPORT_SYMBOL(libcfs_str2anynid);
1388 EXPORT_SYMBOL(cfs_free_nidlist);
1389 EXPORT_SYMBOL(cfs_parse_nidlist);
1390 EXPORT_SYMBOL(cfs_print_nidlist);
1391 EXPORT_SYMBOL(cfs_match_nid);
1392
1393 #endif