Whamcloud - gitweb
LU-11635 gss: proper gss build for client-only
[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                 if (nr->nr_all) {
676                         min_ip_addr = 0;
677                         max_ip_addr = 0xffffffff;
678                         break;
679                 }
680
681                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
682                         rc = cfs_ip_ar_min_max(ar, &tmp_min_ip_addr,
683                                                &tmp_max_ip_addr);
684                         if (rc < 0)
685                                 return rc;
686
687                         if (tmp_min_ip_addr < min_ip_addr || min_ip_addr == 0)
688                                 min_ip_addr = tmp_min_ip_addr;
689                         if (tmp_max_ip_addr > max_ip_addr)
690                                 max_ip_addr = tmp_max_ip_addr;
691                 }
692
693                 nidlist_count++;
694         }
695
696         if (max_nid != NULL)
697                 *max_nid = max_ip_addr;
698         if (min_nid != NULL)
699                 *min_nid = min_ip_addr;
700
701         return 0;
702 }
703
704 static int
705 libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
706 {
707         *addr = 0;
708         return 1;
709 }
710
711 static void
712 libcfs_ip_addr2str(__u32 addr, char *str, size_t size)
713 {
714         snprintf(str, size, "%u.%u.%u.%u",
715                  (addr >> 24) & 0xff, (addr >> 16) & 0xff,
716                  (addr >> 8) & 0xff, addr & 0xff);
717 }
718
719 /* CAVEAT EMPTOR XscanfX
720  * I use "%n" at the end of a sscanf format to detect trailing junk.  However
721  * sscanf may return immediately if it sees the terminating '0' in a string, so
722  * I initialise the %n variable to the expected length.  If sscanf sets it;
723  * fine, if it doesn't, then the scan ended at the end of the string, which is
724  * fine too :) */
725 static int
726 libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
727 {
728         unsigned int    a;
729         unsigned int    b;
730         unsigned int    c;
731         unsigned int    d;
732         int             n = nob; /* XscanfX */
733
734         /* numeric IP? */
735         if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
736             n == nob &&
737             (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
738             (c & ~0xff) == 0 && (d & ~0xff) == 0) {
739                 *addr = ((a<<24)|(b<<16)|(c<<8)|d);
740                 return 1;
741         }
742         return 0;
743 }
744
745 /* Used by lnet/config.c so it can't be static */
746 int
747 cfs_ip_addr_parse(char *str, int len, struct list_head *list)
748 {
749         struct cfs_expr_list *el;
750         struct cfs_lstr src;
751         int rc;
752         int i;
753
754         src.ls_str = str;
755         src.ls_len = len;
756         i = 0;
757
758         while (src.ls_str != NULL) {
759                 struct cfs_lstr res;
760
761                 if (!cfs_gettok(&src, '.', &res)) {
762                         rc = -EINVAL;
763                         goto out;
764                 }
765
766                 rc = cfs_expr_list_parse(res.ls_str, res.ls_len, 0, 255, &el);
767                 if (rc != 0)
768                         goto out;
769
770                 list_add_tail(&el->el_link, list);
771                 i++;
772         }
773
774         if (i == 4)
775                 return 0;
776
777         rc = -EINVAL;
778 out:
779         cfs_expr_list_free_list(list);
780
781         return rc;
782 }
783
784 static int
785 libcfs_ip_addr_range_print(char *buffer, int count, struct list_head *list)
786 {
787         int i = 0, j = 0;
788         struct cfs_expr_list *el;
789
790         list_for_each_entry(el, list, el_link) {
791                 LASSERT(j++ < 4);
792                 if (i != 0)
793                         i += scnprintf(buffer + i, count - i, ".");
794                 i += cfs_expr_list_print(buffer + i, count - i, el);
795         }
796         return i;
797 }
798
799 /**
800  * Matches address (\a addr) against address set encoded in \a list.
801  *
802  * \retval 1 if \a addr matches
803  * \retval 0 otherwise
804  */
805 int
806 cfs_ip_addr_match(__u32 addr, struct list_head *list)
807 {
808         struct cfs_expr_list *el;
809         int i = 0;
810
811         list_for_each_entry_reverse(el, list, el_link) {
812                 if (!cfs_expr_list_match(addr & 0xff, el))
813                         return 0;
814                 addr >>= 8;
815                 i++;
816         }
817
818         return i == 4;
819 }
820
821 /**
822  * Print the network part of the nidrange \a nr into the specified \a buffer.
823  *
824  * \retval number of characters written
825  */
826 static void
827 libcfs_decnum_addr2str(__u32 addr, char *str, size_t size)
828 {
829         snprintf(str, size, "%u", addr);
830 }
831
832 static int
833 libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
834 {
835         int     n;
836
837         n = nob;
838         if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
839                 return 1;
840
841         n = nob;
842         if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
843                 return 1;
844
845         n = nob;
846         if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
847                 return 1;
848
849         return 0;
850 }
851
852 /**
853  * Nf_parse_addrlist method for networks using numeric addresses.
854  *
855  * Examples of such networks are gm and elan.
856  *
857  * \retval 0 if \a str parsed to numeric address
858  * \retval errno otherwise
859  */
860 static int
861 libcfs_num_parse(char *str, int len, struct list_head *list)
862 {
863         struct cfs_expr_list *el;
864         int     rc;
865
866         rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
867         if (rc == 0)
868                 list_add_tail(&el->el_link, list);
869
870         return rc;
871 }
872
873 static int
874 libcfs_num_addr_range_print(char *buffer, int count, struct list_head *list)
875 {
876         int i = 0, j = 0;
877         struct cfs_expr_list *el;
878
879         list_for_each_entry(el, list, el_link) {
880                 LASSERT(j++ < 1);
881                 i += cfs_expr_list_print(buffer + i, count - i, el);
882         }
883         return i;
884 }
885
886 /*
887  * Nf_match_addr method for networks using numeric addresses
888  *
889  * \retval 1 on match
890  * \retval 0 otherwise
891  */
892 static int
893 libcfs_num_match(__u32 addr, struct list_head *numaddr)
894 {
895         struct cfs_expr_list *el;
896
897         LASSERT(!list_empty(numaddr));
898         el = list_entry(numaddr->next, struct cfs_expr_list, el_link);
899
900         return cfs_expr_list_match(addr, el);
901 }
902
903 static struct netstrfns libcfs_netstrfns[] = {
904         { .nf_type              = LOLND,
905           .nf_name              = "lo",
906           .nf_modname           = "klolnd",
907           .nf_addr2str          = libcfs_decnum_addr2str,
908           .nf_str2addr          = libcfs_lo_str2addr,
909           .nf_parse_addrlist    = libcfs_num_parse,
910           .nf_print_addrlist    = libcfs_num_addr_range_print,
911           .nf_match_addr        = libcfs_num_match,
912           .nf_min_max           = cfs_num_min_max },
913         { .nf_type              = SOCKLND,
914           .nf_name              = "tcp",
915           .nf_modname           = "ksocklnd",
916           .nf_addr2str          = libcfs_ip_addr2str,
917           .nf_str2addr          = libcfs_ip_str2addr,
918           .nf_parse_addrlist    = cfs_ip_addr_parse,
919           .nf_print_addrlist    = libcfs_ip_addr_range_print,
920           .nf_match_addr        = cfs_ip_addr_match,
921           .nf_min_max           = cfs_ip_min_max },
922         { .nf_type              = O2IBLND,
923           .nf_name              = "o2ib",
924           .nf_modname           = "ko2iblnd",
925           .nf_addr2str          = libcfs_ip_addr2str,
926           .nf_str2addr          = libcfs_ip_str2addr,
927           .nf_parse_addrlist    = cfs_ip_addr_parse,
928           .nf_print_addrlist    = libcfs_ip_addr_range_print,
929           .nf_match_addr        = cfs_ip_addr_match,
930           .nf_min_max           = cfs_ip_min_max },
931         { .nf_type              = GNILND,
932           .nf_name              = "gni",
933           .nf_modname           = "kgnilnd",
934           .nf_addr2str          = libcfs_decnum_addr2str,
935           .nf_str2addr          = libcfs_num_str2addr,
936           .nf_parse_addrlist    = libcfs_num_parse,
937           .nf_print_addrlist    = libcfs_num_addr_range_print,
938           .nf_match_addr        = libcfs_num_match,
939           .nf_min_max           = cfs_num_min_max },
940         { .nf_type              = GNIIPLND,
941           .nf_name              = "gip",
942           .nf_modname           = "kgnilnd",
943           .nf_addr2str          = libcfs_ip_addr2str,
944           .nf_str2addr          = libcfs_ip_str2addr,
945           .nf_parse_addrlist    = cfs_ip_addr_parse,
946           .nf_print_addrlist    = libcfs_ip_addr_range_print,
947           .nf_match_addr        = cfs_ip_addr_match,
948           .nf_min_max           = cfs_ip_min_max },
949         { .nf_type              = PTL4LND,
950           .nf_name              = "ptlf",
951           .nf_modname           = "kptl4lnd",
952           .nf_addr2str          = libcfs_decnum_addr2str,
953           .nf_str2addr          = libcfs_num_str2addr,
954           .nf_parse_addrlist    = libcfs_num_parse,
955           .nf_print_addrlist    = libcfs_num_addr_range_print,
956           .nf_match_addr        = libcfs_num_match,
957           .nf_min_max           = cfs_num_min_max},
958 };
959
960 static const size_t libcfs_nnetstrfns = ARRAY_SIZE(libcfs_netstrfns);
961
962 static struct netstrfns *
963 libcfs_lnd2netstrfns(__u32 lnd)
964 {
965         int     i;
966
967         for (i = 0; i < libcfs_nnetstrfns; i++)
968                 if (lnd == libcfs_netstrfns[i].nf_type)
969                         return &libcfs_netstrfns[i];
970
971         return NULL;
972 }
973
974 static struct netstrfns *
975 libcfs_namenum2netstrfns(const char *name)
976 {
977         struct netstrfns *nf;
978         int               i;
979
980         for (i = 0; i < libcfs_nnetstrfns; i++) {
981                 nf = &libcfs_netstrfns[i];
982                 if (!strncmp(name, nf->nf_name, strlen(nf->nf_name)))
983                         return nf;
984         }
985         return NULL;
986 }
987
988 static struct netstrfns *
989 libcfs_name2netstrfns(const char *name)
990 {
991         int    i;
992
993         for (i = 0; i < libcfs_nnetstrfns; i++)
994                 if (!strcmp(libcfs_netstrfns[i].nf_name, name))
995                         return &libcfs_netstrfns[i];
996
997         return NULL;
998 }
999
1000 int
1001 libcfs_isknown_lnd(__u32 lnd)
1002 {
1003         return libcfs_lnd2netstrfns(lnd) != NULL;
1004 }
1005 EXPORT_SYMBOL(libcfs_isknown_lnd);
1006
1007 char *
1008 libcfs_lnd2modname(__u32 lnd)
1009 {
1010         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
1011
1012         return (nf == NULL) ? NULL : nf->nf_modname;
1013 }
1014 EXPORT_SYMBOL(libcfs_lnd2modname);
1015
1016 int
1017 libcfs_str2lnd(const char *str)
1018 {
1019         struct netstrfns *nf = libcfs_name2netstrfns(str);
1020
1021         if (nf != NULL)
1022                 return nf->nf_type;
1023
1024         return -ENXIO;
1025 }
1026 EXPORT_SYMBOL(libcfs_str2lnd);
1027
1028 char *
1029 libcfs_lnd2str_r(__u32 lnd, char *buf, size_t buf_size)
1030 {
1031         struct netstrfns *nf;
1032
1033         nf = libcfs_lnd2netstrfns(lnd);
1034         if (nf == NULL)
1035                 snprintf(buf, buf_size, "?%u?", lnd);
1036         else
1037                 snprintf(buf, buf_size, "%s", nf->nf_name);
1038
1039         return buf;
1040 }
1041 EXPORT_SYMBOL(libcfs_lnd2str_r);
1042
1043 char *
1044 libcfs_net2str_r(__u32 net, char *buf, size_t buf_size)
1045 {
1046         __u32             nnum = LNET_NETNUM(net);
1047         __u32             lnd  = LNET_NETTYP(net);
1048         struct netstrfns *nf;
1049
1050         nf = libcfs_lnd2netstrfns(lnd);
1051         if (nf == NULL)
1052                 snprintf(buf, buf_size, "<%u:%u>", lnd, nnum);
1053         else if (nnum == 0)
1054                 snprintf(buf, buf_size, "%s", nf->nf_name);
1055         else
1056                 snprintf(buf, buf_size, "%s%u", nf->nf_name, nnum);
1057
1058         return buf;
1059 }
1060 EXPORT_SYMBOL(libcfs_net2str_r);
1061
1062 char *
1063 libcfs_nid2str_r(lnet_nid_t nid, char *buf, size_t buf_size)
1064 {
1065         __u32             addr = LNET_NIDADDR(nid);
1066         __u32             net  = LNET_NIDNET(nid);
1067         __u32             nnum = LNET_NETNUM(net);
1068         __u32             lnd  = LNET_NETTYP(net);
1069         struct netstrfns *nf;
1070
1071         if (nid == LNET_NID_ANY) {
1072                 strncpy(buf, "<?>", buf_size);
1073                 buf[buf_size - 1] = '\0';
1074                 return buf;
1075         }
1076
1077         nf = libcfs_lnd2netstrfns(lnd);
1078         if (nf == NULL) {
1079                 snprintf(buf, buf_size, "%x@<%u:%u>", addr, lnd, nnum);
1080         } else {
1081                 size_t addr_len;
1082
1083                 nf->nf_addr2str(addr, buf, buf_size);
1084                 addr_len = strlen(buf);
1085                 if (nnum == 0)
1086                         snprintf(buf + addr_len, buf_size - addr_len, "@%s",
1087                                  nf->nf_name);
1088                 else
1089                         snprintf(buf + addr_len, buf_size - addr_len, "@%s%u",
1090                                  nf->nf_name, nnum);
1091         }
1092
1093         return buf;
1094 }
1095 EXPORT_SYMBOL(libcfs_nid2str_r);
1096
1097 static struct netstrfns *
1098 libcfs_str2net_internal(const char *str, __u32 *net)
1099 {
1100         struct netstrfns *nf = NULL;
1101         int               nob;
1102         unsigned int      netnum;
1103         int               i;
1104
1105         for (i = 0; i < libcfs_nnetstrfns; i++) {
1106                 nf = &libcfs_netstrfns[i];
1107                 if (!strncmp(str, nf->nf_name, strlen(nf->nf_name)))
1108                         break;
1109         }
1110
1111         if (i == libcfs_nnetstrfns)
1112                 return NULL;
1113
1114         nob = strlen(nf->nf_name);
1115
1116         if (strlen(str) == (unsigned int)nob) {
1117                 netnum = 0;
1118         } else {
1119                 if (nf->nf_type == LOLND) /* net number not allowed */
1120                         return NULL;
1121
1122                 str += nob;
1123                 i = strlen(str);
1124                 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
1125                     i != (int)strlen(str))
1126                         return NULL;
1127         }
1128
1129         *net = LNET_MKNET(nf->nf_type, netnum);
1130         return nf;
1131 }
1132
1133 __u32
1134 libcfs_str2net(const char *str)
1135 {
1136         __u32  net;
1137
1138         if (libcfs_str2net_internal(str, &net) != NULL)
1139                 return net;
1140
1141         return LNET_NIDNET(LNET_NID_ANY);
1142 }
1143 EXPORT_SYMBOL(libcfs_str2net);
1144
1145 lnet_nid_t
1146 libcfs_str2nid(const char *str)
1147 {
1148         const char       *sep = strchr(str, '@');
1149         struct netstrfns *nf;
1150         __u32             net;
1151         __u32             addr;
1152
1153         if (sep != NULL) {
1154                 nf = libcfs_str2net_internal(sep + 1, &net);
1155                 if (nf == NULL)
1156                         return LNET_NID_ANY;
1157         } else {
1158                 sep = str + strlen(str);
1159                 net = LNET_MKNET(SOCKLND, 0);
1160                 nf = libcfs_lnd2netstrfns(SOCKLND);
1161                 LASSERT(nf != NULL);
1162         }
1163
1164         if (!nf->nf_str2addr(str, (int)(sep - str), &addr))
1165                 return LNET_NID_ANY;
1166
1167         return LNET_MKNID(net, addr);
1168 }
1169 EXPORT_SYMBOL(libcfs_str2nid);
1170
1171 char *
1172 libcfs_id2str(struct lnet_process_id id)
1173 {
1174         char *str = libcfs_next_nidstring();
1175
1176         if (id.pid == LNET_PID_ANY) {
1177                 snprintf(str, LNET_NIDSTR_SIZE,
1178                          "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
1179                 return str;
1180         }
1181
1182         snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
1183                  ((id.pid & LNET_PID_USERFLAG) != 0) ? "U" : "",
1184                  (id.pid & ~LNET_PID_USERFLAG), libcfs_nid2str(id.nid));
1185         return str;
1186 }
1187 EXPORT_SYMBOL(libcfs_id2str);
1188
1189 int
1190 libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
1191 {
1192         if (!strcmp(str, "*")) {
1193                 *nidp = LNET_NID_ANY;
1194                 return 1;
1195         }
1196
1197         *nidp = libcfs_str2nid(str);
1198         return *nidp != LNET_NID_ANY;
1199 }
1200 EXPORT_SYMBOL(libcfs_str2anynid);