Whamcloud - gitweb
LU-6142 lnet: SPDX for lnet/lnet/
[fs/lustre-release.git] / lnet / lnet / nidstrings.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 /* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
4  * Use is subject to license terms.
5  *
6  * Copyright (c) 2011, 2015, Intel Corporation.
7  */
8
9 /* This file is part of Lustre, http://www.lustre.org/
10  *
11  * Author: Phil Schwan <phil@clusterfs.com>
12  */
13
14 #define DEBUG_SUBSYSTEM S_LNET
15
16 #include <linux/sunrpc/addr.h>
17 #include <libcfs/libcfs.h>
18 #include <uapi/linux/lnet/nidstr.h>
19 #include <lnet/lib-types.h>
20
21 /* max value for numeric network address */
22 #define MAX_NUMERIC_VALUE 0xffffffff
23
24 #define IPSTRING_LENGTH 16
25
26 /* CAVEAT VENDITOR! Keep the canonical string representation of nets/nids
27  * consistent in all conversion functions.  Some code fragments are copied
28  * around for the sake of clarity...
29  */
30
31 /* CAVEAT EMPTOR! Racey temporary buffer allocation!
32  * Choose the number of nidstrings to support the MAXIMUM expected number of
33  * concurrent users.  If there are more, the returned string will be volatile.
34  * NB this number must allow for a process to be descheduled for a timeslice
35  * between getting its string and using it.
36  */
37
38 static char      libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE];
39 static int       libcfs_nidstring_idx;
40
41 static DEFINE_SPINLOCK(libcfs_nidstring_lock);
42
43 static struct netstrfns *libcfs_namenum2netstrfns(const char *name);
44
45 char *
46 libcfs_next_nidstring(void)
47 {
48         char          *str;
49         unsigned long  flags;
50
51         spin_lock_irqsave(&libcfs_nidstring_lock, flags);
52
53         str = libcfs_nidstrings[libcfs_nidstring_idx++];
54         if (libcfs_nidstring_idx == ARRAY_SIZE(libcfs_nidstrings))
55                 libcfs_nidstring_idx = 0;
56
57         spin_unlock_irqrestore(&libcfs_nidstring_lock, flags);
58         return str;
59 }
60 EXPORT_SYMBOL(libcfs_next_nidstring);
61
62 /**
63  * Nid range list syntax.
64  * \verbatim
65  *
66  * <nidlist>         :== <nidrange> [ ' ' <nidrange> ]
67  * <nidrange>        :== <addrrange> '@' <net>
68  * <addrrange>       :== '*' |
69  *                       <ipaddr_range> |
70  *                       <cfs_expr_list>
71  * <ipaddr_range>    :== <cfs_expr_list>.<cfs_expr_list>.<cfs_expr_list>.
72  *                       <cfs_expr_list>
73  * <cfs_expr_list>   :== <number> |
74  *                       <expr_list>
75  * <expr_list>       :== '[' <range_expr> [ ',' <range_expr>] ']'
76  * <range_expr>      :== <number> |
77  *                       <number> '-' <number> |
78  *                       <number> '-' <number> '/' <number>
79  * <net>             :== <netname> | <netname><number>
80  * <netname>         :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" |
81  *                       "vib" | "ra" | "elan" | "mx" | "ptl"
82  * \endverbatim
83  */
84
85 /**
86  * Structure to represent \<nidrange\> token of the syntax.
87  *
88  * One of this is created for each \<net\> parsed.
89  */
90 struct nidrange {
91         /**
92          * Link to list of this structures which is built on nid range
93          * list parsing.
94          */
95         struct list_head nr_link;
96         /**
97          * List head for addrrange::ar_link.
98          */
99         struct list_head nr_addrranges;
100         /**
101          * Flag indicating that *@<net> is found.
102          */
103         int nr_all;
104         /**
105          * Pointer to corresponding element of libcfs_netstrfns.
106          */
107         struct netstrfns *nr_netstrfns;
108         /**
109          * Number of network. E.g. 5 if \<net\> is "elan5".
110          */
111         int nr_netnum;
112 };
113
114 /**
115  * Structure to represent \<addrrange\> token of the syntax.
116  */
117 struct addrrange {
118         /**
119          * Link to nidrange::nr_addrranges.
120          */
121         struct list_head ar_link;
122         /**
123          * List head for cfs_expr_list::el_list.
124          */
125         struct list_head ar_numaddr_ranges;
126 };
127
128 /**
129  * Parses \<addrrange\> token on the syntax.
130  *
131  * Allocates struct addrrange and links to \a nidrange via
132  * (nidrange::nr_addrranges)
133  *
134  * \retval 0 if \a src parses to '*' | \<ipaddr_range\> | \<cfs_expr_list\>
135  * \retval -errno otherwise
136  */
137 static int
138 parse_addrange(char *str, struct nidrange *nidrange)
139 {
140         struct addrrange *addrrange;
141
142         if (strcmp(str, "*") == 0) {
143                 nidrange->nr_all = 1;
144                 return 0;
145         }
146
147         CFS_ALLOC_PTR(addrrange);
148         if (addrrange == NULL)
149                 return -ENOMEM;
150         list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges);
151         INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges);
152
153         return nidrange->nr_netstrfns->nf_parse_addrlist(str, strlen(str),
154                                                 &addrrange->ar_numaddr_ranges);
155 }
156
157 /**
158  * Finds or creates struct nidrange.
159  *
160  * Checks if \a src is a valid network name, looks for corresponding
161  * nidrange on the ist of nidranges (\a nidlist), creates new struct
162  * nidrange if it is not found.
163  *
164  * \retval pointer to struct nidrange matching network specified via \a src
165  * \retval NULL if \a src does not match any network
166  */
167 static struct nidrange *
168 add_nidrange(char *str, struct list_head *nidlist)
169 {
170         struct netstrfns *nf;
171         struct nidrange *nr;
172         char *end;
173         unsigned int netnum;
174
175         nf = libcfs_namenum2netstrfns(str);
176         if (nf == NULL)
177                 return NULL;
178         end = str + strlen(nf->nf_name);
179         if (!*end) {
180                 /* network name only, e.g. "elan" or "tcp" */
181                 netnum = 0;
182         } else {
183                 /* e.g. "elan25" or "tcp23", refuse to parse if
184                  * network name is not appended with decimal or
185                  * hexadecimal number
186                  */
187                 if (kstrtouint(end, 0, &netnum) != 0)
188                         return NULL;
189         }
190
191         list_for_each_entry(nr, nidlist, nr_link) {
192                 if (nr->nr_netstrfns != nf)
193                         continue;
194                 if (nr->nr_netnum != netnum)
195                         continue;
196                 return nr;
197         }
198
199         CFS_ALLOC_PTR(nr);
200         if (nr == NULL)
201                 return NULL;
202         list_add_tail(&nr->nr_link, nidlist);
203         INIT_LIST_HEAD(&nr->nr_addrranges);
204         nr->nr_netstrfns = nf;
205         nr->nr_all = 0;
206         nr->nr_netnum = netnum;
207
208         return nr;
209 }
210
211 /**
212  * Parses \<nidrange\> token of the syntax.
213  *
214  * \retval 0 if \a src parses to \<addrrange\> '@' \<net\>
215  * \retval -EINVAL otherwise
216  */
217 static int
218 parse_nidrange(char *str, struct list_head *nidlist)
219 {
220         char *addrrange;
221         char *net;
222         struct nidrange *nr;
223
224         addrrange = strim(strsep(&str, "@"));
225         if (!str)
226                 goto failed;
227
228         net = strim(str);
229         if (strchr(net, '@') != NULL || !*net)
230                 goto failed;
231
232         nr = add_nidrange(net, nidlist);
233         if (nr == NULL)
234                 goto failed;
235
236         if (parse_addrange(addrrange, nr) != 0)
237                 goto failed;
238
239         return 0;
240 failed:
241         return -EINVAL;
242 }
243
244 /**
245  * Frees addrrange structures of \a list.
246  *
247  * For each struct addrrange structure found on \a list it frees
248  * cfs_expr_list list attached to it and frees the addrrange itself.
249  *
250  * \retval none
251  */
252 static void
253 free_addrranges(struct list_head *list)
254 {
255         struct addrrange *ar;
256
257         while ((ar = list_first_entry_or_null(list,
258                                               struct addrrange,
259                                               ar_link)) != NULL) {
260                 cfs_expr_list_free_list(&ar->ar_numaddr_ranges);
261                 list_del(&ar->ar_link);
262                 CFS_FREE_PTR(ar);
263         }
264 }
265
266 /**
267  * Frees nidrange strutures of \a list.
268  *
269  * For each struct nidrange structure found on \a list it frees
270  * addrrange list attached to it and frees the nidrange itself.
271  *
272  * \retval none
273  */
274 void
275 cfs_free_nidlist(struct list_head *list)
276 {
277         struct list_head *pos, *next;
278         struct nidrange *nr;
279
280         list_for_each_safe(pos, next, list) {
281                 nr = list_entry(pos, struct nidrange, nr_link);
282                 free_addrranges(&nr->nr_addrranges);
283                 list_del(pos);
284                 CFS_FREE_PTR(nr);
285         }
286 }
287 EXPORT_SYMBOL(cfs_free_nidlist);
288
289 /**
290  * Parses nid range list.
291  *
292  * Parses with rigorous syntax and overflow checking \a str into
293  * \<nidrange\> [ ' ' \<nidrange\> ], compiles \a str into set of
294  * structures and links that structure to \a nidlist. The resulting
295  * list can be used to match a NID againts set of NIDS defined by \a
296  * str.
297  * \see cfs_match_nid
298  *
299  * \retval 0 on success
300  * \retval -errno otherwise (-ENOMEM or -EINVAL)
301  */
302 int
303 cfs_parse_nidlist(char *orig, struct list_head *nidlist)
304 {
305         int rc = 0;
306         char *str;
307
308         orig = kstrdup(orig, GFP_KERNEL);
309         if (!orig)
310                 return -ENOMEM;
311
312         INIT_LIST_HEAD(nidlist);
313         str = orig;
314         while (rc == 0 && str) {
315                 char *tok = strsep(&str, " ");
316
317                 if (*tok)
318                         rc = parse_nidrange(tok, nidlist);
319         }
320         kfree(orig);
321         if (rc)
322                 cfs_free_nidlist(nidlist);
323         else if (list_empty(nidlist))
324                 rc = -EINVAL;
325         return rc;
326 }
327 EXPORT_SYMBOL(cfs_parse_nidlist);
328
329 /**
330  * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
331  *
332  * \see cfs_parse_nidlist()
333  *
334  * \retval 1 on match
335  * \retval 0  otherwises
336  */
337 int cfs_match_nid(struct lnet_nid *nid, struct list_head *nidlist)
338 {
339         struct nidrange *nr;
340         struct addrrange *ar;
341
342         if (!nid_is_nid4(nid))
343                 return 0;
344         list_for_each_entry(nr, nidlist, nr_link) {
345                 if (nr->nr_netstrfns->nf_type != nid->nid_type)
346                         continue;
347                 if (nr->nr_netnum != be16_to_cpu(nid->nid_num))
348                         continue;
349                 if (nr->nr_all)
350                         return 1;
351                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
352                         if (nr->nr_netstrfns->nf_match_addr(
353                                     be32_to_cpu(nid->nid_addr[0]),
354                                     &ar->ar_numaddr_ranges))
355                                 return 1;
356         }
357         return 0;
358 }
359 EXPORT_SYMBOL(cfs_match_nid);
360
361 /**
362  * Print the network part of the nidrange \a nr into the specified \a buffer.
363  *
364  * \retval number of characters written
365  */
366 static int
367 cfs_print_network(char *buffer, int count, struct nidrange *nr)
368 {
369         struct netstrfns *nf = nr->nr_netstrfns;
370
371         if (nr->nr_netnum == 0)
372                 return scnprintf(buffer, count, "@%s", nf->nf_name);
373         else
374                 return scnprintf(buffer, count, "@%s%u",
375                                     nf->nf_name, nr->nr_netnum);
376 }
377
378 /**
379  * Print a list of addrrange (\a addrranges) into the specified \a buffer.
380  * At max \a count characters can be printed into \a buffer.
381  *
382  * \retval number of characters written
383  */
384 static int
385 cfs_print_addrranges(char *buffer, int count, struct list_head *addrranges,
386                      struct nidrange *nr)
387 {
388         int i = 0;
389         struct addrrange *ar;
390         struct netstrfns *nf = nr->nr_netstrfns;
391
392         list_for_each_entry(ar, addrranges, ar_link) {
393                 if (i != 0)
394                         i += scnprintf(buffer + i, count - i, " ");
395                 i += nf->nf_print_addrlist(buffer + i, count - i,
396                                            &ar->ar_numaddr_ranges);
397                 i += cfs_print_network(buffer + i, count - i, nr);
398         }
399         return i;
400 }
401
402 /**
403  * Print a list of nidranges (\a nidlist) into the specified \a buffer.
404  * At max \a count characters can be printed into \a buffer.
405  * Nidranges are separated by a space character.
406  *
407  * \retval number of characters written
408  */
409 int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist)
410 {
411         int i = 0;
412         struct nidrange *nr;
413
414         if (count <= 0)
415                 return 0;
416
417         list_for_each_entry(nr, nidlist, nr_link) {
418                 if (i != 0)
419                         i += scnprintf(buffer + i, count - i, " ");
420
421                 if (nr->nr_all != 0) {
422                         LASSERT(list_empty(&nr->nr_addrranges));
423                         i += scnprintf(buffer + i, count - i, "*");
424                         i += cfs_print_network(buffer + i, count - i, nr);
425                 } else {
426                         i += cfs_print_addrranges(buffer + i, count - i,
427                                                   &nr->nr_addrranges, nr);
428                 }
429         }
430         return i;
431 }
432 EXPORT_SYMBOL(cfs_print_nidlist);
433
434 static int
435 libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
436 {
437         *addr = 0;
438         return 1;
439 }
440
441 static void
442 libcfs_ip_addr2str(__u32 addr, char *str, size_t size)
443 {
444         snprintf(str, size, "%u.%u.%u.%u",
445                  (addr >> 24) & 0xff, (addr >> 16) & 0xff,
446                  (addr >> 8) & 0xff, addr & 0xff);
447 }
448
449 static void
450 libcfs_ip_addr2str_size(const __be32 *addr, size_t asize,
451                         char *str, size_t size)
452 {
453         struct sockaddr_storage sa = {};
454
455         switch (asize) {
456         case 4:
457                 sa.ss_family = AF_INET;
458                 memcpy(&((struct sockaddr_in *)(&sa))->sin_addr.s_addr,
459                        addr, asize);
460                 break;
461         case 16:
462                 sa.ss_family = AF_INET6;
463                 memcpy(&((struct sockaddr_in6 *)(&sa))->sin6_addr.s6_addr,
464                        addr, asize);
465                 break;
466         default:
467                 return;
468         }
469
470         rpc_ntop((struct sockaddr *)&sa, str, size);
471 }
472
473 /* CAVEAT EMPTOR XscanfX
474  * I use "%n" at the end of a sscanf format to detect trailing junk.  However
475  * sscanf may return immediately if it sees the terminating '0' in a string, so
476  * I initialise the %n variable to the expected length.  If sscanf sets it;
477  * fine, if it doesn't, then the scan ended at the end of the string, which is
478  * fine too :) */
479 static int
480 libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
481 {
482         unsigned int    a;
483         unsigned int    b;
484         unsigned int    c;
485         unsigned int    d;
486         int             n = nob; /* XscanfX */
487
488         /* numeric IP? */
489         if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
490             n == nob &&
491             (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
492             (c & ~0xff) == 0 && (d & ~0xff) == 0) {
493                 *addr = ((a<<24)|(b<<16)|(c<<8)|d);
494                 return 1;
495         }
496         return 0;
497 }
498
499 static int
500 libcfs_ip_str2addr_size(const char *str, int nob,
501                         __be32 *addr, size_t *alen)
502 {
503         struct sockaddr_storage sa;
504
505         /* Note: 'net' arg to rpc_pton is only needed for link-local
506          * addresses.  Such addresses would not work with LNet routing,
507          * so we can assume they aren't used.  So it doesn't matter
508          * which net namespace is passed.
509          */
510         if (rpc_pton(&init_net, str, nob,
511                      (struct sockaddr *)&sa, sizeof(sa)) == 0)
512                 return 0;
513         if (sa.ss_family == AF_INET6) {
514                 memcpy(addr,
515                        &((struct sockaddr_in6 *)(&sa))->sin6_addr.s6_addr,
516                        16);
517                 *alen = 16;
518                 return 1;
519         }
520         if (sa.ss_family == AF_INET) {
521                 memcpy(addr,
522                        &((struct sockaddr_in *)(&sa))->sin_addr.s_addr,
523                        4);
524                 *alen = 4;
525                 return 1;
526         }
527         return 0;
528 }
529
530
531 /* Used by lnet/config.c so it can't be static */
532 int
533 cfs_ip_addr_parse(char *str, int len_ignored, struct list_head *list)
534 {
535         struct cfs_expr_list *el;
536         int rc = 0;
537         int i = 0;
538
539         str = strim(str);
540         while (rc == 0 && str) {
541                 char *res;
542
543                 res = strsep(&str, ".");
544                 res = strim(res);
545                 if (!*res) {
546                         rc = -EINVAL;
547                 } else if ((rc = cfs_expr_list_parse(res, strlen(res),
548                                                    0, 255, &el)) == 0) {
549                         list_add_tail(&el->el_link, list);
550                         i++;
551                 }
552         }
553
554         if (rc == 0 && i == 4)
555                 return 0;
556         cfs_expr_list_free_list(list);
557
558         return rc ?: -EINVAL;
559 }
560
561 /**
562  * Print the range expression \a re into specified \a buffer.
563  * If \a bracketed is true, expression does not need additional
564  * brackets.
565  *
566  * \retval number of characters written
567  */
568 static int
569 cfs_range_expr_print(char *buffer, int count, struct cfs_range_expr *expr,
570                      bool bracketed)
571 {
572         int i;
573         char s[] = "[";
574         char e[] = "]";
575
576         if (bracketed)
577                 s[0] = e[0] = '\0';
578
579         if (expr->re_lo == expr->re_hi)
580                 i = scnprintf(buffer, count, "%u", expr->re_lo);
581         else if (expr->re_stride == 1)
582                 i = scnprintf(buffer, count, "%s%u-%u%s",
583                               s, expr->re_lo, expr->re_hi, e);
584         else
585                 i = scnprintf(buffer, count, "%s%u-%u/%u%s",
586                               s, expr->re_lo, expr->re_hi,
587                               expr->re_stride, e);
588         return i;
589 }
590
591 /**
592  * Print a list of range expressions (\a expr_list) into specified \a buffer.
593  * If the list contains several expressions, separate them with comma
594  * and surround the list with brackets.
595  *
596  * \retval number of characters written
597  */
598 static int
599 cfs_expr_list_print(char *buffer, int count, struct cfs_expr_list *expr_list)
600 {
601         struct cfs_range_expr *expr;
602         int i = 0, j = 0;
603         int numexprs = 0;
604
605         if (count <= 0)
606                 return 0;
607
608         list_for_each_entry(expr, &expr_list->el_exprs, re_link)
609                 numexprs++;
610
611         if (numexprs > 1)
612                 i += scnprintf(buffer + i, count - i, "[");
613
614         list_for_each_entry(expr, &expr_list->el_exprs, re_link) {
615                 if (j++ != 0)
616                         i += scnprintf(buffer + i, count - i, ",");
617                 i += cfs_range_expr_print(buffer + i, count - i, expr,
618                                           numexprs > 1);
619         }
620
621         if (numexprs > 1)
622                 i += scnprintf(buffer + i, count - i, "]");
623
624         return i;
625 }
626
627 static int
628 libcfs_ip_addr_range_print(char *buffer, int count, struct list_head *list)
629 {
630         int i = 0, j = 0;
631         struct cfs_expr_list *el;
632
633         list_for_each_entry(el, list, el_link) {
634                 LASSERT(j++ < 4);
635                 if (i != 0)
636                         i += scnprintf(buffer + i, count - i, ".");
637                 i += cfs_expr_list_print(buffer + i, count - i, el);
638         }
639         return i;
640 }
641
642 /**
643  * Matches address (\a addr) against address set encoded in \a list.
644  *
645  * \retval 1 if \a addr matches
646  * \retval 0 otherwise
647  */
648 int
649 cfs_ip_addr_match(__u32 addr, struct list_head *list)
650 {
651         struct cfs_expr_list *el;
652         int i = 0;
653
654         list_for_each_entry_reverse(el, list, el_link) {
655                 if (!cfs_expr_list_match(addr & 0xff, el))
656                         return 0;
657                 addr >>= 8;
658                 i++;
659         }
660
661         return i == 4;
662 }
663
664 /**
665  * Print the network part of the nidrange \a nr into the specified \a buffer.
666  *
667  * \retval number of characters written
668  */
669 static void
670 libcfs_decnum_addr2str(__u32 addr, char *str, size_t size)
671 {
672         snprintf(str, size, "%u", addr);
673 }
674
675 static int
676 libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
677 {
678         int     n;
679
680         n = nob;
681         if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
682                 return 1;
683
684         n = nob;
685         if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
686                 return 1;
687
688         n = nob;
689         if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
690                 return 1;
691
692         return 0;
693 }
694
695 /**
696  * Nf_parse_addrlist method for networks using numeric addresses.
697  *
698  * Examples of such networks are gm and elan.
699  *
700  * \retval 0 if \a str parsed to numeric address
701  * \retval errno otherwise
702  */
703 int
704 libcfs_num_parse(char *str, int len, struct list_head *list)
705 {
706         struct cfs_expr_list *el;
707         int     rc;
708
709         rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
710         if (rc == 0)
711                 list_add_tail(&el->el_link, list);
712
713         return rc;
714 }
715
716 static int
717 libcfs_num_addr_range_print(char *buffer, int count, struct list_head *list)
718 {
719         int i = 0, j = 0;
720         struct cfs_expr_list *el;
721
722         list_for_each_entry(el, list, el_link) {
723                 LASSERT(j++ < 1);
724                 i += cfs_expr_list_print(buffer + i, count - i, el);
725         }
726         return i;
727 }
728
729 /*
730  * Nf_match_addr method for networks using numeric addresses
731  *
732  * \retval 1 on match
733  * \retval 0 otherwise
734  */
735 static int
736 libcfs_num_match(__u32 addr, struct list_head *numaddr)
737 {
738         struct cfs_expr_list *el;
739
740         LASSERT(!list_empty(numaddr));
741         el = list_first_entry(numaddr, struct cfs_expr_list, el_link);
742
743         return cfs_expr_list_match(addr, el);
744 }
745
746 static struct netstrfns libcfs_netstrfns[] = {
747         { .nf_type              = LOLND,
748           .nf_name              = "lo",
749           .nf_modname           = "klolnd",
750           .nf_addr2str          = libcfs_decnum_addr2str,
751           .nf_str2addr          = libcfs_lo_str2addr,
752           .nf_parse_addrlist    = libcfs_num_parse,
753           .nf_print_addrlist    = libcfs_num_addr_range_print,
754           .nf_match_addr        = libcfs_num_match
755         },
756         { .nf_type              = SOCKLND,
757           .nf_name              = "tcp",
758           .nf_modname           = "ksocklnd",
759           .nf_addr2str          = libcfs_ip_addr2str,
760           .nf_addr2str_size     = libcfs_ip_addr2str_size,
761           .nf_str2addr          = libcfs_ip_str2addr,
762           .nf_str2addr_size     = libcfs_ip_str2addr_size,
763           .nf_parse_addrlist    = cfs_ip_addr_parse,
764           .nf_print_addrlist    = libcfs_ip_addr_range_print,
765           .nf_match_addr        = cfs_ip_addr_match
766         },
767         { .nf_type              = O2IBLND,
768           .nf_name              = "o2ib",
769           .nf_modname           = "ko2iblnd",
770           .nf_addr2str          = libcfs_ip_addr2str,
771           .nf_str2addr          = libcfs_ip_str2addr,
772           .nf_parse_addrlist    = cfs_ip_addr_parse,
773           .nf_print_addrlist    = libcfs_ip_addr_range_print,
774           .nf_match_addr        = cfs_ip_addr_match
775         },
776         { .nf_type              = GNILND,
777           .nf_name              = "gni",
778           .nf_modname           = "kgnilnd",
779           .nf_addr2str          = libcfs_decnum_addr2str,
780           .nf_str2addr          = libcfs_num_str2addr,
781           .nf_parse_addrlist    = libcfs_num_parse,
782           .nf_print_addrlist    = libcfs_num_addr_range_print,
783           .nf_match_addr        = libcfs_num_match
784         },
785         { .nf_type              = GNIIPLND,
786           .nf_name              = "gip",
787           .nf_modname           = "kgnilnd",
788           .nf_addr2str          = libcfs_ip_addr2str,
789           .nf_str2addr          = libcfs_ip_str2addr,
790           .nf_parse_addrlist    = cfs_ip_addr_parse,
791           .nf_print_addrlist    = libcfs_ip_addr_range_print,
792           .nf_match_addr        = cfs_ip_addr_match
793         },
794         { .nf_type              = PTL4LND,
795           .nf_name              = "ptlf",
796           .nf_modname           = "kptl4lnd",
797           .nf_addr2str          = libcfs_decnum_addr2str,
798           .nf_str2addr          = libcfs_num_str2addr,
799           .nf_parse_addrlist    = libcfs_num_parse,
800           .nf_print_addrlist    = libcfs_num_addr_range_print,
801           .nf_match_addr        = libcfs_num_match
802         },
803         {
804           .nf_type              = KFILND,
805           .nf_name              = "kfi",
806           .nf_modname           = "kkfilnd",
807           .nf_addr2str          = libcfs_decnum_addr2str,
808           .nf_str2addr          = libcfs_num_str2addr,
809           .nf_parse_addrlist    = libcfs_num_parse,
810           .nf_print_addrlist    = libcfs_num_addr_range_print,
811           .nf_match_addr        = libcfs_num_match
812         },
813 };
814
815 static const size_t libcfs_nnetstrfns = ARRAY_SIZE(libcfs_netstrfns);
816
817 static struct netstrfns *
818 type2net_info(__u32 net_type)
819 {
820         int i;
821
822         for (i = 0; i < libcfs_nnetstrfns; i++) {
823                 if (libcfs_netstrfns[i].nf_type == net_type)
824                         return &libcfs_netstrfns[i];
825         }
826
827         return NULL;
828 }
829
830 int
831 cfs_match_net(__u32 net_id, __u32 net_type, struct list_head *net_num_list)
832 {
833         __u32 net_num;
834
835         if (!net_num_list)
836                 return 0;
837
838         if (net_type != LNET_NETTYP(net_id))
839                 return 0;
840
841         net_num = LNET_NETNUM(net_id);
842
843         /* if there is a net number but the list passed in is empty, then
844          * there is no match.
845          */
846         if (!net_num && list_empty(net_num_list))
847                 return 1;
848         else if (list_empty(net_num_list))
849                 return 0;
850
851         if (!libcfs_num_match(net_num, net_num_list))
852                 return 0;
853
854         return 1;
855 }
856
857 int
858 cfs_match_nid_net(struct lnet_nid *nid, __u32 net_type,
859                    struct list_head *net_num_list,
860                    struct list_head *addr)
861 {
862         __u32 address;
863         struct netstrfns *nf;
864
865         if (!addr || list_empty(addr) || !net_num_list)
866                 return 0;
867
868         nf = type2net_info(LNET_NETTYP(LNET_NID_NET(nid)));
869         if (!nf)
870                 return 0;
871
872         /* FIXME handle long-addr nid */
873         address = LNET_NIDADDR(lnet_nid_to_nid4(nid));
874
875         /* if either the address or net number don't match then no match */
876         if (!nf->nf_match_addr(address, addr) ||
877             !cfs_match_net(LNET_NID_NET(nid), net_type, net_num_list))
878                 return 0;
879
880         return 1;
881 }
882 EXPORT_SYMBOL(cfs_match_nid_net);
883
884 static struct netstrfns *
885 libcfs_lnd2netstrfns(__u32 lnd)
886 {
887         int     i;
888
889         for (i = 0; i < libcfs_nnetstrfns; i++)
890                 if (lnd == libcfs_netstrfns[i].nf_type)
891                         return &libcfs_netstrfns[i];
892
893         return NULL;
894 }
895
896 static struct netstrfns *
897 libcfs_namenum2netstrfns(const char *name)
898 {
899         struct netstrfns *nf;
900         int               i;
901
902         for (i = 0; i < libcfs_nnetstrfns; i++) {
903                 nf = &libcfs_netstrfns[i];
904                 if (!strncmp(name, nf->nf_name, strlen(nf->nf_name)))
905                         return nf;
906         }
907         return NULL;
908 }
909
910 static struct netstrfns *
911 libcfs_name2netstrfns(const char *name)
912 {
913         int    i;
914
915         for (i = 0; i < libcfs_nnetstrfns; i++)
916                 if (!strcmp(libcfs_netstrfns[i].nf_name, name))
917                         return &libcfs_netstrfns[i];
918
919         return NULL;
920 }
921
922 int
923 libcfs_isknown_lnd(__u32 lnd)
924 {
925         return libcfs_lnd2netstrfns(lnd) != NULL;
926 }
927 EXPORT_SYMBOL(libcfs_isknown_lnd);
928
929 char *
930 libcfs_lnd2modname(__u32 lnd)
931 {
932         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
933
934         return (nf == NULL) ? NULL : nf->nf_modname;
935 }
936 EXPORT_SYMBOL(libcfs_lnd2modname);
937
938 int
939 libcfs_str2lnd(const char *str)
940 {
941         struct netstrfns *nf = libcfs_name2netstrfns(str);
942
943         if (nf != NULL)
944                 return nf->nf_type;
945
946         return -ENXIO;
947 }
948 EXPORT_SYMBOL(libcfs_str2lnd);
949
950 char *
951 libcfs_lnd2str_r(__u32 lnd, char *buf, size_t buf_size)
952 {
953         struct netstrfns *nf;
954
955         nf = libcfs_lnd2netstrfns(lnd);
956         if (nf == NULL)
957                 snprintf(buf, buf_size, "?%u?", lnd);
958         else
959                 snprintf(buf, buf_size, "%s", nf->nf_name);
960
961         return buf;
962 }
963 EXPORT_SYMBOL(libcfs_lnd2str_r);
964
965 char *
966 libcfs_net2str_r(__u32 net, char *buf, size_t buf_size)
967 {
968         __u32             nnum = LNET_NETNUM(net);
969         __u32             lnd  = LNET_NETTYP(net);
970         struct netstrfns *nf;
971
972         nf = libcfs_lnd2netstrfns(lnd);
973         if (nf == NULL)
974                 snprintf(buf, buf_size, "<%u:%u>", lnd, nnum);
975         else if (nnum == 0)
976                 snprintf(buf, buf_size, "%s", nf->nf_name);
977         else
978                 snprintf(buf, buf_size, "%s%u", nf->nf_name, nnum);
979
980         return buf;
981 }
982 EXPORT_SYMBOL(libcfs_net2str_r);
983
984 char *
985 libcfs_nid2str_r(lnet_nid_t nid, char *buf, size_t buf_size)
986 {
987         __u32             addr = LNET_NIDADDR(nid);
988         __u32             net  = LNET_NIDNET(nid);
989         __u32             nnum = LNET_NETNUM(net);
990         __u32             lnd  = LNET_NETTYP(net);
991         struct netstrfns *nf;
992
993         if (nid == LNET_NID_ANY) {
994                 strncpy(buf, "<?>", buf_size);
995                 buf[buf_size - 1] = '\0';
996                 return buf;
997         }
998
999         nf = libcfs_lnd2netstrfns(lnd);
1000         if (nf == NULL) {
1001                 snprintf(buf, buf_size, "%x@<%u:%u>", addr, lnd, nnum);
1002         } else {
1003                 size_t addr_len;
1004
1005                 nf->nf_addr2str(addr, buf, buf_size);
1006                 addr_len = strlen(buf);
1007                 if (nnum == 0)
1008                         snprintf(buf + addr_len, buf_size - addr_len, "@%s",
1009                                  nf->nf_name);
1010                 else
1011                         snprintf(buf + addr_len, buf_size - addr_len, "@%s%u",
1012                                  nf->nf_name, nnum);
1013         }
1014
1015         return buf;
1016 }
1017 EXPORT_SYMBOL(libcfs_nid2str_r);
1018
1019 char *
1020 libcfs_nidstr_r(const struct lnet_nid *nid, char *buf, size_t buf_size)
1021 {
1022         __u32 nnum;
1023         __u32 lnd;
1024         struct netstrfns *nf;
1025
1026         if (LNET_NID_IS_ANY(nid)) {
1027                 strncpy(buf, "<?>", buf_size);
1028                 buf[buf_size - 1] = '\0';
1029                 return buf;
1030         }
1031
1032         nnum = be16_to_cpu(nid->nid_num);
1033         lnd = nid->nid_type;
1034         nf = libcfs_lnd2netstrfns(lnd);
1035         if (nf) {
1036                 size_t addr_len;
1037
1038                 if (nf->nf_addr2str_size)
1039                         nf->nf_addr2str_size(nid->nid_addr, NID_ADDR_BYTES(nid),
1040                                              buf, buf_size);
1041                 else
1042                         nf->nf_addr2str(ntohl(nid->nid_addr[0]), buf, buf_size);
1043                 addr_len = strlen(buf);
1044                 if (nnum == 0)
1045                         snprintf(buf + addr_len, buf_size - addr_len, "@%s",
1046                                  nf->nf_name);
1047                 else
1048                         snprintf(buf + addr_len, buf_size - addr_len, "@%s%u",
1049                                  nf->nf_name, nnum);
1050         } else {
1051                 int l = 0;
1052                 int words = DIV_ROUND_UP(NID_ADDR_BYTES(nid), 4);
1053                 int i;
1054
1055                 for (i = 0; i < words && i < 4; i++)
1056                         l = snprintf(buf+l, buf_size-l, "%s%x",
1057                                      i ? ":" : "", ntohl(nid->nid_addr[i]));
1058                 snprintf(buf+l, buf_size-l, "@<%u:%u>", lnd, nnum);
1059         }
1060
1061         return buf;
1062 }
1063 EXPORT_SYMBOL(libcfs_nidstr_r);
1064
1065 static struct netstrfns *
1066 libcfs_str2net_internal(const char *str, __u32 *net)
1067 {
1068         struct netstrfns *nf = NULL;
1069         int               nob;
1070         unsigned int      netnum;
1071         int               i;
1072
1073         for (i = 0; i < libcfs_nnetstrfns; i++) {
1074                 nf = &libcfs_netstrfns[i];
1075                 if (!strncmp(str, nf->nf_name, strlen(nf->nf_name)))
1076                         break;
1077         }
1078
1079         if (i == libcfs_nnetstrfns)
1080                 return NULL;
1081
1082         nob = strlen(nf->nf_name);
1083
1084         if (strlen(str) == (unsigned int)nob) {
1085                 netnum = 0;
1086         } else {
1087                 if (nf->nf_type == LOLND) /* net number not allowed */
1088                         return NULL;
1089
1090                 str += nob;
1091                 i = strlen(str);
1092                 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
1093                     i != (int)strlen(str))
1094                         return NULL;
1095         }
1096
1097         *net = LNET_MKNET(nf->nf_type, netnum);
1098         return nf;
1099 }
1100
1101 __u32
1102 libcfs_str2net(const char *str)
1103 {
1104         __u32  net;
1105
1106         if (libcfs_str2net_internal(str, &net) != NULL)
1107                 return net;
1108
1109         return LNET_NET_ANY;
1110 }
1111 EXPORT_SYMBOL(libcfs_str2net);
1112
1113 lnet_nid_t
1114 libcfs_str2nid(const char *str)
1115 {
1116         const char       *sep = strchr(str, '@');
1117         struct netstrfns *nf;
1118         __u32             net;
1119         __u32             addr;
1120
1121         if (sep != NULL) {
1122                 nf = libcfs_str2net_internal(sep + 1, &net);
1123                 if (nf == NULL)
1124                         return LNET_NID_ANY;
1125         } else {
1126                 sep = str + strlen(str);
1127                 net = LNET_MKNET(SOCKLND, 0);
1128                 nf = libcfs_lnd2netstrfns(SOCKLND);
1129                 LASSERT(nf != NULL);
1130         }
1131
1132         if (!nf->nf_str2addr(str, (int)(sep - str), &addr))
1133                 return LNET_NID_ANY;
1134
1135         return LNET_MKNID(net, addr);
1136 }
1137 EXPORT_SYMBOL(libcfs_str2nid);
1138
1139 int
1140 libcfs_strnid(struct lnet_nid *nid, const char *str)
1141 {
1142         const char       *sep = strchr(str, '@');
1143         struct netstrfns *nf;
1144         __u32             net;
1145
1146         if (sep != NULL) {
1147                 nf = libcfs_str2net_internal(sep + 1, &net);
1148                 if (nf == NULL)
1149                         return -EINVAL;
1150         } else {
1151                 if (strcmp(str, "<?>") == 0) {
1152                         memcpy(nid, &LNET_ANY_NID, sizeof(*nid));
1153                         return 0;
1154                 }
1155                 sep = str + strlen(str);
1156                 net = LNET_MKNET(SOCKLND, 0);
1157                 nf = libcfs_lnd2netstrfns(SOCKLND);
1158                 LASSERT(nf != NULL);
1159         }
1160
1161         memset(nid, 0, sizeof(*nid));
1162         nid->nid_type = LNET_NETTYP(net);
1163         nid->nid_num = htons(LNET_NETNUM(net));
1164         if (nf->nf_str2addr_size) {
1165                 size_t asize = 0;
1166
1167                 if (!nf->nf_str2addr_size(str, (int)(sep - str),
1168                                           nid->nid_addr, &asize))
1169                         return -EINVAL;
1170                 nid->nid_size = asize - 4;
1171         } else {
1172                 __u32 addr;
1173
1174                 if (!nf->nf_str2addr(str, (int)(sep - str), &addr))
1175                         return -EINVAL;
1176                 nid->nid_addr[0] = htonl(addr);
1177                 nid->nid_size = 0;
1178         }
1179         return 0;
1180 }
1181 EXPORT_SYMBOL(libcfs_strnid);
1182
1183 char *
1184 libcfs_id2str(struct lnet_process_id id)
1185 {
1186         char *str = libcfs_next_nidstring();
1187
1188         if (id.pid == LNET_PID_ANY) {
1189                 snprintf(str, LNET_NIDSTR_SIZE,
1190                          "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
1191                 return str;
1192         }
1193
1194         snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
1195                  ((id.pid & LNET_PID_USERFLAG) != 0) ? "U" : "",
1196                  (id.pid & ~LNET_PID_USERFLAG), libcfs_nid2str(id.nid));
1197         return str;
1198 }
1199 EXPORT_SYMBOL(libcfs_id2str);
1200
1201 char *
1202 libcfs_idstr(struct lnet_processid *id)
1203 {
1204         char *str = libcfs_next_nidstring();
1205
1206         if (id->pid == LNET_PID_ANY) {
1207                 snprintf(str, LNET_NIDSTR_SIZE,
1208                          "LNET_PID_ANY-%s", libcfs_nidstr(&id->nid));
1209                 return str;
1210         }
1211
1212         snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
1213                  ((id->pid & LNET_PID_USERFLAG) != 0) ? "U" : "",
1214                  (id->pid & ~LNET_PID_USERFLAG), libcfs_nidstr(&id->nid));
1215         return str;
1216 }
1217 EXPORT_SYMBOL(libcfs_idstr);
1218
1219 int
1220 libcfs_strid(struct lnet_processid *id, const char *str)
1221 {
1222         char *tmp = strchr(str, '-');
1223
1224         id->pid = LNET_PID_LUSTRE;
1225         if (tmp &&
1226             strncmp("LNET_PID_ANY-", str, tmp - str) != 0) {
1227                 char pid[LNET_NIDSTR_SIZE];
1228                 int rc;
1229
1230                 strscpy(pid, str, tmp - str);
1231                 rc = kstrtou32(pid, 10, &id->pid);
1232                 if (rc < 0)
1233                         return rc;
1234                 tmp++;
1235         } else {
1236                 tmp = (char *)str;
1237         }
1238
1239         return libcfs_strnid(&id->nid, tmp);
1240 }
1241 EXPORT_SYMBOL(libcfs_strid);
1242
1243 int
1244 libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
1245 {
1246         if (!strcmp(str, "*")) {
1247                 *nidp = LNET_NID_ANY;
1248                 return 1;
1249         }
1250
1251         *nidp = libcfs_str2nid(str);
1252         return *nidp != LNET_NID_ANY;
1253 }
1254 EXPORT_SYMBOL(libcfs_str2anynid);