Whamcloud - gitweb
LU-10391 lnet: introduce struct lnet_nid
[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  *
31  * lnet/lnet/nidstrings.c
32  *
33  * Author: Phil Schwan <phil@clusterfs.com>
34  */
35
36 #define DEBUG_SUBSYSTEM S_LNET
37
38 #include <libcfs/libcfs.h>
39 #include <uapi/linux/lnet/nidstr.h>
40 #include <lnet/lib-types.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         CFS_ALLOC_PTR(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         CFS_ALLOC_PTR(nr);
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                 CFS_FREE_PTR(ar);
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                 CFS_FREE_PTR(nr);
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 static int
455 libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
456 {
457         *addr = 0;
458         return 1;
459 }
460
461 static void
462 libcfs_ip_addr2str(__u32 addr, char *str, size_t size)
463 {
464         snprintf(str, size, "%u.%u.%u.%u",
465                  (addr >> 24) & 0xff, (addr >> 16) & 0xff,
466                  (addr >> 8) & 0xff, addr & 0xff);
467 }
468
469 /* CAVEAT EMPTOR XscanfX
470  * I use "%n" at the end of a sscanf format to detect trailing junk.  However
471  * sscanf may return immediately if it sees the terminating '0' in a string, so
472  * I initialise the %n variable to the expected length.  If sscanf sets it;
473  * fine, if it doesn't, then the scan ended at the end of the string, which is
474  * fine too :) */
475 static int
476 libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
477 {
478         unsigned int    a;
479         unsigned int    b;
480         unsigned int    c;
481         unsigned int    d;
482         int             n = nob; /* XscanfX */
483
484         /* numeric IP? */
485         if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
486             n == nob &&
487             (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
488             (c & ~0xff) == 0 && (d & ~0xff) == 0) {
489                 *addr = ((a<<24)|(b<<16)|(c<<8)|d);
490                 return 1;
491         }
492         return 0;
493 }
494
495 /* Used by lnet/config.c so it can't be static */
496 int
497 cfs_ip_addr_parse(char *str, int len, struct list_head *list)
498 {
499         struct cfs_expr_list *el;
500         struct cfs_lstr src;
501         int rc;
502         int i;
503
504         src.ls_str = str;
505         src.ls_len = len;
506         i = 0;
507
508         while (src.ls_str != NULL) {
509                 struct cfs_lstr res;
510
511                 if (!cfs_gettok(&src, '.', &res)) {
512                         rc = -EINVAL;
513                         goto out;
514                 }
515
516                 rc = cfs_expr_list_parse(res.ls_str, res.ls_len, 0, 255, &el);
517                 if (rc != 0)
518                         goto out;
519
520                 list_add_tail(&el->el_link, list);
521                 i++;
522         }
523
524         if (i == 4)
525                 return 0;
526
527         rc = -EINVAL;
528 out:
529         cfs_expr_list_free_list(list);
530
531         return rc;
532 }
533
534 static int
535 libcfs_ip_addr_range_print(char *buffer, int count, struct list_head *list)
536 {
537         int i = 0, j = 0;
538         struct cfs_expr_list *el;
539
540         list_for_each_entry(el, list, el_link) {
541                 LASSERT(j++ < 4);
542                 if (i != 0)
543                         i += scnprintf(buffer + i, count - i, ".");
544                 i += cfs_expr_list_print(buffer + i, count - i, el);
545         }
546         return i;
547 }
548
549 /**
550  * Matches address (\a addr) against address set encoded in \a list.
551  *
552  * \retval 1 if \a addr matches
553  * \retval 0 otherwise
554  */
555 int
556 cfs_ip_addr_match(__u32 addr, struct list_head *list)
557 {
558         struct cfs_expr_list *el;
559         int i = 0;
560
561         list_for_each_entry_reverse(el, list, el_link) {
562                 if (!cfs_expr_list_match(addr & 0xff, el))
563                         return 0;
564                 addr >>= 8;
565                 i++;
566         }
567
568         return i == 4;
569 }
570
571 /**
572  * Print the network part of the nidrange \a nr into the specified \a buffer.
573  *
574  * \retval number of characters written
575  */
576 static void
577 libcfs_decnum_addr2str(__u32 addr, char *str, size_t size)
578 {
579         snprintf(str, size, "%u", addr);
580 }
581
582 static int
583 libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
584 {
585         int     n;
586
587         n = nob;
588         if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
589                 return 1;
590
591         n = nob;
592         if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
593                 return 1;
594
595         n = nob;
596         if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
597                 return 1;
598
599         return 0;
600 }
601
602 /**
603  * Nf_parse_addrlist method for networks using numeric addresses.
604  *
605  * Examples of such networks are gm and elan.
606  *
607  * \retval 0 if \a str parsed to numeric address
608  * \retval errno otherwise
609  */
610 int
611 libcfs_num_parse(char *str, int len, struct list_head *list)
612 {
613         struct cfs_expr_list *el;
614         int     rc;
615
616         rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
617         if (rc == 0)
618                 list_add_tail(&el->el_link, list);
619
620         return rc;
621 }
622
623 static int
624 libcfs_num_addr_range_print(char *buffer, int count, struct list_head *list)
625 {
626         int i = 0, j = 0;
627         struct cfs_expr_list *el;
628
629         list_for_each_entry(el, list, el_link) {
630                 LASSERT(j++ < 1);
631                 i += cfs_expr_list_print(buffer + i, count - i, el);
632         }
633         return i;
634 }
635
636 /*
637  * Nf_match_addr method for networks using numeric addresses
638  *
639  * \retval 1 on match
640  * \retval 0 otherwise
641  */
642 static int
643 libcfs_num_match(__u32 addr, struct list_head *numaddr)
644 {
645         struct cfs_expr_list *el;
646
647         LASSERT(!list_empty(numaddr));
648         el = list_entry(numaddr->next, struct cfs_expr_list, el_link);
649
650         return cfs_expr_list_match(addr, el);
651 }
652
653 static struct netstrfns libcfs_netstrfns[] = {
654         { .nf_type              = LOLND,
655           .nf_name              = "lo",
656           .nf_modname           = "klolnd",
657           .nf_addr2str          = libcfs_decnum_addr2str,
658           .nf_str2addr          = libcfs_lo_str2addr,
659           .nf_parse_addrlist    = libcfs_num_parse,
660           .nf_print_addrlist    = libcfs_num_addr_range_print,
661           .nf_match_addr        = libcfs_num_match
662         },
663         { .nf_type              = SOCKLND,
664           .nf_name              = "tcp",
665           .nf_modname           = "ksocklnd",
666           .nf_addr2str          = libcfs_ip_addr2str,
667           .nf_str2addr          = libcfs_ip_str2addr,
668           .nf_parse_addrlist    = cfs_ip_addr_parse,
669           .nf_print_addrlist    = libcfs_ip_addr_range_print,
670           .nf_match_addr        = cfs_ip_addr_match
671         },
672         { .nf_type              = O2IBLND,
673           .nf_name              = "o2ib",
674           .nf_modname           = "ko2iblnd",
675           .nf_addr2str          = libcfs_ip_addr2str,
676           .nf_str2addr          = libcfs_ip_str2addr,
677           .nf_parse_addrlist    = cfs_ip_addr_parse,
678           .nf_print_addrlist    = libcfs_ip_addr_range_print,
679           .nf_match_addr        = cfs_ip_addr_match
680         },
681         { .nf_type              = GNILND,
682           .nf_name              = "gni",
683           .nf_modname           = "kgnilnd",
684           .nf_addr2str          = libcfs_decnum_addr2str,
685           .nf_str2addr          = libcfs_num_str2addr,
686           .nf_parse_addrlist    = libcfs_num_parse,
687           .nf_print_addrlist    = libcfs_num_addr_range_print,
688           .nf_match_addr        = libcfs_num_match
689         },
690         { .nf_type              = GNIIPLND,
691           .nf_name              = "gip",
692           .nf_modname           = "kgnilnd",
693           .nf_addr2str          = libcfs_ip_addr2str,
694           .nf_str2addr          = libcfs_ip_str2addr,
695           .nf_parse_addrlist    = cfs_ip_addr_parse,
696           .nf_print_addrlist    = libcfs_ip_addr_range_print,
697           .nf_match_addr        = cfs_ip_addr_match
698         },
699         { .nf_type              = PTL4LND,
700           .nf_name              = "ptlf",
701           .nf_modname           = "kptl4lnd",
702           .nf_addr2str          = libcfs_decnum_addr2str,
703           .nf_str2addr          = libcfs_num_str2addr,
704           .nf_parse_addrlist    = libcfs_num_parse,
705           .nf_print_addrlist    = libcfs_num_addr_range_print,
706           .nf_match_addr        = libcfs_num_match
707         },
708 };
709
710 static const size_t libcfs_nnetstrfns = ARRAY_SIZE(libcfs_netstrfns);
711
712 static struct netstrfns *
713 type2net_info(__u32 net_type)
714 {
715         int i;
716
717         for (i = 0; i < libcfs_nnetstrfns; i++) {
718                 if (libcfs_netstrfns[i].nf_type == net_type)
719                         return &libcfs_netstrfns[i];
720         }
721
722         return NULL;
723 }
724
725 int
726 cfs_match_net(__u32 net_id, __u32 net_type, struct list_head *net_num_list)
727 {
728         __u32 net_num;
729
730         if (!net_num_list)
731                 return 0;
732
733         if (net_type != LNET_NETTYP(net_id))
734                 return 0;
735
736         net_num = LNET_NETNUM(net_id);
737
738         /* if there is a net number but the list passed in is empty, then
739          * there is no match.
740          */
741         if (!net_num && list_empty(net_num_list))
742                 return 1;
743         else if (list_empty(net_num_list))
744                 return 0;
745
746         if (!libcfs_num_match(net_num, net_num_list))
747                 return 0;
748
749         return 1;
750 }
751
752 int
753 cfs_match_nid_net(lnet_nid_t nid, __u32 net_type,
754                   struct list_head *net_num_list,
755                   struct list_head *addr)
756 {
757         __u32 address;
758         struct netstrfns *nf;
759
760         if (!addr || !net_num_list)
761                 return 0;
762
763         nf = type2net_info(LNET_NETTYP(LNET_NIDNET(nid)));
764         if (!nf || !net_num_list || !addr)
765                 return 0;
766
767         address = LNET_NIDADDR(nid);
768
769         /* if either the address or net number don't match then no match */
770         if (!nf->nf_match_addr(address, addr) ||
771             !cfs_match_net(LNET_NIDNET(nid), net_type, net_num_list))
772                 return 0;
773
774         return 1;
775 }
776 EXPORT_SYMBOL(cfs_match_nid_net);
777
778 static struct netstrfns *
779 libcfs_lnd2netstrfns(__u32 lnd)
780 {
781         int     i;
782
783         for (i = 0; i < libcfs_nnetstrfns; i++)
784                 if (lnd == libcfs_netstrfns[i].nf_type)
785                         return &libcfs_netstrfns[i];
786
787         return NULL;
788 }
789
790 static struct netstrfns *
791 libcfs_namenum2netstrfns(const char *name)
792 {
793         struct netstrfns *nf;
794         int               i;
795
796         for (i = 0; i < libcfs_nnetstrfns; i++) {
797                 nf = &libcfs_netstrfns[i];
798                 if (!strncmp(name, nf->nf_name, strlen(nf->nf_name)))
799                         return nf;
800         }
801         return NULL;
802 }
803
804 static struct netstrfns *
805 libcfs_name2netstrfns(const char *name)
806 {
807         int    i;
808
809         for (i = 0; i < libcfs_nnetstrfns; i++)
810                 if (!strcmp(libcfs_netstrfns[i].nf_name, name))
811                         return &libcfs_netstrfns[i];
812
813         return NULL;
814 }
815
816 int
817 libcfs_isknown_lnd(__u32 lnd)
818 {
819         return libcfs_lnd2netstrfns(lnd) != NULL;
820 }
821 EXPORT_SYMBOL(libcfs_isknown_lnd);
822
823 char *
824 libcfs_lnd2modname(__u32 lnd)
825 {
826         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
827
828         return (nf == NULL) ? NULL : nf->nf_modname;
829 }
830 EXPORT_SYMBOL(libcfs_lnd2modname);
831
832 int
833 libcfs_str2lnd(const char *str)
834 {
835         struct netstrfns *nf = libcfs_name2netstrfns(str);
836
837         if (nf != NULL)
838                 return nf->nf_type;
839
840         return -ENXIO;
841 }
842 EXPORT_SYMBOL(libcfs_str2lnd);
843
844 char *
845 libcfs_lnd2str_r(__u32 lnd, char *buf, size_t buf_size)
846 {
847         struct netstrfns *nf;
848
849         nf = libcfs_lnd2netstrfns(lnd);
850         if (nf == NULL)
851                 snprintf(buf, buf_size, "?%u?", lnd);
852         else
853                 snprintf(buf, buf_size, "%s", nf->nf_name);
854
855         return buf;
856 }
857 EXPORT_SYMBOL(libcfs_lnd2str_r);
858
859 char *
860 libcfs_net2str_r(__u32 net, char *buf, size_t buf_size)
861 {
862         __u32             nnum = LNET_NETNUM(net);
863         __u32             lnd  = LNET_NETTYP(net);
864         struct netstrfns *nf;
865
866         nf = libcfs_lnd2netstrfns(lnd);
867         if (nf == NULL)
868                 snprintf(buf, buf_size, "<%u:%u>", lnd, nnum);
869         else if (nnum == 0)
870                 snprintf(buf, buf_size, "%s", nf->nf_name);
871         else
872                 snprintf(buf, buf_size, "%s%u", nf->nf_name, nnum);
873
874         return buf;
875 }
876 EXPORT_SYMBOL(libcfs_net2str_r);
877
878 char *
879 libcfs_nid2str_r(lnet_nid_t nid, char *buf, size_t buf_size)
880 {
881         __u32             addr = LNET_NIDADDR(nid);
882         __u32             net  = LNET_NIDNET(nid);
883         __u32             nnum = LNET_NETNUM(net);
884         __u32             lnd  = LNET_NETTYP(net);
885         struct netstrfns *nf;
886
887         if (nid == LNET_NID_ANY) {
888                 strncpy(buf, "<?>", buf_size);
889                 buf[buf_size - 1] = '\0';
890                 return buf;
891         }
892
893         nf = libcfs_lnd2netstrfns(lnd);
894         if (nf == NULL) {
895                 snprintf(buf, buf_size, "%x@<%u:%u>", addr, lnd, nnum);
896         } else {
897                 size_t addr_len;
898
899                 nf->nf_addr2str(addr, buf, buf_size);
900                 addr_len = strlen(buf);
901                 if (nnum == 0)
902                         snprintf(buf + addr_len, buf_size - addr_len, "@%s",
903                                  nf->nf_name);
904                 else
905                         snprintf(buf + addr_len, buf_size - addr_len, "@%s%u",
906                                  nf->nf_name, nnum);
907         }
908
909         return buf;
910 }
911 EXPORT_SYMBOL(libcfs_nid2str_r);
912
913 char *
914 libcfs_nidstr_r(const struct lnet_nid *nid, char *buf, size_t buf_size)
915 {
916         __u32 nnum = be16_to_cpu(nid->nid_num);
917         __u32 lnd  = nid->nid_type;
918         struct netstrfns *nf;
919
920         if (LNET_NID_IS_ANY(nid)) {
921                 strncpy(buf, "<?>", buf_size);
922                 buf[buf_size - 1] = '\0';
923                 return buf;
924         }
925
926         nf = libcfs_lnd2netstrfns(lnd);
927         if (nf && nid_is_nid4(nid)) {
928                 size_t addr_len;
929
930                 nf->nf_addr2str(ntohl(nid->nid_addr[0]), buf, buf_size);
931                 addr_len = strlen(buf);
932                 if (nnum == 0)
933                         snprintf(buf + addr_len, buf_size - addr_len, "@%s",
934                                  nf->nf_name);
935                 else
936                         snprintf(buf + addr_len, buf_size - addr_len, "@%s%u",
937                                  nf->nf_name, nnum);
938         } else {
939                 int l = 0;
940                 int words = DIV_ROUND_UP(NID_ADDR_BYTES(nid), 4);
941                 int i;
942
943                 for (i = 0; i < words && i < 4; i++)
944                         l = snprintf(buf+l, buf_size-l, "%s%x",
945                                      i ? ":" : "", ntohl(nid->nid_addr[i]));
946                 snprintf(buf+l, buf_size-l, "@<%u:%u>", lnd, nnum);
947         }
948
949         return buf;
950 }
951 EXPORT_SYMBOL(libcfs_nidstr_r);
952
953 static struct netstrfns *
954 libcfs_str2net_internal(const char *str, __u32 *net)
955 {
956         struct netstrfns *nf = NULL;
957         int               nob;
958         unsigned int      netnum;
959         int               i;
960
961         for (i = 0; i < libcfs_nnetstrfns; i++) {
962                 nf = &libcfs_netstrfns[i];
963                 if (!strncmp(str, nf->nf_name, strlen(nf->nf_name)))
964                         break;
965         }
966
967         if (i == libcfs_nnetstrfns)
968                 return NULL;
969
970         nob = strlen(nf->nf_name);
971
972         if (strlen(str) == (unsigned int)nob) {
973                 netnum = 0;
974         } else {
975                 if (nf->nf_type == LOLND) /* net number not allowed */
976                         return NULL;
977
978                 str += nob;
979                 i = strlen(str);
980                 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
981                     i != (int)strlen(str))
982                         return NULL;
983         }
984
985         *net = LNET_MKNET(nf->nf_type, netnum);
986         return nf;
987 }
988
989 __u32
990 libcfs_str2net(const char *str)
991 {
992         __u32  net;
993
994         if (libcfs_str2net_internal(str, &net) != NULL)
995                 return net;
996
997         return LNET_NET_ANY;
998 }
999 EXPORT_SYMBOL(libcfs_str2net);
1000
1001 lnet_nid_t
1002 libcfs_str2nid(const char *str)
1003 {
1004         const char       *sep = strchr(str, '@');
1005         struct netstrfns *nf;
1006         __u32             net;
1007         __u32             addr;
1008
1009         if (sep != NULL) {
1010                 nf = libcfs_str2net_internal(sep + 1, &net);
1011                 if (nf == NULL)
1012                         return LNET_NID_ANY;
1013         } else {
1014                 sep = str + strlen(str);
1015                 net = LNET_MKNET(SOCKLND, 0);
1016                 nf = libcfs_lnd2netstrfns(SOCKLND);
1017                 LASSERT(nf != NULL);
1018         }
1019
1020         if (!nf->nf_str2addr(str, (int)(sep - str), &addr))
1021                 return LNET_NID_ANY;
1022
1023         return LNET_MKNID(net, addr);
1024 }
1025 EXPORT_SYMBOL(libcfs_str2nid);
1026
1027 char *
1028 libcfs_id2str(struct lnet_process_id id)
1029 {
1030         char *str = libcfs_next_nidstring();
1031
1032         if (id.pid == LNET_PID_ANY) {
1033                 snprintf(str, LNET_NIDSTR_SIZE,
1034                          "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
1035                 return str;
1036         }
1037
1038         snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
1039                  ((id.pid & LNET_PID_USERFLAG) != 0) ? "U" : "",
1040                  (id.pid & ~LNET_PID_USERFLAG), libcfs_nid2str(id.nid));
1041         return str;
1042 }
1043 EXPORT_SYMBOL(libcfs_id2str);
1044
1045 int
1046 libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
1047 {
1048         if (!strcmp(str, "*")) {
1049                 *nidp = LNET_NID_ANY;
1050                 return 1;
1051         }
1052
1053         *nidp = libcfs_str2nid(str);
1054         return *nidp != LNET_NID_ANY;
1055 }
1056 EXPORT_SYMBOL(libcfs_str2anynid);