Whamcloud - gitweb
3c1b88e9062252065f1507bddb825fe691d41b13
[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         ENTRY;
898
899         src.ls_str = str;
900         src.ls_len = len;
901         INIT_LIST_HEAD(nidlist);
902         while (src.ls_str) {
903                 rc = cfs_gettok(&src, ' ', &res);
904                 if (rc == 0) {
905                         cfs_free_nidlist(nidlist);
906                         RETURN(0);
907                 }
908                 rc = parse_nidrange(&res, nidlist);
909                 if (rc == 0) {
910                         cfs_free_nidlist(nidlist);
911                         RETURN(0);
912                 }
913         }
914         RETURN(1);
915 }
916
917 /*
918  * Nf_match_addr method for networks using numeric addresses
919  *
920  * \retval 1 on match
921  * \retval 0 otherwise
922  */
923 static int
924 libcfs_num_match(__u32 addr, struct list_head *numaddr)
925 {
926         struct cfs_expr_list *el;
927
928         LASSERT(!list_empty(numaddr));
929         el = list_entry(numaddr->next, struct cfs_expr_list, el_link);
930
931         return cfs_expr_list_match(addr, el);
932 }
933
934 /**
935  * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
936  *
937  * \see cfs_parse_nidlist()
938  *
939  * \retval 1 on match
940  * \retval 0  otherwises
941  */
942 int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist)
943 {
944         struct nidrange *nr;
945         struct addrrange *ar;
946         ENTRY;
947
948         list_for_each_entry(nr, nidlist, nr_link) {
949                 if (nr->nr_netstrfns->nf_type != LNET_NETTYP(LNET_NIDNET(nid)))
950                         continue;
951                 if (nr->nr_netnum != LNET_NETNUM(LNET_NIDNET(nid)))
952                         continue;
953                 if (nr->nr_all)
954                         RETURN(1);
955                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
956                         if (nr->nr_netstrfns->nf_match_addr(LNET_NIDADDR(nid),
957                                                         &ar->ar_numaddr_ranges))
958                                 RETURN(1);
959         }
960         RETURN(0);
961 }
962
963 static int
964 libcfs_num_addr_range_print(char *buffer, int count, struct list_head *list)
965 {
966         int i = 0, j = 0;
967         struct cfs_expr_list *el;
968
969         list_for_each_entry(el, list, el_link) {
970                 LASSERT(j++ < 1);
971                 i += cfs_expr_list_print(buffer + i, count - i, el);
972         }
973         return i;
974 }
975
976 static int
977 libcfs_ip_addr_range_print(char *buffer, int count, struct list_head *list)
978 {
979         int i = 0, j = 0;
980         struct cfs_expr_list *el;
981
982         list_for_each_entry(el, list, el_link) {
983                 LASSERT(j++ < 4);
984                 if (i != 0)
985                         i += cfs_snprintf(buffer + i, count - i, ".");
986                 i += cfs_expr_list_print(buffer + i, count - i, el);
987         }
988         return i;
989 }
990
991
992 /**
993  * Print the network part of the nidrange \a nr into the specified \a buffer.
994  *
995  * \retval number of characters written
996  */
997 static int
998 cfs_print_network(char *buffer, int count, struct nidrange *nr)
999 {
1000         struct netstrfns *nf = nr->nr_netstrfns;
1001
1002         if (nr->nr_netnum == 0)
1003                 return cfs_snprintf(buffer, count, "@%s", nf->nf_name);
1004         else
1005                 return cfs_snprintf(buffer, count, "@%s%u",
1006                                     nf->nf_name, nr->nr_netnum);
1007 }
1008
1009
1010 /**
1011  * Print a list of addrrange (\a addrranges) into the specified \a buffer.
1012  * At max \a count characters can be printed into \a buffer.
1013  *
1014  * \retval number of characters written
1015  */
1016 static int
1017 cfs_print_addrranges(char *buffer, int count, struct list_head *addrranges,
1018                      struct nidrange *nr)
1019 {
1020         int i = 0;
1021         struct addrrange *ar;
1022         struct netstrfns *nf = nr->nr_netstrfns;
1023
1024         list_for_each_entry(ar, addrranges, ar_link) {
1025                 if (i != 0)
1026                         i += cfs_snprintf(buffer + i, count - i, " ");
1027                 i += nf->nf_print_addrlist(buffer + i, count - i,
1028                                            &ar->ar_numaddr_ranges);
1029                 i += cfs_print_network(buffer + i, count - i, nr);
1030         }
1031         return i;
1032 }
1033
1034
1035 /**
1036  * Print a list of nidranges (\a nidlist) into the specified \a buffer.
1037  * At max \a count characters can be printed into \a buffer.
1038  * Nidranges are separated by a space character.
1039  *
1040  * \retval number of characters written
1041  */
1042 int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist)
1043 {
1044         int i = 0;
1045         struct nidrange *nr;
1046         ENTRY;
1047
1048         if (count <= 0)
1049                 RETURN(0);
1050
1051         list_for_each_entry(nr, nidlist, nr_link) {
1052                 if (i != 0)
1053                         i += cfs_snprintf(buffer + i, count - i, " ");
1054
1055                 if (nr->nr_all != 0) {
1056                         LASSERT(list_empty(&nr->nr_addrranges));
1057                         i += cfs_snprintf(buffer + i, count - i, "*");
1058                         i += cfs_print_network(buffer + i, count - i, nr);
1059                 } else {
1060                         i += cfs_print_addrranges(buffer + i, count - i,
1061                                                   &nr->nr_addrranges, nr);
1062                 }
1063         }
1064         RETURN(i);
1065 }
1066
1067 /**
1068  * Determines minimum and maximum addresses for a single
1069  * numeric address range
1070  *
1071  * \param       ar
1072  * \param       min_nid
1073  * \param       max_nid
1074  */
1075 static void cfs_ip_ar_min_max(struct addrrange *ar, __u32 *min_nid,
1076                               __u32 *max_nid)
1077 {
1078         struct cfs_expr_list    *el;
1079         struct cfs_range_expr   *re;
1080         __u32                   tmp_ip_addr = 0;
1081         unsigned int            min_ip[4] = {0};
1082         unsigned int            max_ip[4] = {0};
1083         int                     re_count = 0;
1084
1085         list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) {
1086                 list_for_each_entry(re, &el->el_exprs, re_link) {
1087                         min_ip[re_count] = re->re_lo;
1088                         max_ip[re_count] = re->re_hi;
1089                         re_count++;
1090                 }
1091         }
1092
1093         tmp_ip_addr = ((min_ip[0] << 24) | (min_ip[1] << 16) |
1094                        (min_ip[2] << 8) | min_ip[3]);
1095
1096         if (min_nid != NULL)
1097                 *min_nid = tmp_ip_addr;
1098
1099         tmp_ip_addr = ((max_ip[0] << 24) | (max_ip[1] << 16) |
1100                        (max_ip[2] << 8) | max_ip[3]);
1101
1102         if (max_nid != NULL)
1103                 *max_nid = tmp_ip_addr;
1104 }
1105
1106 /**
1107  * Determines minimum and maximum addresses for a single
1108  * numeric address range
1109  *
1110  * \param       ar
1111  * \param       min_nid
1112  * \param       max_nid
1113  */
1114 static void cfs_num_ar_min_max(struct addrrange *ar, __u32 *min_nid,
1115                                __u32 *max_nid)
1116 {
1117         struct cfs_expr_list    *el;
1118         struct cfs_range_expr   *re;
1119         unsigned int            min_addr = 0;
1120         unsigned int            max_addr = 0;
1121
1122         list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) {
1123                 list_for_each_entry(re, &el->el_exprs, re_link) {
1124                         if (re->re_lo < min_addr || min_addr == 0)
1125                                 min_addr = re->re_lo;
1126                         if (re->re_hi > max_addr)
1127                                 max_addr = re->re_hi;
1128                 }
1129         }
1130
1131         if (min_nid != NULL)
1132                 *min_nid = min_addr;
1133         if (max_nid != NULL)
1134                 *max_nid = max_addr;
1135 }
1136
1137 /**
1138  * Determines whether an expression list in an nidrange contains exactly
1139  * one contiguous address range. Calls the correct netstrfns for the LND
1140  *
1141  * \param       *nidlist
1142  *
1143  * \retval      true if contiguous
1144  * \retval      false if not contiguous
1145  */
1146 bool cfs_nidrange_is_contiguous(struct list_head *nidlist)
1147 {
1148         struct nidrange         *nr;
1149         struct netstrfns        *nf = NULL;
1150         char                    *lndname = NULL;
1151         int                     netnum = -1;
1152
1153         list_for_each_entry(nr, nidlist, nr_link) {
1154                 nf = nr->nr_netstrfns;
1155                 if (lndname == NULL)
1156                         lndname = nf->nf_name;
1157                 if (netnum == -1)
1158                         netnum = nr->nr_netnum;
1159
1160                 if (strcmp(lndname, nf->nf_name) != 0 ||
1161                     netnum != nr->nr_netnum)
1162                         return false;
1163         }
1164
1165         if (nf == NULL)
1166                 return false;
1167
1168         if (!nf->nf_is_contiguous(nidlist))
1169                 return false;
1170
1171         return true;
1172 }
1173 EXPORT_SYMBOL(cfs_nidrange_is_contiguous);
1174
1175 /**
1176  * Determines whether an expression list in an num nidrange contains exactly
1177  * one contiguous address range.
1178  *
1179  * \param       *nidlist
1180  *
1181  * \retval      true if contiguous
1182  * \retval      false if not contiguous
1183  */
1184 static bool cfs_num_is_contiguous(struct list_head *nidlist)
1185 {
1186         struct nidrange         *nr;
1187         struct addrrange        *ar;
1188         struct cfs_expr_list    *el;
1189         struct cfs_range_expr   *re;
1190         int                     last_hi = 0;
1191         __u32                   last_end_nid = 0;
1192         __u32                   current_start_nid = 0;
1193         __u32                   current_end_nid = 0;
1194
1195         list_for_each_entry(nr, nidlist, nr_link) {
1196                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1197                         cfs_num_ar_min_max(ar, &current_start_nid,
1198                                            &current_end_nid);
1199                         if (last_end_nid != 0 &&
1200                             (current_start_nid - last_end_nid != 1))
1201                                         return false;
1202                         last_end_nid = current_end_nid;
1203                         list_for_each_entry(el, &ar->ar_numaddr_ranges,
1204                                             el_link) {
1205                                 list_for_each_entry(re, &el->el_exprs,
1206                                                     re_link) {
1207                                         if (re->re_stride > 1)
1208                                                 return false;
1209                                         else if (last_hi != 0 &&
1210                                                  re->re_hi - last_hi != 1)
1211                                                 return false;
1212                                         last_hi = re->re_hi;
1213                                 }
1214                         }
1215                 }
1216         }
1217
1218         return true;
1219 }
1220
1221 /**
1222  * Determines whether an expression list in an ip nidrange contains exactly
1223  * one contiguous address range.
1224  *
1225  * \param       *nidlist
1226  *
1227  * \retval      true if contiguous
1228  * \retval      false if not contiguous
1229  */
1230 static bool cfs_ip_is_contiguous(struct list_head *nidlist)
1231 {
1232         struct nidrange         *nr;
1233         struct addrrange        *ar;
1234         struct cfs_expr_list    *el;
1235         struct cfs_range_expr   *re;
1236         int                     expr_count;
1237         int                     last_hi = 255;
1238         int                     last_diff = 0;
1239         __u32                   last_end_nid = 0;
1240         __u32                   current_start_nid = 0;
1241         __u32                   current_end_nid = 0;
1242
1243         list_for_each_entry(nr, nidlist, nr_link) {
1244                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1245                         last_hi = 255;
1246                         last_diff = 0;
1247                         cfs_ip_ar_min_max(ar, &current_start_nid,
1248                                           &current_end_nid);
1249                         if (last_end_nid != 0 &&
1250                             (current_start_nid - last_end_nid != 1))
1251                                         return false;
1252                         last_end_nid = current_end_nid;
1253                         list_for_each_entry(el,
1254                                             &ar->ar_numaddr_ranges,
1255                                             el_link) {
1256                                 expr_count = 0;
1257                                 list_for_each_entry(re, &el->el_exprs,
1258                                                     re_link) {
1259                                         expr_count++;
1260                                         if (re->re_stride > 1 ||
1261                                             (last_diff > 0 && last_hi != 255) ||
1262                                             (last_diff > 0 && last_hi == 255 &&
1263                                              re->re_lo > 0))
1264                                                 return false;
1265                                         last_hi = re->re_hi;
1266                                         last_diff = re->re_hi - re->re_lo;
1267                                 }
1268                         }
1269                 }
1270         }
1271
1272         return true;
1273 }
1274
1275 /**
1276  * Takes a linked list of nidrange expressions, determines the minimum
1277  * and maximum nid and creates appropriate nid structures
1278  *
1279  * \param       *nidlist
1280  * \param       *min_nid
1281  * \param       *max_nid
1282  */
1283 void cfs_nidrange_find_min_max(struct list_head *nidlist, char *min_nid,
1284                                char *max_nid, int nidstr_length)
1285 {
1286         struct nidrange         *nr;
1287         struct netstrfns        *nf = NULL;
1288         int                     netnum = -1;
1289         __u32                   min_addr;
1290         __u32                   max_addr;
1291         char                    *lndname = NULL;
1292         char                    min_addr_str[IPSTRING_LENGTH];
1293         char                    max_addr_str[IPSTRING_LENGTH];
1294
1295         list_for_each_entry(nr, nidlist, nr_link) {
1296                 nf = nr->nr_netstrfns;
1297                 lndname = nf->nf_name;
1298                 if (netnum == -1)
1299                         netnum = nr->nr_netnum;
1300
1301                 nf->nf_min_max(nidlist, &min_addr, &max_addr);
1302         }
1303         nf->nf_addr2str(min_addr, min_addr_str);
1304         nf->nf_addr2str(max_addr, max_addr_str);
1305
1306         snprintf(min_nid, nidstr_length, "%s@%s%d", min_addr_str, lndname,
1307                  netnum);
1308         snprintf(max_nid, nidstr_length, "%s@%s%d", max_addr_str, lndname,
1309                  netnum);
1310 }
1311 EXPORT_SYMBOL(cfs_nidrange_find_min_max);
1312
1313 /**
1314  * Determines the min and max NID values for num LNDs
1315  *
1316  * \param       *nidlist
1317  * \param       *min_nid
1318  * \param       *max_nid
1319  */
1320 static void cfs_num_min_max(struct list_head *nidlist, __u32 *min_nid,
1321                             __u32 *max_nid)
1322 {
1323         struct nidrange         *nr;
1324         struct addrrange        *ar;
1325         unsigned int            tmp_min_addr = 0;
1326         unsigned int            tmp_max_addr = 0;
1327         unsigned int            min_addr = 0;
1328         unsigned int            max_addr = 0;
1329
1330         list_for_each_entry(nr, nidlist, nr_link) {
1331                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1332                         cfs_num_ar_min_max(ar, &tmp_min_addr,
1333                                            &tmp_max_addr);
1334                         if (tmp_min_addr < min_addr || min_addr == 0)
1335                                 min_addr = tmp_min_addr;
1336                         if (tmp_max_addr > max_addr)
1337                                 max_addr = tmp_min_addr;
1338                 }
1339         }
1340         *max_nid = max_addr;
1341         *min_nid = min_addr;
1342 }
1343
1344 /**
1345  * Takes an nidlist and determines the minimum and maximum
1346  * ip addresses.
1347  *
1348  * \param       *nidlist
1349  * \param       *min_nid
1350  * \param       *max_nid
1351  */
1352 static void cfs_ip_min_max(struct list_head *nidlist, __u32 *min_nid,
1353                            __u32 *max_nid)
1354 {
1355         struct nidrange         *nr;
1356         struct addrrange        *ar;
1357         __u32                   tmp_min_ip_addr = 0;
1358         __u32                   tmp_max_ip_addr = 0;
1359         __u32                   min_ip_addr = 0;
1360         __u32                   max_ip_addr = 0;
1361
1362         list_for_each_entry(nr, nidlist, nr_link) {
1363                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1364                         cfs_ip_ar_min_max(ar, &tmp_min_ip_addr,
1365                                           &tmp_max_ip_addr);
1366                         if (tmp_min_ip_addr < min_ip_addr || min_ip_addr == 0)
1367                                 min_ip_addr = tmp_min_ip_addr;
1368                         if (tmp_max_ip_addr > max_ip_addr)
1369                                 max_ip_addr = tmp_max_ip_addr;
1370                 }
1371         }
1372
1373         if (min_nid != NULL)
1374                 *min_nid = min_ip_addr;
1375         if (max_nid != NULL)
1376                 *max_nid = max_ip_addr;
1377 }
1378
1379 #ifdef __KERNEL__
1380
1381 EXPORT_SYMBOL(libcfs_isknown_lnd);
1382 EXPORT_SYMBOL(libcfs_lnd2modname);
1383 EXPORT_SYMBOL(libcfs_lnd2str);
1384 EXPORT_SYMBOL(libcfs_str2lnd);
1385 EXPORT_SYMBOL(libcfs_net2str);
1386 EXPORT_SYMBOL(libcfs_nid2str);
1387 EXPORT_SYMBOL(libcfs_str2net);
1388 EXPORT_SYMBOL(libcfs_str2nid);
1389 EXPORT_SYMBOL(libcfs_id2str);
1390 EXPORT_SYMBOL(libcfs_str2anynid);
1391 EXPORT_SYMBOL(cfs_free_nidlist);
1392 EXPORT_SYMBOL(cfs_parse_nidlist);
1393 EXPORT_SYMBOL(cfs_print_nidlist);
1394 EXPORT_SYMBOL(cfs_match_nid);
1395
1396 #endif