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