Whamcloud - gitweb
LU-8912 nodemap: fix contiguous range support
[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, 2015, 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 <uapi/linux/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[out]  *min_nid __u32 representation of min NID
460  * \param[out]  *max_nid __u32 representation of max NID
461  * \retval      -EINVAL unsupported LNET range
462  * \retval      -ERANGE non-contiguous LNET range
463  */
464 static int cfs_ip_ar_min_max(struct addrrange *ar, __u32 *min_nid,
465                               __u32 *max_nid)
466 {
467         struct cfs_expr_list *expr_list;
468         struct cfs_range_expr *range;
469         unsigned int min_ip[4] = {0};
470         unsigned int max_ip[4] = {0};
471         int cur_octet = 0;
472         bool expect_full_octet = false;
473
474         list_for_each_entry(expr_list, &ar->ar_numaddr_ranges, el_link) {
475                 int re_count = 0;
476
477                 list_for_each_entry(range, &expr_list->el_exprs, re_link) {
478                         /* XXX: add support for multiple & non-contig. re's */
479                         if (re_count > 0)
480                                 return -EINVAL;
481
482                         /* if a previous octet was ranged, then all remaining
483                          * octets must be full for contiguous range */
484                         if (expect_full_octet && (range->re_lo != 0 ||
485                                                   range->re_hi != 255))
486                                 return -ERANGE;
487
488                         if (range->re_stride != 1)
489                                 return -ERANGE;
490
491                         if (range->re_lo > range->re_hi)
492                                 return -EINVAL;
493
494                         if (range->re_lo != range->re_hi)
495                                 expect_full_octet = true;
496
497                         min_ip[cur_octet] = range->re_lo;
498                         max_ip[cur_octet] = range->re_hi;
499
500                         re_count++;
501                 }
502
503                 cur_octet++;
504         }
505
506         if (min_nid != NULL)
507                 *min_nid = ((min_ip[0] << 24) | (min_ip[1] << 16) |
508                             (min_ip[2] << 8) | min_ip[3]);
509
510         if (max_nid != NULL)
511                 *max_nid = ((max_ip[0] << 24) | (max_ip[1] << 16) |
512                             (max_ip[2] << 8) | max_ip[3]);
513
514         return 0;
515 }
516
517 /**
518  * Determines minimum and maximum addresses for a single
519  * numeric address range
520  *
521  * \param       ar
522  * \param[out]  *min_nid __u32 representation of min NID
523  * \param[out]  *max_nid __u32 representation of max NID
524  * \retval      -EINVAL unsupported LNET range
525  */
526 static int cfs_num_ar_min_max(struct addrrange *ar, __u32 *min_nid,
527                                __u32 *max_nid)
528 {
529         struct cfs_expr_list *el;
530         struct cfs_range_expr *re;
531         unsigned int min_addr = 0;
532         unsigned int max_addr = 0;
533
534         list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) {
535                 int re_count = 0;
536
537                 list_for_each_entry(re, &el->el_exprs, re_link) {
538                         if (re_count > 0)
539                                 return -EINVAL;
540                         if (re->re_lo > re->re_hi)
541                                 return -EINVAL;
542
543                         if (re->re_lo < min_addr || min_addr == 0)
544                                 min_addr = re->re_lo;
545                         if (re->re_hi > max_addr)
546                                 max_addr = re->re_hi;
547
548                         re_count++;
549                 }
550         }
551
552         if (min_nid != NULL)
553                 *min_nid = min_addr;
554         if (max_nid != NULL)
555                 *max_nid = max_addr;
556
557         return 0;
558 }
559
560 /**
561  * Takes a linked list of nidrange expressions, determines the minimum
562  * and maximum nid and creates appropriate nid structures
563  *
564  * \param[out]  *min_nid string representation of min NID
565  * \param[out]  *max_nid string representation of max NID
566  * \retval      -EINVAL unsupported LNET range
567  * \retval      -ERANGE non-contiguous LNET range
568  */
569 int cfs_nidrange_find_min_max(struct list_head *nidlist, char *min_nid,
570                               char *max_nid, size_t nidstr_length)
571 {
572         struct nidrange *first_nidrange;
573         int netnum;
574         struct netstrfns *nf;
575         char *lndname;
576         __u32 min_addr;
577         __u32 max_addr;
578         char min_addr_str[IPSTRING_LENGTH];
579         char max_addr_str[IPSTRING_LENGTH];
580         int rc;
581
582         first_nidrange = list_entry(nidlist->next, struct nidrange, nr_link);
583
584         netnum = first_nidrange->nr_netnum;
585         nf = first_nidrange->nr_netstrfns;
586         lndname = nf->nf_name;
587
588         rc = nf->nf_min_max(nidlist, &min_addr, &max_addr);
589         if (rc < 0)
590                 return rc;
591
592         nf->nf_addr2str(min_addr, min_addr_str, sizeof(min_addr_str));
593         nf->nf_addr2str(max_addr, max_addr_str, sizeof(max_addr_str));
594
595         snprintf(min_nid, nidstr_length, "%s@%s%d", min_addr_str, lndname,
596                  netnum);
597         snprintf(max_nid, nidstr_length, "%s@%s%d", max_addr_str, lndname,
598                  netnum);
599
600         return 0;
601 }
602 EXPORT_SYMBOL(cfs_nidrange_find_min_max);
603
604 /**
605  * Determines the min and max NID values for num LNDs
606  *
607  * \param       *nidlist
608  * \param[out]  *min_nid if provided, returns string representation of min NID
609  * \param[out]  *max_nid if provided, returns string representation of max NID
610  * \retval      -EINVAL unsupported LNET range
611  * \retval      -ERANGE non-contiguous LNET range
612  */
613 static int cfs_num_min_max(struct list_head *nidlist, __u32 *min_nid,
614                             __u32 *max_nid)
615 {
616         struct nidrange *nr;
617         struct addrrange *ar;
618         unsigned int tmp_min_addr = 0;
619         unsigned int tmp_max_addr = 0;
620         unsigned int min_addr = 0;
621         unsigned int max_addr = 0;
622         int nidlist_count = 0;
623         int rc;
624
625         list_for_each_entry(nr, nidlist, nr_link) {
626                 if (nidlist_count > 0)
627                         return -EINVAL;
628
629                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
630                         rc = cfs_num_ar_min_max(ar, &tmp_min_addr,
631                                                 &tmp_max_addr);
632                         if (rc < 0)
633                                 return rc;
634
635                         if (tmp_min_addr < min_addr || min_addr == 0)
636                                 min_addr = tmp_min_addr;
637                         if (tmp_max_addr > max_addr)
638                                 max_addr = tmp_min_addr;
639                 }
640         }
641         if (max_nid != NULL)
642                 *max_nid = max_addr;
643         if (min_nid != NULL)
644                 *min_nid = min_addr;
645
646         return 0;
647 }
648
649 /**
650  * Takes an nidlist and determines the minimum and maximum
651  * ip addresses.
652  *
653  * \param       *nidlist
654  * \param[out]  *min_nid if provided, returns string representation of min NID
655  * \param[out]  *max_nid if provided, returns string representation of max NID
656  * \retval      -EINVAL unsupported LNET range
657  * \retval      -ERANGE non-contiguous LNET range
658  */
659 static int cfs_ip_min_max(struct list_head *nidlist, __u32 *min_nid,
660                            __u32 *max_nid)
661 {
662         struct nidrange *nr;
663         struct addrrange *ar;
664         __u32 tmp_min_ip_addr = 0;
665         __u32 tmp_max_ip_addr = 0;
666         __u32 min_ip_addr = 0;
667         __u32 max_ip_addr = 0;
668         int nidlist_count = 0;
669         int rc;
670
671         list_for_each_entry(nr, nidlist, nr_link) {
672                 if (nidlist_count > 0)
673                         return -EINVAL;
674
675                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
676                         rc = cfs_ip_ar_min_max(ar, &tmp_min_ip_addr,
677                                                &tmp_max_ip_addr);
678                         if (rc < 0)
679                                 return rc;
680
681                         if (tmp_min_ip_addr < min_ip_addr || min_ip_addr == 0)
682                                 min_ip_addr = tmp_min_ip_addr;
683                         if (tmp_max_ip_addr > max_ip_addr)
684                                 max_ip_addr = tmp_max_ip_addr;
685                 }
686
687                 nidlist_count++;
688         }
689
690         if (max_nid != NULL)
691                 *max_nid = max_ip_addr;
692         if (min_nid != NULL)
693                 *min_nid = min_ip_addr;
694
695         return 0;
696 }
697
698 static int
699 libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
700 {
701         *addr = 0;
702         return 1;
703 }
704
705 static void
706 libcfs_ip_addr2str(__u32 addr, char *str, size_t size)
707 {
708         snprintf(str, size, "%u.%u.%u.%u",
709                  (addr >> 24) & 0xff, (addr >> 16) & 0xff,
710                  (addr >> 8) & 0xff, addr & 0xff);
711 }
712
713 /* CAVEAT EMPTOR XscanfX
714  * I use "%n" at the end of a sscanf format to detect trailing junk.  However
715  * sscanf may return immediately if it sees the terminating '0' in a string, so
716  * I initialise the %n variable to the expected length.  If sscanf sets it;
717  * fine, if it doesn't, then the scan ended at the end of the string, which is
718  * fine too :) */
719 static int
720 libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
721 {
722         unsigned int    a;
723         unsigned int    b;
724         unsigned int    c;
725         unsigned int    d;
726         int             n = nob; /* XscanfX */
727
728         /* numeric IP? */
729         if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
730             n == nob &&
731             (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
732             (c & ~0xff) == 0 && (d & ~0xff) == 0) {
733                 *addr = ((a<<24)|(b<<16)|(c<<8)|d);
734                 return 1;
735         }
736         return 0;
737 }
738
739 /* Used by lnet/config.c so it can't be static */
740 int
741 cfs_ip_addr_parse(char *str, int len, struct list_head *list)
742 {
743         struct cfs_expr_list *el;
744         struct cfs_lstr src;
745         int rc;
746         int i;
747
748         src.ls_str = str;
749         src.ls_len = len;
750         i = 0;
751
752         while (src.ls_str != NULL) {
753                 struct cfs_lstr res;
754
755                 if (!cfs_gettok(&src, '.', &res)) {
756                         rc = -EINVAL;
757                         goto out;
758                 }
759
760                 rc = cfs_expr_list_parse(res.ls_str, res.ls_len, 0, 255, &el);
761                 if (rc != 0)
762                         goto out;
763
764                 list_add_tail(&el->el_link, list);
765                 i++;
766         }
767
768         if (i == 4)
769                 return 0;
770
771         rc = -EINVAL;
772 out:
773         cfs_expr_list_free_list(list);
774
775         return rc;
776 }
777
778 static int
779 libcfs_ip_addr_range_print(char *buffer, int count, struct list_head *list)
780 {
781         int i = 0, j = 0;
782         struct cfs_expr_list *el;
783
784         list_for_each_entry(el, list, el_link) {
785                 LASSERT(j++ < 4);
786                 if (i != 0)
787                         i += scnprintf(buffer + i, count - i, ".");
788                 i += cfs_expr_list_print(buffer + i, count - i, el);
789         }
790         return i;
791 }
792
793 /**
794  * Matches address (\a addr) against address set encoded in \a list.
795  *
796  * \retval 1 if \a addr matches
797  * \retval 0 otherwise
798  */
799 int
800 cfs_ip_addr_match(__u32 addr, struct list_head *list)
801 {
802         struct cfs_expr_list *el;
803         int i = 0;
804
805         list_for_each_entry_reverse(el, list, el_link) {
806                 if (!cfs_expr_list_match(addr & 0xff, el))
807                         return 0;
808                 addr >>= 8;
809                 i++;
810         }
811
812         return i == 4;
813 }
814
815 /**
816  * Print the network part of the nidrange \a nr into the specified \a buffer.
817  *
818  * \retval number of characters written
819  */
820 static void
821 libcfs_decnum_addr2str(__u32 addr, char *str, size_t size)
822 {
823         snprintf(str, size, "%u", addr);
824 }
825
826 static int
827 libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
828 {
829         int     n;
830
831         n = nob;
832         if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
833                 return 1;
834
835         n = nob;
836         if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
837                 return 1;
838
839         n = nob;
840         if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
841                 return 1;
842
843         return 0;
844 }
845
846 /**
847  * Nf_parse_addrlist method for networks using numeric addresses.
848  *
849  * Examples of such networks are gm and elan.
850  *
851  * \retval 0 if \a str parsed to numeric address
852  * \retval errno otherwise
853  */
854 static int
855 libcfs_num_parse(char *str, int len, struct list_head *list)
856 {
857         struct cfs_expr_list *el;
858         int     rc;
859
860         rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
861         if (rc == 0)
862                 list_add_tail(&el->el_link, list);
863
864         return rc;
865 }
866
867 static int
868 libcfs_num_addr_range_print(char *buffer, int count, struct list_head *list)
869 {
870         int i = 0, j = 0;
871         struct cfs_expr_list *el;
872
873         list_for_each_entry(el, list, el_link) {
874                 LASSERT(j++ < 1);
875                 i += cfs_expr_list_print(buffer + i, count - i, el);
876         }
877         return i;
878 }
879
880 /*
881  * Nf_match_addr method for networks using numeric addresses
882  *
883  * \retval 1 on match
884  * \retval 0 otherwise
885  */
886 static int
887 libcfs_num_match(__u32 addr, struct list_head *numaddr)
888 {
889         struct cfs_expr_list *el;
890
891         LASSERT(!list_empty(numaddr));
892         el = list_entry(numaddr->next, struct cfs_expr_list, el_link);
893
894         return cfs_expr_list_match(addr, el);
895 }
896
897 static struct netstrfns libcfs_netstrfns[] = {
898         { .nf_type              = LOLND,
899           .nf_name              = "lo",
900           .nf_modname           = "klolnd",
901           .nf_addr2str          = libcfs_decnum_addr2str,
902           .nf_str2addr          = libcfs_lo_str2addr,
903           .nf_parse_addrlist    = libcfs_num_parse,
904           .nf_print_addrlist    = libcfs_num_addr_range_print,
905           .nf_match_addr        = libcfs_num_match,
906           .nf_min_max           = cfs_num_min_max },
907         { .nf_type              = SOCKLND,
908           .nf_name              = "tcp",
909           .nf_modname           = "ksocklnd",
910           .nf_addr2str          = libcfs_ip_addr2str,
911           .nf_str2addr          = libcfs_ip_str2addr,
912           .nf_parse_addrlist    = cfs_ip_addr_parse,
913           .nf_print_addrlist    = libcfs_ip_addr_range_print,
914           .nf_match_addr        = cfs_ip_addr_match,
915           .nf_min_max           = cfs_ip_min_max },
916         { .nf_type              = O2IBLND,
917           .nf_name              = "o2ib",
918           .nf_modname           = "ko2iblnd",
919           .nf_addr2str          = libcfs_ip_addr2str,
920           .nf_str2addr          = libcfs_ip_str2addr,
921           .nf_parse_addrlist    = cfs_ip_addr_parse,
922           .nf_print_addrlist    = libcfs_ip_addr_range_print,
923           .nf_match_addr        = cfs_ip_addr_match,
924           .nf_min_max           = cfs_ip_min_max },
925         { .nf_type              = GNILND,
926           .nf_name              = "gni",
927           .nf_modname           = "kgnilnd",
928           .nf_addr2str          = libcfs_decnum_addr2str,
929           .nf_str2addr          = libcfs_num_str2addr,
930           .nf_parse_addrlist    = libcfs_num_parse,
931           .nf_print_addrlist    = libcfs_num_addr_range_print,
932           .nf_match_addr        = libcfs_num_match,
933           .nf_min_max           = cfs_num_min_max },
934         { .nf_type              = GNIIPLND,
935           .nf_name              = "gip",
936           .nf_modname           = "kgnilnd",
937           .nf_addr2str          = libcfs_ip_addr2str,
938           .nf_str2addr          = libcfs_ip_str2addr,
939           .nf_parse_addrlist    = cfs_ip_addr_parse,
940           .nf_print_addrlist    = libcfs_ip_addr_range_print,
941           .nf_match_addr        = cfs_ip_addr_match,
942           .nf_min_max           = cfs_ip_min_max },
943         { .nf_type              = PTL4LND,
944           .nf_name              = "ptlf",
945           .nf_modname           = "kptl4lnd",
946           .nf_addr2str          = libcfs_decnum_addr2str,
947           .nf_str2addr          = libcfs_num_str2addr,
948           .nf_parse_addrlist    = libcfs_num_parse,
949           .nf_print_addrlist    = libcfs_num_addr_range_print,
950           .nf_match_addr        = libcfs_num_match,
951           .nf_min_max           = cfs_num_min_max},
952 };
953
954 static const size_t libcfs_nnetstrfns = ARRAY_SIZE(libcfs_netstrfns);
955
956 static struct netstrfns *
957 libcfs_lnd2netstrfns(__u32 lnd)
958 {
959         int     i;
960
961         for (i = 0; i < libcfs_nnetstrfns; i++)
962                 if (lnd == libcfs_netstrfns[i].nf_type)
963                         return &libcfs_netstrfns[i];
964
965         return NULL;
966 }
967
968 static struct netstrfns *
969 libcfs_namenum2netstrfns(const char *name)
970 {
971         struct netstrfns *nf;
972         int               i;
973
974         for (i = 0; i < libcfs_nnetstrfns; i++) {
975                 nf = &libcfs_netstrfns[i];
976                 if (!strncmp(name, nf->nf_name, strlen(nf->nf_name)))
977                         return nf;
978         }
979         return NULL;
980 }
981
982 static struct netstrfns *
983 libcfs_name2netstrfns(const char *name)
984 {
985         int    i;
986
987         for (i = 0; i < libcfs_nnetstrfns; i++)
988                 if (!strcmp(libcfs_netstrfns[i].nf_name, name))
989                         return &libcfs_netstrfns[i];
990
991         return NULL;
992 }
993
994 int
995 libcfs_isknown_lnd(__u32 lnd)
996 {
997         return libcfs_lnd2netstrfns(lnd) != NULL;
998 }
999 EXPORT_SYMBOL(libcfs_isknown_lnd);
1000
1001 char *
1002 libcfs_lnd2modname(__u32 lnd)
1003 {
1004         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
1005
1006         return (nf == NULL) ? NULL : nf->nf_modname;
1007 }
1008 EXPORT_SYMBOL(libcfs_lnd2modname);
1009
1010 int
1011 libcfs_str2lnd(const char *str)
1012 {
1013         struct netstrfns *nf = libcfs_name2netstrfns(str);
1014
1015         if (nf != NULL)
1016                 return nf->nf_type;
1017
1018         return -ENXIO;
1019 }
1020 EXPORT_SYMBOL(libcfs_str2lnd);
1021
1022 char *
1023 libcfs_lnd2str_r(__u32 lnd, char *buf, size_t buf_size)
1024 {
1025         struct netstrfns *nf;
1026
1027         nf = libcfs_lnd2netstrfns(lnd);
1028         if (nf == NULL)
1029                 snprintf(buf, buf_size, "?%u?", lnd);
1030         else
1031                 snprintf(buf, buf_size, "%s", nf->nf_name);
1032
1033         return buf;
1034 }
1035 EXPORT_SYMBOL(libcfs_lnd2str_r);
1036
1037 char *
1038 libcfs_net2str_r(__u32 net, char *buf, size_t buf_size)
1039 {
1040         __u32             nnum = LNET_NETNUM(net);
1041         __u32             lnd  = LNET_NETTYP(net);
1042         struct netstrfns *nf;
1043
1044         nf = libcfs_lnd2netstrfns(lnd);
1045         if (nf == NULL)
1046                 snprintf(buf, buf_size, "<%u:%u>", lnd, nnum);
1047         else if (nnum == 0)
1048                 snprintf(buf, buf_size, "%s", nf->nf_name);
1049         else
1050                 snprintf(buf, buf_size, "%s%u", nf->nf_name, nnum);
1051
1052         return buf;
1053 }
1054 EXPORT_SYMBOL(libcfs_net2str_r);
1055
1056 char *
1057 libcfs_nid2str_r(lnet_nid_t nid, char *buf, size_t buf_size)
1058 {
1059         __u32             addr = LNET_NIDADDR(nid);
1060         __u32             net  = LNET_NIDNET(nid);
1061         __u32             nnum = LNET_NETNUM(net);
1062         __u32             lnd  = LNET_NETTYP(net);
1063         struct netstrfns *nf;
1064
1065         if (nid == LNET_NID_ANY) {
1066                 strncpy(buf, "<?>", buf_size);
1067                 buf[buf_size - 1] = '\0';
1068                 return buf;
1069         }
1070
1071         nf = libcfs_lnd2netstrfns(lnd);
1072         if (nf == NULL) {
1073                 snprintf(buf, buf_size, "%x@<%u:%u>", addr, lnd, nnum);
1074         } else {
1075                 size_t addr_len;
1076
1077                 nf->nf_addr2str(addr, buf, buf_size);
1078                 addr_len = strlen(buf);
1079                 if (nnum == 0)
1080                         snprintf(buf + addr_len, buf_size - addr_len, "@%s",
1081                                  nf->nf_name);
1082                 else
1083                         snprintf(buf + addr_len, buf_size - addr_len, "@%s%u",
1084                                  nf->nf_name, nnum);
1085         }
1086
1087         return buf;
1088 }
1089 EXPORT_SYMBOL(libcfs_nid2str_r);
1090
1091 static struct netstrfns *
1092 libcfs_str2net_internal(const char *str, __u32 *net)
1093 {
1094         struct netstrfns *nf = NULL;
1095         int               nob;
1096         unsigned int      netnum;
1097         int               i;
1098
1099         for (i = 0; i < libcfs_nnetstrfns; i++) {
1100                 nf = &libcfs_netstrfns[i];
1101                 if (!strncmp(str, nf->nf_name, strlen(nf->nf_name)))
1102                         break;
1103         }
1104
1105         if (i == libcfs_nnetstrfns)
1106                 return NULL;
1107
1108         nob = strlen(nf->nf_name);
1109
1110         if (strlen(str) == (unsigned int)nob) {
1111                 netnum = 0;
1112         } else {
1113                 if (nf->nf_type == LOLND) /* net number not allowed */
1114                         return NULL;
1115
1116                 str += nob;
1117                 i = strlen(str);
1118                 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
1119                     i != (int)strlen(str))
1120                         return NULL;
1121         }
1122
1123         *net = LNET_MKNET(nf->nf_type, netnum);
1124         return nf;
1125 }
1126
1127 __u32
1128 libcfs_str2net(const char *str)
1129 {
1130         __u32  net;
1131
1132         if (libcfs_str2net_internal(str, &net) != NULL)
1133                 return net;
1134
1135         return LNET_NIDNET(LNET_NID_ANY);
1136 }
1137 EXPORT_SYMBOL(libcfs_str2net);
1138
1139 lnet_nid_t
1140 libcfs_str2nid(const char *str)
1141 {
1142         const char       *sep = strchr(str, '@');
1143         struct netstrfns *nf;
1144         __u32             net;
1145         __u32             addr;
1146
1147         if (sep != NULL) {
1148                 nf = libcfs_str2net_internal(sep + 1, &net);
1149                 if (nf == NULL)
1150                         return LNET_NID_ANY;
1151         } else {
1152                 sep = str + strlen(str);
1153                 net = LNET_MKNET(SOCKLND, 0);
1154                 nf = libcfs_lnd2netstrfns(SOCKLND);
1155                 LASSERT(nf != NULL);
1156         }
1157
1158         if (!nf->nf_str2addr(str, (int)(sep - str), &addr))
1159                 return LNET_NID_ANY;
1160
1161         return LNET_MKNID(net, addr);
1162 }
1163 EXPORT_SYMBOL(libcfs_str2nid);
1164
1165 char *
1166 libcfs_id2str(struct lnet_process_id id)
1167 {
1168         char *str = libcfs_next_nidstring();
1169
1170         if (id.pid == LNET_PID_ANY) {
1171                 snprintf(str, LNET_NIDSTR_SIZE,
1172                          "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
1173                 return str;
1174         }
1175
1176         snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
1177                  ((id.pid & LNET_PID_USERFLAG) != 0) ? "U" : "",
1178                  (id.pid & ~LNET_PID_USERFLAG), libcfs_nid2str(id.nid));
1179         return str;
1180 }
1181 EXPORT_SYMBOL(libcfs_id2str);
1182
1183 int
1184 libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
1185 {
1186         if (!strcmp(str, "*")) {
1187                 *nidp = LNET_NID_ANY;
1188                 return 1;
1189         }
1190
1191         *nidp = libcfs_str2nid(str);
1192         return *nidp != LNET_NID_ANY;
1193 }
1194 EXPORT_SYMBOL(libcfs_str2anynid);