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