Whamcloud - gitweb
LU-5557 mdt: track reint operations in MDS service stats
[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/nidstr.h>
45 #ifndef __KERNEL__
46 #ifdef HAVE_GETHOSTBYNAME
47 # include <netdb.h>
48 #endif
49 #endif
50
51 /* max value for numeric network address */
52 #define MAX_NUMERIC_VALUE 0xffffffff
53
54 #define IPSTRING_LENGTH 16
55
56 /* CAVEAT VENDITOR! Keep the canonical string representation of nets/nids
57  * consistent in all conversion functions.  Some code fragments are copied
58  * around for the sake of clarity...
59  */
60
61 /* CAVEAT EMPTOR! Racey temporary buffer allocation!
62  * Choose the number of nidstrings to support the MAXIMUM expected number of
63  * concurrent users.  If there are more, the returned string will be volatile.
64  * NB this number must allow for a process to be descheduled for a timeslice
65  * between getting its string and using it.
66  */
67
68 static char      libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE];
69 static int       libcfs_nidstring_idx = 0;
70
71 #ifdef __KERNEL__
72 static spinlock_t libcfs_nidstring_lock;
73
74 void libcfs_init_nidstrings (void)
75 {
76         spin_lock_init(&libcfs_nidstring_lock);
77 }
78
79 # define NIDSTR_LOCK(f)   spin_lock_irqsave(&libcfs_nidstring_lock, f)
80 # define NIDSTR_UNLOCK(f) spin_unlock_irqrestore(&libcfs_nidstring_lock, f)
81 #else
82 # define NIDSTR_LOCK(f)   (f=sizeof(f))  /* avoid set-but-unused warnings */
83 # define NIDSTR_UNLOCK(f) (f=sizeof(f))
84 #endif
85
86 static char *
87 libcfs_next_nidstring (void)
88 {
89         char          *str;
90         unsigned long  flags;
91
92         NIDSTR_LOCK(flags);
93
94         str = libcfs_nidstrings[libcfs_nidstring_idx++];
95         if (libcfs_nidstring_idx ==
96             sizeof(libcfs_nidstrings)/sizeof(libcfs_nidstrings[0]))
97                 libcfs_nidstring_idx = 0;
98
99         NIDSTR_UNLOCK(flags);
100         return str;
101 }
102
103 static int  libcfs_lo_str2addr(const char *str, int nob, __u32 *addr);
104 static void libcfs_ip_addr2str(__u32 addr, char *str);
105 static int  libcfs_ip_str2addr(const char *str, int nob, __u32 *addr);
106 static bool cfs_ip_is_contiguous(struct list_head *nidlist);
107 static void cfs_ip_min_max(struct list_head *nidlist, __u32 *min, __u32 *max);
108 static void libcfs_decnum_addr2str(__u32 addr, char *str);
109 static void libcfs_hexnum_addr2str(__u32 addr, char *str);
110 static int  libcfs_num_str2addr(const char *str, int nob, __u32 *addr);
111 static int  libcfs_num_parse(char *str, int len, struct list_head *list);
112 static int  libcfs_num_match(__u32 addr, struct list_head *list);
113 static int  libcfs_num_addr_range_print(char *buffer, int count,
114                                         struct list_head *list);
115 static int  libcfs_ip_addr_range_print(char *buffer, int count,
116                                        struct list_head *list);
117 static bool cfs_num_is_contiguous(struct list_head *nidlist);
118 static void cfs_num_min_max(struct list_head *nidlist, __u32 *min, __u32 *max);
119
120 struct netstrfns {
121         int      nf_type;
122         char    *nf_name;
123         char    *nf_modname;
124         void    (*nf_addr2str)(__u32 addr, char *str);
125         int     (*nf_str2addr)(const char *str, int nob, __u32 *addr);
126         int     (*nf_parse_addrlist)(char *str, int len,
127                                         struct list_head *list);
128         int     (*nf_print_addrlist)(char *buffer, int count,
129                                      struct list_head *list);
130         int     (*nf_match_addr)(__u32 addr, struct list_head *list);
131         bool    (*nf_is_contiguous)(struct list_head *nidlist);
132         void    (*nf_min_max)(struct list_head *nidlist, __u32 *min_nid,
133                                 __u32 *max_nid);
134 };
135
136 static struct netstrfns  libcfs_netstrfns[] = {
137         {/* .nf_type      */  LOLND,
138          /* .nf_name      */  "lo",
139          /* .nf_modname   */  "klolnd",
140          /* .nf_addr2str  */  libcfs_decnum_addr2str,
141          /* .nf_str2addr  */  libcfs_lo_str2addr,
142          /* .nf_parse_addr*/  libcfs_num_parse,
143          /* .nf_print_addrlist*/  libcfs_num_addr_range_print,
144          /* .nf_match_addr*/      libcfs_num_match,
145          /* .nf_is_contiguous */  cfs_num_is_contiguous,
146          /* .nf_min_max   */      cfs_num_min_max},
147         {/* .nf_type      */  SOCKLND,
148          /* .nf_name      */  "tcp",
149          /* .nf_modname   */  "ksocklnd",
150          /* .nf_addr2str  */  libcfs_ip_addr2str,
151          /* .nf_str2addr  */  libcfs_ip_str2addr,
152          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
153          /* .nf_print_addrlist*/  libcfs_ip_addr_range_print,
154          /* .nf_match_addr*/      cfs_ip_addr_match,
155          /* .nf_is_contiguous */  cfs_ip_is_contiguous,
156          /* .nf_min_max   */      cfs_ip_min_max},
157         {/* .nf_type      */  O2IBLND,
158          /* .nf_name      */  "o2ib",
159          /* .nf_modname   */  "ko2iblnd",
160          /* .nf_addr2str  */  libcfs_ip_addr2str,
161          /* .nf_str2addr  */  libcfs_ip_str2addr,
162          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
163          /* .nf_print_addrlist*/  libcfs_ip_addr_range_print,
164          /* .nf_match_addr*/      cfs_ip_addr_match,
165          /* .nf_is_contiguous */  cfs_ip_is_contiguous,
166          /* .nf_min_max   */      cfs_ip_min_max},
167         {/* .nf_type      */  CIBLND,
168          /* .nf_name      */  "cib",
169          /* .nf_modname   */  "kciblnd",
170          /* .nf_addr2str  */  libcfs_ip_addr2str,
171          /* .nf_str2addr  */  libcfs_ip_str2addr,
172          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
173          /* .nf_print_addrlist*/  libcfs_ip_addr_range_print,
174          /* .nf_match_addr*/      cfs_ip_addr_match,
175          /* .nf_is_contiguous */  cfs_ip_is_contiguous,
176          /* .nf_min_max   */      cfs_ip_min_max},
177         {/* .nf_type      */  OPENIBLND,
178          /* .nf_name      */  "openib",
179          /* .nf_modname   */  "kopeniblnd",
180          /* .nf_addr2str  */  libcfs_ip_addr2str,
181          /* .nf_str2addr  */  libcfs_ip_str2addr,
182          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
183          /* .nf_print_addrlist*/  libcfs_ip_addr_range_print,
184          /* .nf_match_addr*/      cfs_ip_addr_match,
185          /* .nf_is_contiguous */  cfs_ip_is_contiguous,
186          /* .nf_min_max   */      cfs_ip_min_max},
187         {/* .nf_type      */  IIBLND,
188          /* .nf_name      */  "iib",
189          /* .nf_modname   */  "kiiblnd",
190          /* .nf_addr2str  */  libcfs_ip_addr2str,
191          /* .nf_str2addr  */  libcfs_ip_str2addr,
192          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
193          /* .nf_print_addrlist*/  libcfs_ip_addr_range_print,
194          /* .nf_match_addr*/      cfs_ip_addr_match,
195          /* .nf_is_contiguous */  cfs_ip_is_contiguous,
196          /* .nf_min_max   */      cfs_ip_min_max},
197         {/* .nf_type      */  VIBLND,
198          /* .nf_name      */  "vib",
199          /* .nf_modname   */  "kviblnd",
200          /* .nf_addr2str  */  libcfs_ip_addr2str,
201          /* .nf_str2addr  */  libcfs_ip_str2addr,
202          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
203          /* .nf_print_addrlist*/  libcfs_ip_addr_range_print,
204          /* .nf_match_addr*/      cfs_ip_addr_match,
205          /* .nf_is_contiguous */  cfs_ip_is_contiguous,
206          /* .nf_min_max   */      cfs_ip_min_max},
207         {/* .nf_type      */  RALND,
208          /* .nf_name      */  "ra",
209          /* .nf_modname   */  "kralnd",
210          /* .nf_addr2str  */  libcfs_ip_addr2str,
211          /* .nf_str2addr  */  libcfs_ip_str2addr,
212          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
213          /* .nf_print_addrlist*/  libcfs_ip_addr_range_print,
214          /* .nf_match_addr*/      cfs_ip_addr_match,
215          /* .nf_is_contiguous */  cfs_ip_is_contiguous,
216          /* .nf_min_max   */      cfs_ip_min_max},
217         {/* .nf_type      */      QSWLND,
218          /* .nf_name      */      "elan",
219          /* .nf_modname   */      "kqswlnd",
220          /* .nf_addr2str  */      libcfs_decnum_addr2str,
221          /* .nf_str2addr  */      libcfs_num_str2addr,
222          /* .nf_parse_addrlist*/  libcfs_num_parse,
223          /* .nf_print_addrlist*/  libcfs_num_addr_range_print,
224          /* .nf_match_addr*/      libcfs_num_match,
225          /* .nf_is_contiguous */  cfs_num_is_contiguous,
226          /* .nf_min_max   */      cfs_num_min_max},
227         {/* .nf_type      */      GMLND,
228          /* .nf_name      */      "gm",
229          /* .nf_modname   */      "kgmlnd",
230          /* .nf_addr2str  */      libcfs_hexnum_addr2str,
231          /* .nf_str2addr  */      libcfs_num_str2addr,
232          /* .nf_parse_addrlist*/  libcfs_num_parse,
233          /* .nf_print_addrlist*/  libcfs_num_addr_range_print,
234          /* .nf_match_addr*/      libcfs_num_match,
235          /* .nf_is_contiguous */  cfs_num_is_contiguous,
236          /* .nf_min_max   */      cfs_num_min_max},
237         {/* .nf_type      */      MXLND,
238          /* .nf_name      */      "mx",
239          /* .nf_modname   */      "kmxlnd",
240          /* .nf_addr2str  */      libcfs_ip_addr2str,
241          /* .nf_str2addr  */      libcfs_ip_str2addr,
242          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
243          /* .nf_print_addrlist*/  libcfs_ip_addr_range_print,
244          /* .nf_match_addr*/      cfs_ip_addr_match,
245          /* .nf_is_contiguous */  cfs_ip_is_contiguous,
246          /* .nf_min_max   */      cfs_ip_min_max},
247         {/* .nf_type      */      PTLLND,
248          /* .nf_name      */      "ptl",
249          /* .nf_modname   */      "kptllnd",
250          /* .nf_addr2str  */      libcfs_decnum_addr2str,
251          /* .nf_str2addr  */      libcfs_num_str2addr,
252          /* .nf_parse_addrlist*/  libcfs_num_parse,
253          /* .nf_print_addrlist*/  libcfs_num_addr_range_print,
254          /* .nf_match_addr*/      libcfs_num_match,
255          /* .nf_is_contiguous */  cfs_num_is_contiguous,
256          /* .nf_min_max   */      cfs_num_min_max},
257         {/* .nf_type      */      GNILND,
258          /* .nf_name      */      "gni",
259          /* .nf_modname   */      "kgnilnd",
260          /* .nf_addr2str  */      libcfs_decnum_addr2str,
261          /* .nf_str2addr  */      libcfs_num_str2addr,
262          /* .nf_parse_addrlist*/  libcfs_num_parse,
263          /* .nf_print_addrlist*/  libcfs_num_addr_range_print,
264          /* .nf_match_addr*/      libcfs_num_match,
265          /* .nf_is_contiguous */  cfs_num_is_contiguous,
266          /* .nf_min_max   */      cfs_num_min_max},
267         {/* .nf_type      */      GNIIPLND,
268          /* .nf_name      */      "gip",
269          /* .nf_modname   */      "kgnilnd",
270          /* .nf_addr2str  */      libcfs_ip_addr2str,
271          /* .nf_str2addr  */      libcfs_ip_str2addr,
272          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
273          /* .nf_print_addrlist*/  libcfs_ip_addr_range_print,
274          /* .nf_match_addr*/      cfs_ip_addr_match,
275          /* .nf_is_contiguous */  cfs_ip_is_contiguous,
276          /* .nf_min_max   */      cfs_ip_min_max},
277          /* placeholder for net0 alias.  It MUST BE THE LAST ENTRY */
278         {/* .nf_type      */  -1},
279 };
280
281 const int libcfs_nnetstrfns = sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
282
283 int
284 libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
285 {
286         *addr = 0;
287         return 1;
288 }
289
290 void
291 libcfs_ip_addr2str(__u32 addr, char *str)
292 {
293 #if 0   /* never lookup */
294 #if !defined(__KERNEL__) && defined HAVE_GETHOSTBYNAME
295         __u32           netip = htonl(addr);
296         struct hostent *he = gethostbyaddr(&netip, sizeof(netip), AF_INET);
297
298         if (he != NULL) {
299                 snprintf(str, LNET_NIDSTR_SIZE, "%s", he->h_name);
300                 return;
301         }
302 #endif
303 #endif
304         snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u",
305                  (addr >> 24) & 0xff, (addr >> 16) & 0xff,
306                  (addr >> 8) & 0xff, addr & 0xff);
307 }
308
309 /* CAVEAT EMPTOR XscanfX
310  * I use "%n" at the end of a sscanf format to detect trailing junk.  However
311  * sscanf may return immediately if it sees the terminating '0' in a string, so
312  * I initialise the %n variable to the expected length.  If sscanf sets it;
313  * fine, if it doesn't, then the scan ended at the end of the string, which is
314  * fine too :) */
315
316 int
317 libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
318 {
319         unsigned int    a;
320         unsigned int    b;
321         unsigned int    c;
322         unsigned int    d;
323         int             n = nob; /* XscanfX */
324
325         /* numeric IP? */
326         if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
327             n == nob &&
328             (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
329             (c & ~0xff) == 0 && (d & ~0xff) == 0) {
330                 *addr = ((a<<24)|(b<<16)|(c<<8)|d);
331                 return 1;
332         }
333
334 #if !defined(__KERNEL__) && defined HAVE_GETHOSTBYNAME
335         /* known hostname? */
336         if (('a' <= str[0] && str[0] <= 'z') ||
337             ('A' <= str[0] && str[0] <= 'Z')) {
338                 char *tmp;
339
340                 LIBCFS_ALLOC(tmp, nob + 1);
341                 if (tmp != NULL) {
342                         struct hostent *he;
343
344                         memcpy(tmp, str, nob);
345                         tmp[nob] = 0;
346
347                         he = gethostbyname(tmp);
348
349                         LIBCFS_FREE(tmp, nob);
350
351                         if (he != NULL) {
352                                 __u32 ip = *(__u32 *)he->h_addr;
353
354                                 *addr = ntohl(ip);
355                                 return 1;
356                         }
357                 }
358         }
359 #endif
360         return 0;
361 }
362
363 void
364 libcfs_decnum_addr2str(__u32 addr, char *str)
365 {
366         snprintf(str, LNET_NIDSTR_SIZE, "%u", addr);
367 }
368
369 void
370 libcfs_hexnum_addr2str(__u32 addr, char *str)
371 {
372         snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr);
373 }
374
375 int
376 libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
377 {
378         int     n;
379
380         n = nob;
381         if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
382                 return 1;
383
384         n = nob;
385         if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
386                 return 1;
387
388         n = nob;
389         if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
390                 return 1;
391
392         return 0;
393 }
394
395 struct netstrfns *
396 libcfs_lnd2netstrfns(int lnd)
397 {
398         int    i;
399
400         if (lnd >= 0)
401                 for (i = 0; i < libcfs_nnetstrfns; i++)
402                         if (lnd == libcfs_netstrfns[i].nf_type)
403                                 return &libcfs_netstrfns[i];
404
405         return NULL;
406 }
407
408 struct netstrfns *
409 libcfs_namenum2netstrfns(const char *name)
410 {
411         struct netstrfns *nf;
412         int               i;
413
414         for (i = 0; i < libcfs_nnetstrfns; i++) {
415                 nf = &libcfs_netstrfns[i];
416                 if (nf->nf_type >= 0 &&
417                     !strncmp(name, nf->nf_name, strlen(nf->nf_name)))
418                         return nf;
419         }
420         return NULL;
421 }
422
423 struct netstrfns *
424 libcfs_name2netstrfns(const char *name)
425 {
426         int    i;
427
428         for (i = 0; i < libcfs_nnetstrfns; i++)
429                 if (libcfs_netstrfns[i].nf_type >= 0 &&
430                     !strcmp(libcfs_netstrfns[i].nf_name, name))
431                         return &libcfs_netstrfns[i];
432
433         return NULL;
434 }
435
436 int
437 libcfs_isknown_lnd(int type)
438 {
439         return libcfs_lnd2netstrfns(type) != NULL;
440 }
441
442 char *
443 libcfs_lnd2modname(int lnd)
444 {
445         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
446
447         return (nf == NULL) ? NULL : nf->nf_modname;
448 }
449
450 char *
451 libcfs_lnd2str(int lnd)
452 {
453         char           *str;
454         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
455
456         if (nf != NULL)
457                 return nf->nf_name;
458
459         str = libcfs_next_nidstring();
460         snprintf(str, LNET_NIDSTR_SIZE, "?%u?", lnd);
461         return str;
462 }
463
464 int
465 libcfs_str2lnd(const char *str)
466 {
467         struct netstrfns *nf = libcfs_name2netstrfns(str);
468
469         if (nf != NULL)
470                 return nf->nf_type;
471
472         return -1;
473 }
474
475 char *
476 libcfs_net2str(__u32 net)
477 {
478         int               lnd = LNET_NETTYP(net);
479         int               num = LNET_NETNUM(net);
480         struct netstrfns *nf  = libcfs_lnd2netstrfns(lnd);
481         char             *str = libcfs_next_nidstring();
482
483         if (nf == NULL)
484                 snprintf(str, LNET_NIDSTR_SIZE, "<%u:%u>", lnd, num);
485         else if (num == 0)
486                 snprintf(str, LNET_NIDSTR_SIZE, "%s", nf->nf_name);
487         else
488                 snprintf(str, LNET_NIDSTR_SIZE, "%s%u", nf->nf_name, num);
489
490         return str;
491 }
492
493 char *
494 libcfs_nid2str(lnet_nid_t nid)
495 {
496         __u32             addr = LNET_NIDADDR(nid);
497         __u32             net = LNET_NIDNET(nid);
498         int               lnd = LNET_NETTYP(net);
499         int               nnum = LNET_NETNUM(net);
500         struct netstrfns *nf;
501         char             *str;
502         int               nob;
503
504         if (nid == LNET_NID_ANY)
505                 return "<?>";
506
507         nf = libcfs_lnd2netstrfns(lnd);
508         str = libcfs_next_nidstring();
509
510         if (nf == NULL)
511                 snprintf(str, LNET_NIDSTR_SIZE, "%x@<%u:%u>", addr, lnd, nnum);
512         else {
513                 nf->nf_addr2str(addr, str);
514                 nob = strlen(str);
515                 if (nnum == 0)
516                         snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s",
517                                  nf->nf_name);
518                 else
519                         snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s%u",
520                                  nf->nf_name, nnum);
521         }
522
523         return str;
524 }
525
526 static struct netstrfns *
527 libcfs_str2net_internal(const char *str, __u32 *net)
528 {
529         struct netstrfns *nf = NULL;
530         int               nob;
531         unsigned int      netnum;
532         int               i;
533
534         for (i = 0; i < libcfs_nnetstrfns; i++) {
535                 nf = &libcfs_netstrfns[i];
536                 if (nf->nf_type >= 0 &&
537                     !strncmp(str, nf->nf_name, strlen(nf->nf_name)))
538                         break;
539         }
540
541         if (i == libcfs_nnetstrfns)
542                 return NULL;
543
544         nob = strlen(nf->nf_name);
545
546         if (strlen(str) == (unsigned int)nob) {
547                 netnum = 0;
548         } else {
549                 if (nf->nf_type == LOLND) /* net number not allowed */
550                         return NULL;
551
552                 str += nob;
553                 i = strlen(str);
554                 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
555                     i != (int)strlen(str))
556                         return NULL;
557         }
558
559         *net = LNET_MKNET(nf->nf_type, netnum);
560         return nf;
561 }
562
563 __u32
564 libcfs_str2net(const char *str)
565 {
566         __u32  net;
567
568         if (libcfs_str2net_internal(str, &net) != NULL)
569                 return net;
570
571         return LNET_NIDNET(LNET_NID_ANY);
572 }
573
574 lnet_nid_t
575 libcfs_str2nid(const char *str)
576 {
577         const char       *sep = strchr(str, '@');
578         struct netstrfns *nf;
579         __u32             net;
580         __u32             addr;
581
582         if (sep != NULL) {
583                 nf = libcfs_str2net_internal(sep + 1, &net);
584                 if (nf == NULL)
585                         return LNET_NID_ANY;
586         } else {
587                 sep = str + strlen(str);
588                 net = LNET_MKNET(SOCKLND, 0);
589                 nf = libcfs_lnd2netstrfns(SOCKLND);
590                 LASSERT (nf != NULL);
591         }
592
593         if (!nf->nf_str2addr(str, (int)(sep - str), &addr))
594                 return LNET_NID_ANY;
595
596         return LNET_MKNID(net, addr);
597 }
598
599 char *
600 libcfs_id2str(lnet_process_id_t id)
601 {
602         char *str = libcfs_next_nidstring();
603
604         if (id.pid == LNET_PID_ANY) {
605                 snprintf(str, LNET_NIDSTR_SIZE,
606                          "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
607                 return str;
608         }
609
610         snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
611                  ((id.pid & LNET_PID_USERFLAG) != 0) ? "U" : "",
612                  (id.pid & ~LNET_PID_USERFLAG), libcfs_nid2str(id.nid));
613         return str;
614 }
615
616 int
617 libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
618 {
619         if (!strcmp(str, "*")) {
620                 *nidp = LNET_NID_ANY;
621                 return 1;
622         }
623
624         *nidp = libcfs_str2nid(str);
625         return *nidp != LNET_NID_ANY;
626 }
627
628 /**
629  * Nid range list syntax.
630  * \verbatim
631  *
632  * <nidlist>         :== <nidrange> [ ' ' <nidrange> ]
633  * <nidrange>        :== <addrrange> '@' <net>
634  * <addrrange>       :== '*' |
635  *                       <ipaddr_range> |
636  *                       <cfs_expr_list>
637  * <ipaddr_range>    :== <cfs_expr_list>.<cfs_expr_list>.<cfs_expr_list>.
638  *                       <cfs_expr_list>
639  * <cfs_expr_list>   :== <number> |
640  *                       <expr_list>
641  * <expr_list>       :== '[' <range_expr> [ ',' <range_expr>] ']'
642  * <range_expr>      :== <number> |
643  *                       <number> '-' <number> |
644  *                       <number> '-' <number> '/' <number>
645  * <net>             :== <netname> | <netname><number>
646  * <netname>         :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" |
647  *                       "vib" | "ra" | "elan" | "mx" | "ptl"
648  * \endverbatim
649  */
650
651 /**
652  * Structure to represent \<nidrange\> token of the syntax.
653  *
654  * One of this is created for each \<net\> parsed.
655  */
656 struct nidrange {
657         /**
658          * Link to list of this structures which is built on nid range
659          * list parsing.
660          */
661         struct list_head nr_link;
662         /**
663          * List head for addrrange::ar_link.
664          */
665         struct list_head nr_addrranges;
666         /**
667          * Flag indicating that *@<net> is found.
668          */
669         int nr_all;
670         /**
671          * Pointer to corresponding element of libcfs_netstrfns.
672          */
673         struct netstrfns *nr_netstrfns;
674         /**
675          * Number of network. E.g. 5 if \<net\> is "elan5".
676          */
677         int nr_netnum;
678 };
679
680 /**
681  * Structure to represent \<addrrange\> token of the syntax.
682  */
683 struct addrrange {
684         /**
685          * Link to nidrange::nr_addrranges.
686          */
687         struct list_head ar_link;
688         /**
689          * List head for cfs_expr_list::el_list.
690          */
691         struct list_head ar_numaddr_ranges;
692 };
693
694 /**
695  * Nf_parse_addrlist method for networks using numeric addresses.
696  *
697  * Examples of such networks are gm and elan.
698  *
699  * \retval 0 if \a str parsed to numeric address
700  * \retval errno otherwise
701  */
702 static int
703 libcfs_num_parse(char *str, int len, struct list_head *list)
704 {
705         struct cfs_expr_list *el;
706         int     rc;
707
708         rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
709         if (rc == 0)
710                 list_add_tail(&el->el_link, list);
711
712         return rc;
713 }
714
715 /**
716  * Parses \<addrrange\> token on the syntax.
717  *
718  * Allocates struct addrrange and links to \a nidrange via
719  * (nidrange::nr_addrranges)
720  *
721  * \retval 0 if \a src parses to '*' | \<ipaddr_range\> | \<cfs_expr_list\>
722  * \retval -errno otherwise
723  */
724 static int
725 parse_addrange(const struct cfs_lstr *src, struct nidrange *nidrange)
726 {
727         struct addrrange *addrrange;
728
729         if (src->ls_len == 1 && src->ls_str[0] == '*') {
730                 nidrange->nr_all = 1;
731                 return 0;
732         }
733
734         LIBCFS_ALLOC(addrrange, sizeof(struct addrrange));
735         if (addrrange == NULL)
736                 return -ENOMEM;
737         list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges);
738         INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges);
739
740         return nidrange->nr_netstrfns->nf_parse_addrlist(src->ls_str,
741                                                 src->ls_len,
742                                                 &addrrange->ar_numaddr_ranges);
743 }
744
745 /**
746  * Finds or creates struct nidrange.
747  *
748  * Checks if \a src is a valid network name, looks for corresponding
749  * nidrange on the ist of nidranges (\a nidlist), creates new struct
750  * nidrange if it is not found.
751  *
752  * \retval pointer to struct nidrange matching network specified via \a src
753  * \retval NULL if \a src does not match any network
754  */
755 static struct nidrange *
756 add_nidrange(const struct cfs_lstr *src,
757              struct list_head *nidlist)
758 {
759         struct netstrfns *nf;
760         struct nidrange *nr;
761         int endlen;
762         unsigned netnum;
763
764         if (src->ls_len >= LNET_NIDSTR_SIZE)
765                 return NULL;
766
767         nf = libcfs_namenum2netstrfns(src->ls_str);
768         if (nf == NULL)
769                 return NULL;
770         endlen = src->ls_len - strlen(nf->nf_name);
771         if (endlen == 0)
772                 /* network name only, e.g. "elan" or "tcp" */
773                 netnum = 0;
774         else {
775                 /* e.g. "elan25" or "tcp23", refuse to parse if
776                  * network name is not appended with decimal or
777                  * hexadecimal number */
778                 if (!cfs_str2num_check(src->ls_str + strlen(nf->nf_name),
779                                        endlen, &netnum, 0, MAX_NUMERIC_VALUE))
780                         return NULL;
781         }
782
783         list_for_each_entry(nr, nidlist, nr_link) {
784                 if (nr->nr_netstrfns != nf)
785                         continue;
786                 if (nr->nr_netnum != netnum)
787                         continue;
788                 return nr;
789         }
790
791         LIBCFS_ALLOC(nr, sizeof(struct nidrange));
792         if (nr == NULL)
793                 return NULL;
794         list_add_tail(&nr->nr_link, nidlist);
795         INIT_LIST_HEAD(&nr->nr_addrranges);
796         nr->nr_netstrfns = nf;
797         nr->nr_all = 0;
798         nr->nr_netnum = netnum;
799
800         return nr;
801 }
802
803 /**
804  * Parses \<nidrange\> token of the syntax.
805  *
806  * \retval 1 if \a src parses to \<addrrange\> '@' \<net\>
807  * \retval 0 otherwise
808  */
809 static int
810 parse_nidrange(struct cfs_lstr *src, struct list_head *nidlist)
811 {
812         struct cfs_lstr addrrange;
813         struct cfs_lstr net;
814         struct cfs_lstr tmp;
815         struct nidrange *nr;
816
817         tmp = *src;
818         if (cfs_gettok(src, '@', &addrrange) == 0)
819                 goto failed;
820
821         if (cfs_gettok(src, '@', &net) == 0 || src->ls_str != NULL)
822                 goto failed;
823
824         nr = add_nidrange(&net, nidlist);
825         if (nr == NULL)
826                 goto failed;
827
828         if (parse_addrange(&addrrange, nr) != 0)
829                 goto failed;
830
831         return 1;
832  failed:
833         CWARN("can't parse nidrange: \"%.*s\"\n", tmp.ls_len, tmp.ls_str);
834         return 0;
835 }
836
837 /**
838  * Frees addrrange structures of \a list.
839  *
840  * For each struct addrrange structure found on \a list it frees
841  * cfs_expr_list list attached to it and frees the addrrange itself.
842  *
843  * \retval none
844  */
845 static void
846 free_addrranges(struct list_head *list)
847 {
848         while (!list_empty(list)) {
849                 struct addrrange *ar;
850
851                 ar = list_entry(list->next, struct addrrange, ar_link);
852
853                 cfs_expr_list_free_list(&ar->ar_numaddr_ranges);
854                 list_del(&ar->ar_link);
855                 LIBCFS_FREE(ar, sizeof(struct addrrange));
856         }
857 }
858
859 /**
860  * Frees nidrange strutures of \a list.
861  *
862  * For each struct nidrange structure found on \a list it frees
863  * addrrange list attached to it and frees the nidrange itself.
864  *
865  * \retval none
866  */
867 void
868 cfs_free_nidlist(struct list_head *list)
869 {
870         struct list_head *pos, *next;
871         struct nidrange *nr;
872
873         list_for_each_safe(pos, next, list) {
874                 nr = list_entry(pos, struct nidrange, nr_link);
875                 free_addrranges(&nr->nr_addrranges);
876                 list_del(pos);
877                 LIBCFS_FREE(nr, sizeof(struct nidrange));
878         }
879 }
880
881 /**
882  * Parses nid range list.
883  *
884  * Parses with rigorous syntax and overflow checking \a str into
885  * \<nidrange\> [ ' ' \<nidrange\> ], compiles \a str into set of
886  * structures and links that structure to \a nidlist. The resulting
887  * list can be used to match a NID againts set of NIDS defined by \a
888  * str.
889  * \see cfs_match_nid
890  *
891  * \retval 1 on success
892  * \retval 0 otherwise
893  */
894 int
895 cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
896 {
897         struct cfs_lstr src;
898         struct cfs_lstr res;
899         int rc;
900
901         src.ls_str = str;
902         src.ls_len = len;
903         INIT_LIST_HEAD(nidlist);
904         while (src.ls_str) {
905                 rc = cfs_gettok(&src, ' ', &res);
906                 if (rc == 0) {
907                         cfs_free_nidlist(nidlist);
908                         return 0;
909                 }
910                 rc = parse_nidrange(&res, nidlist);
911                 if (rc == 0) {
912                         cfs_free_nidlist(nidlist);
913                         return 0;
914                 }
915         }
916         return 1;
917 }
918
919 /*
920  * Nf_match_addr method for networks using numeric addresses
921  *
922  * \retval 1 on match
923  * \retval 0 otherwise
924  */
925 static int
926 libcfs_num_match(__u32 addr, struct list_head *numaddr)
927 {
928         struct cfs_expr_list *el;
929
930         LASSERT(!list_empty(numaddr));
931         el = list_entry(numaddr->next, struct cfs_expr_list, el_link);
932
933         return cfs_expr_list_match(addr, el);
934 }
935
936 /**
937  * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
938  *
939  * \see cfs_parse_nidlist()
940  *
941  * \retval 1 on match
942  * \retval 0  otherwises
943  */
944 int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist)
945 {
946         struct nidrange *nr;
947         struct addrrange *ar;
948
949         list_for_each_entry(nr, nidlist, nr_link) {
950                 if (nr->nr_netstrfns->nf_type != LNET_NETTYP(LNET_NIDNET(nid)))
951                         continue;
952                 if (nr->nr_netnum != LNET_NETNUM(LNET_NIDNET(nid)))
953                         continue;
954                 if (nr->nr_all)
955                         return 1;
956                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
957                         if (nr->nr_netstrfns->nf_match_addr(LNET_NIDADDR(nid),
958                                                         &ar->ar_numaddr_ranges))
959                                 return 1;
960         }
961         return 0;
962 }
963
964 static int
965 libcfs_num_addr_range_print(char *buffer, int count, struct list_head *list)
966 {
967         int i = 0, j = 0;
968         struct cfs_expr_list *el;
969
970         list_for_each_entry(el, list, el_link) {
971                 LASSERT(j++ < 1);
972                 i += cfs_expr_list_print(buffer + i, count - i, el);
973         }
974         return i;
975 }
976
977 static int
978 libcfs_ip_addr_range_print(char *buffer, int count, struct list_head *list)
979 {
980         int i = 0, j = 0;
981         struct cfs_expr_list *el;
982
983         list_for_each_entry(el, list, el_link) {
984                 LASSERT(j++ < 4);
985                 if (i != 0)
986                         i += cfs_snprintf(buffer + i, count - i, ".");
987                 i += cfs_expr_list_print(buffer + i, count - i, el);
988         }
989         return i;
990 }
991
992
993 /**
994  * Print the network part of the nidrange \a nr into the specified \a buffer.
995  *
996  * \retval number of characters written
997  */
998 static int
999 cfs_print_network(char *buffer, int count, struct nidrange *nr)
1000 {
1001         struct netstrfns *nf = nr->nr_netstrfns;
1002
1003         if (nr->nr_netnum == 0)
1004                 return cfs_snprintf(buffer, count, "@%s", nf->nf_name);
1005         else
1006                 return cfs_snprintf(buffer, count, "@%s%u",
1007                                     nf->nf_name, nr->nr_netnum);
1008 }
1009
1010
1011 /**
1012  * Print a list of addrrange (\a addrranges) into the specified \a buffer.
1013  * At max \a count characters can be printed into \a buffer.
1014  *
1015  * \retval number of characters written
1016  */
1017 static int
1018 cfs_print_addrranges(char *buffer, int count, struct list_head *addrranges,
1019                      struct nidrange *nr)
1020 {
1021         int i = 0;
1022         struct addrrange *ar;
1023         struct netstrfns *nf = nr->nr_netstrfns;
1024
1025         list_for_each_entry(ar, addrranges, ar_link) {
1026                 if (i != 0)
1027                         i += cfs_snprintf(buffer + i, count - i, " ");
1028                 i += nf->nf_print_addrlist(buffer + i, count - i,
1029                                            &ar->ar_numaddr_ranges);
1030                 i += cfs_print_network(buffer + i, count - i, nr);
1031         }
1032         return i;
1033 }
1034
1035
1036 /**
1037  * Print a list of nidranges (\a nidlist) into the specified \a buffer.
1038  * At max \a count characters can be printed into \a buffer.
1039  * Nidranges are separated by a space character.
1040  *
1041  * \retval number of characters written
1042  */
1043 int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist)
1044 {
1045         int i = 0;
1046         struct nidrange *nr;
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