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