Whamcloud - gitweb
f97b464508d99a8b3de96b8ce1ea0d699c1a32ef
[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, 2016, 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 nidrange *nr;
249
250         if (cfs_gettok(src, '@', &addrrange) == 0)
251                 goto failed;
252
253         if (cfs_gettok(src, '@', &net) == 0 || src->ls_str != NULL)
254                 goto failed;
255
256         nr = add_nidrange(&net, nidlist);
257         if (nr == NULL)
258                 goto failed;
259
260         if (parse_addrange(&addrrange, nr) != 0)
261                 goto failed;
262
263         return 1;
264 failed:
265         return 0;
266 }
267
268 /**
269  * Frees addrrange structures of \a list.
270  *
271  * For each struct addrrange structure found on \a list it frees
272  * cfs_expr_list list attached to it and frees the addrrange itself.
273  *
274  * \retval none
275  */
276 static void
277 free_addrranges(struct list_head *list)
278 {
279         while (!list_empty(list)) {
280                 struct addrrange *ar;
281
282                 ar = list_entry(list->next, struct addrrange, ar_link);
283
284                 cfs_expr_list_free_list(&ar->ar_numaddr_ranges);
285                 list_del(&ar->ar_link);
286                 LIBCFS_FREE(ar, sizeof(struct addrrange));
287         }
288 }
289
290 /**
291  * Frees nidrange strutures of \a list.
292  *
293  * For each struct nidrange structure found on \a list it frees
294  * addrrange list attached to it and frees the nidrange itself.
295  *
296  * \retval none
297  */
298 void
299 cfs_free_nidlist(struct list_head *list)
300 {
301         struct list_head *pos, *next;
302         struct nidrange *nr;
303
304         list_for_each_safe(pos, next, list) {
305                 nr = list_entry(pos, struct nidrange, nr_link);
306                 free_addrranges(&nr->nr_addrranges);
307                 list_del(pos);
308                 LIBCFS_FREE(nr, sizeof(struct nidrange));
309         }
310 }
311 EXPORT_SYMBOL(cfs_free_nidlist);
312
313 /**
314  * Parses nid range list.
315  *
316  * Parses with rigorous syntax and overflow checking \a str into
317  * \<nidrange\> [ ' ' \<nidrange\> ], compiles \a str into set of
318  * structures and links that structure to \a nidlist. The resulting
319  * list can be used to match a NID againts set of NIDS defined by \a
320  * str.
321  * \see cfs_match_nid
322  *
323  * \retval 1 on success
324  * \retval 0 otherwise
325  */
326 int
327 cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
328 {
329         struct cfs_lstr src;
330         struct cfs_lstr res;
331         int rc;
332
333         src.ls_str = str;
334         src.ls_len = len;
335         INIT_LIST_HEAD(nidlist);
336         while (src.ls_str) {
337                 rc = cfs_gettok(&src, ' ', &res);
338                 if (rc == 0) {
339                         cfs_free_nidlist(nidlist);
340                         return 0;
341                 }
342                 rc = parse_nidrange(&res, nidlist);
343                 if (rc == 0) {
344                         cfs_free_nidlist(nidlist);
345                         return 0;
346                 }
347         }
348         return 1;
349 }
350 EXPORT_SYMBOL(cfs_parse_nidlist);
351
352 /**
353  * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
354  *
355  * \see cfs_parse_nidlist()
356  *
357  * \retval 1 on match
358  * \retval 0  otherwises
359  */
360 int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist)
361 {
362         struct nidrange *nr;
363         struct addrrange *ar;
364
365         list_for_each_entry(nr, nidlist, nr_link) {
366                 if (nr->nr_netstrfns->nf_type != LNET_NETTYP(LNET_NIDNET(nid)))
367                         continue;
368                 if (nr->nr_netnum != LNET_NETNUM(LNET_NIDNET(nid)))
369                         continue;
370                 if (nr->nr_all)
371                         return 1;
372                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
373                         if (nr->nr_netstrfns->nf_match_addr(LNET_NIDADDR(nid),
374                                                         &ar->ar_numaddr_ranges))
375                                 return 1;
376         }
377         return 0;
378 }
379 EXPORT_SYMBOL(cfs_match_nid);
380
381 /**
382  * Print the network part of the nidrange \a nr into the specified \a buffer.
383  *
384  * \retval number of characters written
385  */
386 static int
387 cfs_print_network(char *buffer, int count, struct nidrange *nr)
388 {
389         struct netstrfns *nf = nr->nr_netstrfns;
390
391         if (nr->nr_netnum == 0)
392                 return scnprintf(buffer, count, "@%s", nf->nf_name);
393         else
394                 return scnprintf(buffer, count, "@%s%u",
395                                     nf->nf_name, nr->nr_netnum);
396 }
397
398 /**
399  * Print a list of addrrange (\a addrranges) into the specified \a buffer.
400  * At max \a count characters can be printed into \a buffer.
401  *
402  * \retval number of characters written
403  */
404 static int
405 cfs_print_addrranges(char *buffer, int count, struct list_head *addrranges,
406                      struct nidrange *nr)
407 {
408         int i = 0;
409         struct addrrange *ar;
410         struct netstrfns *nf = nr->nr_netstrfns;
411
412         list_for_each_entry(ar, addrranges, ar_link) {
413                 if (i != 0)
414                         i += scnprintf(buffer + i, count - i, " ");
415                 i += nf->nf_print_addrlist(buffer + i, count - i,
416                                            &ar->ar_numaddr_ranges);
417                 i += cfs_print_network(buffer + i, count - i, nr);
418         }
419         return i;
420 }
421
422 /**
423  * Print a list of nidranges (\a nidlist) into the specified \a buffer.
424  * At max \a count characters can be printed into \a buffer.
425  * Nidranges are separated by a space character.
426  *
427  * \retval number of characters written
428  */
429 int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist)
430 {
431         int i = 0;
432         struct nidrange *nr;
433
434         if (count <= 0)
435                 return 0;
436
437         list_for_each_entry(nr, nidlist, nr_link) {
438                 if (i != 0)
439                         i += scnprintf(buffer + i, count - i, " ");
440
441                 if (nr->nr_all != 0) {
442                         LASSERT(list_empty(&nr->nr_addrranges));
443                         i += scnprintf(buffer + i, count - i, "*");
444                         i += cfs_print_network(buffer + i, count - i, nr);
445                 } else {
446                         i += cfs_print_addrranges(buffer + i, count - i,
447                                                   &nr->nr_addrranges, nr);
448                 }
449         }
450         return i;
451 }
452 EXPORT_SYMBOL(cfs_print_nidlist);
453
454 /**
455  * Determines minimum and maximum addresses for a single
456  * numeric address range
457  *
458  * \param       ar
459  * \param       min_nid
460  * \param       max_nid
461  */
462 static void cfs_ip_ar_min_max(struct addrrange *ar, __u32 *min_nid,
463                               __u32 *max_nid)
464 {
465         struct cfs_expr_list *el;
466         struct cfs_range_expr *re;
467         __u32 tmp_ip_addr = 0;
468         unsigned int min_ip[4] = {0};
469         unsigned int max_ip[4] = {0};
470         int re_count = 0;
471
472         list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) {
473                 list_for_each_entry(re, &el->el_exprs, re_link) {
474                         min_ip[re_count] = re->re_lo;
475                         max_ip[re_count] = re->re_hi;
476                         re_count++;
477                 }
478         }
479
480         tmp_ip_addr = ((min_ip[0] << 24) | (min_ip[1] << 16) |
481                        (min_ip[2] << 8) | min_ip[3]);
482
483         if (min_nid != NULL)
484                 *min_nid = tmp_ip_addr;
485
486         tmp_ip_addr = ((max_ip[0] << 24) | (max_ip[1] << 16) |
487                        (max_ip[2] << 8) | max_ip[3]);
488
489         if (max_nid != NULL)
490                 *max_nid = tmp_ip_addr;
491 }
492
493 /**
494  * Determines minimum and maximum addresses for a single
495  * numeric address range
496  *
497  * \param       ar
498  * \param       min_nid
499  * \param       max_nid
500  */
501 static void cfs_num_ar_min_max(struct addrrange *ar, __u32 *min_nid,
502                                __u32 *max_nid)
503 {
504         struct cfs_expr_list *el;
505         struct cfs_range_expr *re;
506         unsigned int min_addr = 0;
507         unsigned int max_addr = 0;
508
509         list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) {
510                 list_for_each_entry(re, &el->el_exprs, re_link) {
511                         if (re->re_lo < min_addr || min_addr == 0)
512                                 min_addr = re->re_lo;
513                         if (re->re_hi > max_addr)
514                                 max_addr = re->re_hi;
515                 }
516         }
517
518         if (min_nid != NULL)
519                 *min_nid = min_addr;
520         if (max_nid != NULL)
521                 *max_nid = max_addr;
522 }
523
524 /**
525  * Determines whether an expression list in an nidrange contains exactly
526  * one contiguous address range. Calls the correct netstrfns for the LND
527  *
528  * \param       *nidlist
529  *
530  * \retval      true if contiguous
531  * \retval      false if not contiguous
532  */
533 bool cfs_nidrange_is_contiguous(struct list_head *nidlist)
534 {
535         struct nidrange *nr;
536         struct netstrfns *nf = NULL;
537         char *lndname = NULL;
538         int netnum = -1;
539
540         list_for_each_entry(nr, nidlist, nr_link) {
541                 nf = nr->nr_netstrfns;
542                 if (lndname == NULL)
543                         lndname = nf->nf_name;
544                 if (netnum == -1)
545                         netnum = nr->nr_netnum;
546
547                 if (strcmp(lndname, nf->nf_name) != 0 ||
548                     netnum != nr->nr_netnum)
549                         return false;
550         }
551
552         if (nf == NULL)
553                 return false;
554
555         if (!nf->nf_is_contiguous(nidlist))
556                 return false;
557
558         return true;
559 }
560 EXPORT_SYMBOL(cfs_nidrange_is_contiguous);
561
562 /**
563  * Determines whether an expression list in an num nidrange contains exactly
564  * one contiguous address range.
565  *
566  * \param       *nidlist
567  *
568  * \retval      true if contiguous
569  * \retval      false if not contiguous
570  */
571 static bool cfs_num_is_contiguous(struct list_head *nidlist)
572 {
573         struct nidrange *nr;
574         struct addrrange *ar;
575         struct cfs_expr_list *el;
576         struct cfs_range_expr *re;
577         int last_hi = 0;
578         __u32 last_end_nid = 0;
579         __u32 current_start_nid = 0;
580         __u32 current_end_nid = 0;
581
582         list_for_each_entry(nr, nidlist, nr_link) {
583                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
584                         cfs_num_ar_min_max(ar, &current_start_nid,
585                                            &current_end_nid);
586                         if (last_end_nid != 0 &&
587                             (current_start_nid - last_end_nid != 1))
588                                         return false;
589                         last_end_nid = current_end_nid;
590                         list_for_each_entry(el, &ar->ar_numaddr_ranges,
591                                             el_link) {
592                                 list_for_each_entry(re, &el->el_exprs,
593                                                     re_link) {
594                                         if (re->re_stride > 1)
595                                                 return false;
596                                         else if (last_hi != 0 &&
597                                                  re->re_hi - last_hi != 1)
598                                                 return false;
599                                         last_hi = re->re_hi;
600                                 }
601                         }
602                 }
603         }
604
605         return true;
606 }
607
608 /**
609  * Determines whether an expression list in an ip nidrange contains exactly
610  * one contiguous address range.
611  *
612  * \param       *nidlist
613  *
614  * \retval      true if contiguous
615  * \retval      false if not contiguous
616  */
617 static bool cfs_ip_is_contiguous(struct list_head *nidlist)
618 {
619         struct nidrange *nr;
620         struct addrrange *ar;
621         struct cfs_expr_list *el;
622         struct cfs_range_expr *re;
623         int expr_count;
624         int last_hi = 255;
625         int last_diff = 0;
626         __u32 last_end_nid = 0;
627         __u32 current_start_nid = 0;
628         __u32 current_end_nid = 0;
629
630         list_for_each_entry(nr, nidlist, nr_link) {
631                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
632                         last_hi = 255;
633                         last_diff = 0;
634                         cfs_ip_ar_min_max(ar, &current_start_nid,
635                                           &current_end_nid);
636                         if (last_end_nid != 0 &&
637                             (current_start_nid - last_end_nid != 1))
638                                         return false;
639                         last_end_nid = current_end_nid;
640                         list_for_each_entry(el,
641                                             &ar->ar_numaddr_ranges,
642                                             el_link) {
643                                 expr_count = 0;
644                                 list_for_each_entry(re, &el->el_exprs,
645                                                     re_link) {
646                                         expr_count++;
647                                         if (re->re_stride > 1 ||
648                                             (last_diff > 0 && last_hi != 255) ||
649                                             (last_diff > 0 && last_hi == 255 &&
650                                              re->re_lo > 0))
651                                                 return false;
652                                         last_hi = re->re_hi;
653                                         last_diff = re->re_hi - re->re_lo;
654                                 }
655                         }
656                 }
657         }
658
659         return true;
660 }
661
662 /**
663  * Takes a linked list of nidrange expressions, determines the minimum
664  * and maximum nid and creates appropriate nid structures
665  *
666  * \param       *nidlist
667  * \param       *min_nid
668  * \param       *max_nid
669  */
670 void cfs_nidrange_find_min_max(struct list_head *nidlist, char *min_nid,
671                                char *max_nid, size_t nidstr_length)
672 {
673         struct nidrange *nr;
674         struct netstrfns *nf = NULL;
675         int netnum = -1;
676         __u32 min_addr;
677         __u32 max_addr;
678         char *lndname = NULL;
679         char min_addr_str[IPSTRING_LENGTH];
680         char max_addr_str[IPSTRING_LENGTH];
681
682         list_for_each_entry(nr, nidlist, nr_link) {
683                 nf = nr->nr_netstrfns;
684                 lndname = nf->nf_name;
685                 if (netnum == -1)
686                         netnum = nr->nr_netnum;
687
688                 nf->nf_min_max(nidlist, &min_addr, &max_addr);
689         }
690         nf->nf_addr2str(min_addr, min_addr_str, sizeof(min_addr_str));
691         nf->nf_addr2str(max_addr, max_addr_str, sizeof(max_addr_str));
692
693         snprintf(min_nid, nidstr_length, "%s@%s%d", min_addr_str, lndname,
694                  netnum);
695         snprintf(max_nid, nidstr_length, "%s@%s%d", max_addr_str, lndname,
696                  netnum);
697 }
698 EXPORT_SYMBOL(cfs_nidrange_find_min_max);
699
700 /**
701  * Determines the min and max NID values for num LNDs
702  *
703  * \param       *nidlist
704  * \param       *min_nid
705  * \param       *max_nid
706  */
707 static void cfs_num_min_max(struct list_head *nidlist, __u32 *min_nid,
708                             __u32 *max_nid)
709 {
710         struct nidrange *nr;
711         struct addrrange *ar;
712         unsigned int tmp_min_addr = 0;
713         unsigned int tmp_max_addr = 0;
714         unsigned int min_addr = 0;
715         unsigned int max_addr = 0;
716
717         list_for_each_entry(nr, nidlist, nr_link) {
718                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
719                         cfs_num_ar_min_max(ar, &tmp_min_addr,
720                                            &tmp_max_addr);
721                         if (tmp_min_addr < min_addr || min_addr == 0)
722                                 min_addr = tmp_min_addr;
723                         if (tmp_max_addr > max_addr)
724                                 max_addr = tmp_min_addr;
725                 }
726         }
727         *max_nid = max_addr;
728         *min_nid = min_addr;
729 }
730
731 /**
732  * Takes an nidlist and determines the minimum and maximum
733  * ip addresses.
734  *
735  * \param       *nidlist
736  * \param       *min_nid
737  * \param       *max_nid
738  */
739 static void cfs_ip_min_max(struct list_head *nidlist, __u32 *min_nid,
740                            __u32 *max_nid)
741 {
742         struct nidrange *nr;
743         struct addrrange *ar;
744         __u32 tmp_min_ip_addr = 0;
745         __u32 tmp_max_ip_addr = 0;
746         __u32 min_ip_addr = 0;
747         __u32 max_ip_addr = 0;
748
749         list_for_each_entry(nr, nidlist, nr_link) {
750                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
751                         cfs_ip_ar_min_max(ar, &tmp_min_ip_addr,
752                                           &tmp_max_ip_addr);
753                         if (tmp_min_ip_addr < min_ip_addr || min_ip_addr == 0)
754                                 min_ip_addr = tmp_min_ip_addr;
755                         if (tmp_max_ip_addr > max_ip_addr)
756                                 max_ip_addr = tmp_max_ip_addr;
757                 }
758         }
759
760         if (min_nid != NULL)
761                 *min_nid = min_ip_addr;
762         if (max_nid != NULL)
763                 *max_nid = max_ip_addr;
764 }
765
766 static int
767 libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
768 {
769         *addr = 0;
770         return 1;
771 }
772
773 static void
774 libcfs_ip_addr2str(__u32 addr, char *str, size_t size)
775 {
776         snprintf(str, size, "%u.%u.%u.%u",
777                  (addr >> 24) & 0xff, (addr >> 16) & 0xff,
778                  (addr >> 8) & 0xff, addr & 0xff);
779 }
780
781 /* CAVEAT EMPTOR XscanfX
782  * I use "%n" at the end of a sscanf format to detect trailing junk.  However
783  * sscanf may return immediately if it sees the terminating '0' in a string, so
784  * I initialise the %n variable to the expected length.  If sscanf sets it;
785  * fine, if it doesn't, then the scan ended at the end of the string, which is
786  * fine too :) */
787 static int
788 libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
789 {
790         unsigned int    a;
791         unsigned int    b;
792         unsigned int    c;
793         unsigned int    d;
794         int             n = nob; /* XscanfX */
795
796         /* numeric IP? */
797         if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
798             n == nob &&
799             (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
800             (c & ~0xff) == 0 && (d & ~0xff) == 0) {
801                 *addr = ((a<<24)|(b<<16)|(c<<8)|d);
802                 return 1;
803         }
804         return 0;
805 }
806
807 /* Used by lnet/config.c so it can't be static */
808 int
809 cfs_ip_addr_parse(char *str, int len, struct list_head *list)
810 {
811         struct cfs_expr_list *el;
812         struct cfs_lstr src;
813         int rc;
814         int i;
815
816         src.ls_str = str;
817         src.ls_len = len;
818         i = 0;
819
820         while (src.ls_str != NULL) {
821                 struct cfs_lstr res;
822
823                 if (!cfs_gettok(&src, '.', &res)) {
824                         rc = -EINVAL;
825                         goto out;
826                 }
827
828                 rc = cfs_expr_list_parse(res.ls_str, res.ls_len, 0, 255, &el);
829                 if (rc != 0)
830                         goto out;
831
832                 list_add_tail(&el->el_link, list);
833                 i++;
834         }
835
836         if (i == 4)
837                 return 0;
838
839         rc = -EINVAL;
840 out:
841         cfs_expr_list_free_list(list);
842
843         return rc;
844 }
845
846 static int
847 libcfs_ip_addr_range_print(char *buffer, int count, struct list_head *list)
848 {
849         int i = 0, j = 0;
850         struct cfs_expr_list *el;
851
852         list_for_each_entry(el, list, el_link) {
853                 LASSERT(j++ < 4);
854                 if (i != 0)
855                         i += scnprintf(buffer + i, count - i, ".");
856                 i += cfs_expr_list_print(buffer + i, count - i, el);
857         }
858         return i;
859 }
860
861 /**
862  * Matches address (\a addr) against address set encoded in \a list.
863  *
864  * \retval 1 if \a addr matches
865  * \retval 0 otherwise
866  */
867 int
868 cfs_ip_addr_match(__u32 addr, struct list_head *list)
869 {
870         struct cfs_expr_list *el;
871         int i = 0;
872
873         list_for_each_entry_reverse(el, list, el_link) {
874                 if (!cfs_expr_list_match(addr & 0xff, el))
875                         return 0;
876                 addr >>= 8;
877                 i++;
878         }
879
880         return i == 4;
881 }
882
883 /**
884  * Print the network part of the nidrange \a nr into the specified \a buffer.
885  *
886  * \retval number of characters written
887  */
888 static void
889 libcfs_decnum_addr2str(__u32 addr, char *str, size_t size)
890 {
891         snprintf(str, size, "%u", addr);
892 }
893
894 static int
895 libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
896 {
897         int     n;
898
899         n = nob;
900         if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
901                 return 1;
902
903         n = nob;
904         if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
905                 return 1;
906
907         n = nob;
908         if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
909                 return 1;
910
911         return 0;
912 }
913
914 /**
915  * Nf_parse_addrlist method for networks using numeric addresses.
916  *
917  * Examples of such networks are gm and elan.
918  *
919  * \retval 0 if \a str parsed to numeric address
920  * \retval errno otherwise
921  */
922 static int
923 libcfs_num_parse(char *str, int len, struct list_head *list)
924 {
925         struct cfs_expr_list *el;
926         int     rc;
927
928         rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
929         if (rc == 0)
930                 list_add_tail(&el->el_link, list);
931
932         return rc;
933 }
934
935 static int
936 libcfs_num_addr_range_print(char *buffer, int count, struct list_head *list)
937 {
938         int i = 0, j = 0;
939         struct cfs_expr_list *el;
940
941         list_for_each_entry(el, list, el_link) {
942                 LASSERT(j++ < 1);
943                 i += cfs_expr_list_print(buffer + i, count - i, el);
944         }
945         return i;
946 }
947
948 /*
949  * Nf_match_addr method for networks using numeric addresses
950  *
951  * \retval 1 on match
952  * \retval 0 otherwise
953  */
954 static int
955 libcfs_num_match(__u32 addr, struct list_head *numaddr)
956 {
957         struct cfs_expr_list *el;
958
959         LASSERT(!list_empty(numaddr));
960         el = list_entry(numaddr->next, struct cfs_expr_list, el_link);
961
962         return cfs_expr_list_match(addr, el);
963 }
964
965 static struct netstrfns libcfs_netstrfns[] = {
966         { .nf_type              = LOLND,
967           .nf_name              = "lo",
968           .nf_modname           = "klolnd",
969           .nf_addr2str          = libcfs_decnum_addr2str,
970           .nf_str2addr          = libcfs_lo_str2addr,
971           .nf_parse_addrlist    = libcfs_num_parse,
972           .nf_print_addrlist    = libcfs_num_addr_range_print,
973           .nf_match_addr        = libcfs_num_match,
974           .nf_is_contiguous     = cfs_num_is_contiguous,
975           .nf_min_max           = cfs_num_min_max },
976         { .nf_type              = SOCKLND,
977           .nf_name              = "tcp",
978           .nf_modname           = "ksocklnd",
979           .nf_addr2str          = libcfs_ip_addr2str,
980           .nf_str2addr          = libcfs_ip_str2addr,
981           .nf_parse_addrlist    = cfs_ip_addr_parse,
982           .nf_print_addrlist    = libcfs_ip_addr_range_print,
983           .nf_match_addr        = cfs_ip_addr_match,
984           .nf_is_contiguous     = cfs_ip_is_contiguous,
985           .nf_min_max           = cfs_ip_min_max },
986         { .nf_type              = O2IBLND,
987           .nf_name              = "o2ib",
988           .nf_modname           = "ko2iblnd",
989           .nf_addr2str          = libcfs_ip_addr2str,
990           .nf_str2addr          = libcfs_ip_str2addr,
991           .nf_parse_addrlist    = cfs_ip_addr_parse,
992           .nf_print_addrlist    = libcfs_ip_addr_range_print,
993           .nf_match_addr        = cfs_ip_addr_match,
994           .nf_is_contiguous     = cfs_ip_is_contiguous,
995           .nf_min_max           = cfs_ip_min_max },
996         { .nf_type              = GNILND,
997           .nf_name              = "gni",
998           .nf_modname           = "kgnilnd",
999           .nf_addr2str          = libcfs_decnum_addr2str,
1000           .nf_str2addr          = libcfs_num_str2addr,
1001           .nf_parse_addrlist    = libcfs_num_parse,
1002           .nf_print_addrlist    = libcfs_num_addr_range_print,
1003           .nf_match_addr        = libcfs_num_match,
1004           .nf_is_contiguous     = cfs_num_is_contiguous,
1005           .nf_min_max           = cfs_num_min_max },
1006         { .nf_type              = GNIIPLND,
1007           .nf_name              = "gip",
1008           .nf_modname           = "kgnilnd",
1009           .nf_addr2str          = libcfs_ip_addr2str,
1010           .nf_str2addr          = libcfs_ip_str2addr,
1011           .nf_parse_addrlist    = cfs_ip_addr_parse,
1012           .nf_print_addrlist    = libcfs_ip_addr_range_print,
1013           .nf_match_addr        = cfs_ip_addr_match,
1014           .nf_is_contiguous     = cfs_ip_is_contiguous,
1015           .nf_min_max           = cfs_ip_min_max },
1016         { .nf_type              = PTL4LND,
1017           .nf_name              = "ptlf",
1018           .nf_modname           = "kptl4lnd",
1019           .nf_addr2str          = libcfs_decnum_addr2str,
1020           .nf_str2addr          = libcfs_num_str2addr,
1021           .nf_parse_addrlist    = libcfs_num_parse,
1022           .nf_print_addrlist    = libcfs_num_addr_range_print,
1023           .nf_match_addr        = libcfs_num_match,
1024           .nf_is_contiguous     = cfs_num_is_contiguous,
1025           .nf_min_max           = cfs_num_min_max},
1026 };
1027
1028 static const size_t libcfs_nnetstrfns = ARRAY_SIZE(libcfs_netstrfns);
1029
1030 static struct netstrfns *
1031 libcfs_lnd2netstrfns(__u32 lnd)
1032 {
1033         int     i;
1034
1035         for (i = 0; i < libcfs_nnetstrfns; i++)
1036                 if (lnd == libcfs_netstrfns[i].nf_type)
1037                         return &libcfs_netstrfns[i];
1038
1039         return NULL;
1040 }
1041
1042 static struct netstrfns *
1043 libcfs_namenum2netstrfns(const char *name)
1044 {
1045         struct netstrfns *nf;
1046         int               i;
1047
1048         for (i = 0; i < libcfs_nnetstrfns; i++) {
1049                 nf = &libcfs_netstrfns[i];
1050                 if (!strncmp(name, nf->nf_name, strlen(nf->nf_name)))
1051                         return nf;
1052         }
1053         return NULL;
1054 }
1055
1056 static struct netstrfns *
1057 libcfs_name2netstrfns(const char *name)
1058 {
1059         int    i;
1060
1061         for (i = 0; i < libcfs_nnetstrfns; i++)
1062                 if (!strcmp(libcfs_netstrfns[i].nf_name, name))
1063                         return &libcfs_netstrfns[i];
1064
1065         return NULL;
1066 }
1067
1068 int
1069 libcfs_isknown_lnd(__u32 lnd)
1070 {
1071         return libcfs_lnd2netstrfns(lnd) != NULL;
1072 }
1073 EXPORT_SYMBOL(libcfs_isknown_lnd);
1074
1075 char *
1076 libcfs_lnd2modname(__u32 lnd)
1077 {
1078         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
1079
1080         return (nf == NULL) ? NULL : nf->nf_modname;
1081 }
1082 EXPORT_SYMBOL(libcfs_lnd2modname);
1083
1084 int
1085 libcfs_str2lnd(const char *str)
1086 {
1087         struct netstrfns *nf = libcfs_name2netstrfns(str);
1088
1089         if (nf != NULL)
1090                 return nf->nf_type;
1091
1092         return -ENXIO;
1093 }
1094 EXPORT_SYMBOL(libcfs_str2lnd);
1095
1096 char *
1097 libcfs_lnd2str_r(__u32 lnd, char *buf, size_t buf_size)
1098 {
1099         struct netstrfns *nf;
1100
1101         nf = libcfs_lnd2netstrfns(lnd);
1102         if (nf == NULL)
1103                 snprintf(buf, buf_size, "?%u?", lnd);
1104         else
1105                 snprintf(buf, buf_size, "%s", nf->nf_name);
1106
1107         return buf;
1108 }
1109 EXPORT_SYMBOL(libcfs_lnd2str_r);
1110
1111 char *
1112 libcfs_net2str_r(__u32 net, char *buf, size_t buf_size)
1113 {
1114         __u32             nnum = LNET_NETNUM(net);
1115         __u32             lnd  = LNET_NETTYP(net);
1116         struct netstrfns *nf;
1117
1118         nf = libcfs_lnd2netstrfns(lnd);
1119         if (nf == NULL)
1120                 snprintf(buf, buf_size, "<%u:%u>", lnd, nnum);
1121         else if (nnum == 0)
1122                 snprintf(buf, buf_size, "%s", nf->nf_name);
1123         else
1124                 snprintf(buf, buf_size, "%s%u", nf->nf_name, nnum);
1125
1126         return buf;
1127 }
1128 EXPORT_SYMBOL(libcfs_net2str_r);
1129
1130 char *
1131 libcfs_nid2str_r(lnet_nid_t nid, char *buf, size_t buf_size)
1132 {
1133         __u32             addr = LNET_NIDADDR(nid);
1134         __u32             net  = LNET_NIDNET(nid);
1135         __u32             nnum = LNET_NETNUM(net);
1136         __u32             lnd  = LNET_NETTYP(net);
1137         struct netstrfns *nf;
1138
1139         if (nid == LNET_NID_ANY) {
1140                 strncpy(buf, "<?>", buf_size);
1141                 buf[buf_size - 1] = '\0';
1142                 return buf;
1143         }
1144
1145         nf = libcfs_lnd2netstrfns(lnd);
1146         if (nf == NULL) {
1147                 snprintf(buf, buf_size, "%x@<%u:%u>", addr, lnd, nnum);
1148         } else {
1149                 size_t addr_len;
1150
1151                 nf->nf_addr2str(addr, buf, buf_size);
1152                 addr_len = strlen(buf);
1153                 if (nnum == 0)
1154                         snprintf(buf + addr_len, buf_size - addr_len, "@%s",
1155                                  nf->nf_name);
1156                 else
1157                         snprintf(buf + addr_len, buf_size - addr_len, "@%s%u",
1158                                  nf->nf_name, nnum);
1159         }
1160
1161         return buf;
1162 }
1163 EXPORT_SYMBOL(libcfs_nid2str_r);
1164
1165 static struct netstrfns *
1166 libcfs_str2net_internal(const char *str, __u32 *net)
1167 {
1168         struct netstrfns *nf = NULL;
1169         int               nob;
1170         unsigned int      netnum;
1171         int               i;
1172
1173         for (i = 0; i < libcfs_nnetstrfns; i++) {
1174                 nf = &libcfs_netstrfns[i];
1175                 if (!strncmp(str, nf->nf_name, strlen(nf->nf_name)))
1176                         break;
1177         }
1178
1179         if (i == libcfs_nnetstrfns)
1180                 return NULL;
1181
1182         nob = strlen(nf->nf_name);
1183
1184         if (strlen(str) == (unsigned int)nob) {
1185                 netnum = 0;
1186         } else {
1187                 if (nf->nf_type == LOLND) /* net number not allowed */
1188                         return NULL;
1189
1190                 str += nob;
1191                 i = strlen(str);
1192                 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
1193                     i != (int)strlen(str))
1194                         return NULL;
1195         }
1196
1197         *net = LNET_MKNET(nf->nf_type, netnum);
1198         return nf;
1199 }
1200
1201 __u32
1202 libcfs_str2net(const char *str)
1203 {
1204         __u32  net;
1205
1206         if (libcfs_str2net_internal(str, &net) != NULL)
1207                 return net;
1208
1209         return LNET_NIDNET(LNET_NID_ANY);
1210 }
1211 EXPORT_SYMBOL(libcfs_str2net);
1212
1213 lnet_nid_t
1214 libcfs_str2nid(const char *str)
1215 {
1216         const char       *sep = strchr(str, '@');
1217         struct netstrfns *nf;
1218         __u32             net;
1219         __u32             addr;
1220
1221         if (sep != NULL) {
1222                 nf = libcfs_str2net_internal(sep + 1, &net);
1223                 if (nf == NULL)
1224                         return LNET_NID_ANY;
1225         } else {
1226                 sep = str + strlen(str);
1227                 net = LNET_MKNET(SOCKLND, 0);
1228                 nf = libcfs_lnd2netstrfns(SOCKLND);
1229                 LASSERT(nf != NULL);
1230         }
1231
1232         if (!nf->nf_str2addr(str, (int)(sep - str), &addr))
1233                 return LNET_NID_ANY;
1234
1235         return LNET_MKNID(net, addr);
1236 }
1237 EXPORT_SYMBOL(libcfs_str2nid);
1238
1239 char *
1240 libcfs_id2str(lnet_process_id_t id)
1241 {
1242         char *str = libcfs_next_nidstring();
1243
1244         if (id.pid == LNET_PID_ANY) {
1245                 snprintf(str, LNET_NIDSTR_SIZE,
1246                          "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
1247                 return str;
1248         }
1249
1250         snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
1251                  ((id.pid & LNET_PID_USERFLAG) != 0) ? "U" : "",
1252                  (id.pid & ~LNET_PID_USERFLAG), libcfs_nid2str(id.nid));
1253         return str;
1254 }
1255 EXPORT_SYMBOL(libcfs_id2str);
1256
1257 int
1258 libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
1259 {
1260         if (!strcmp(str, "*")) {
1261                 *nidp = LNET_NID_ANY;
1262                 return 1;
1263         }
1264
1265         *nidp = libcfs_str2nid(str);
1266         return *nidp != LNET_NID_ANY;
1267 }
1268 EXPORT_SYMBOL(libcfs_str2anynid);