Whamcloud - gitweb
28796e7ab0858b8c61b3476ef0abc4f29e4c1426
[fs/lustre-release.git] / libcfs / libcfs / nidstrings.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * libcfs/libcfs/nidstrings.c
37  *
38  * Author: Phil Schwan <phil@clusterfs.com>
39  */
40
41 #ifndef EXPORT_SYMTAB
42 # define EXPORT_SYMTAB
43 #endif
44
45 #define DEBUG_SUBSYSTEM S_LNET
46
47 #include <libcfs/libcfs.h>
48 #include <lnet/lnet.h>
49 #ifndef __KERNEL__
50 #ifdef HAVE_GETHOSTBYNAME
51 # include <netdb.h>
52 #endif
53 #endif
54
55 /* CAVEAT VENDITOR! Keep the canonical string representation of nets/nids
56  * consistent in all conversion functions.  Some code fragments are copied
57  * around for the sake of clarity...
58  */
59
60 /* CAVEAT EMPTOR! Racey temporary buffer allocation!
61  * Choose the number of nidstrings to support the MAXIMUM expected number of
62  * concurrent users.  If there are more, the returned string will be volatile.
63  * NB this number must allow for a process to be descheduled for a timeslice
64  * between getting its string and using it.
65  */
66
67 #define LNET_NIDSTR_COUNT  128     /* # of nidstrings */
68 #define LNET_NIDSTR_SIZE   32      /* size of each one (see below for usage) */
69
70 static char      libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE];
71 static int       libcfs_nidstring_idx = 0;
72
73 #ifdef __KERNEL__
74 static spinlock_t libcfs_nidstring_lock;
75
76 void libcfs_init_nidstrings (void)
77 {
78         spin_lock_init(&libcfs_nidstring_lock);
79 }
80
81 # define NIDSTR_LOCK(f)   spin_lock_irqsave(&libcfs_nidstring_lock, f)
82 # define NIDSTR_UNLOCK(f) spin_unlock_irqrestore(&libcfs_nidstring_lock, f)
83 #else
84 # define NIDSTR_LOCK(f)   (f=0)                 /* avoid unused var warnings */
85 # define NIDSTR_UNLOCK(f) (f=0)
86 #endif
87
88 static char *
89 libcfs_next_nidstring (void)
90 {
91         char          *str;
92         unsigned long  flags;
93
94         NIDSTR_LOCK(flags);
95
96         str = libcfs_nidstrings[libcfs_nidstring_idx++];
97         if (libcfs_nidstring_idx ==
98             sizeof(libcfs_nidstrings)/sizeof(libcfs_nidstrings[0]))
99                 libcfs_nidstring_idx = 0;
100
101         NIDSTR_UNLOCK(flags);
102         return str;
103 }
104
105 static int  libcfs_lo_str2addr(const char *str, int nob, __u32 *addr);
106 static void libcfs_ip_addr2str(__u32 addr, char *str);
107 static int  libcfs_ip_str2addr(const char *str, int nob, __u32 *addr);
108 static void libcfs_decnum_addr2str(__u32 addr, char *str);
109 static void libcfs_hexnum_addr2str(__u32 addr, char *str);
110 static int  libcfs_num_str2addr(const char *str, int nob, __u32 *addr);
111 static int  libcfs_ip_parse(char *str, int len, struct list_head *list);
112 static int  libcfs_num_parse(char *str, int len, struct list_head *list);
113 static int  libcfs_ip_match(__u32 addr, struct list_head *list);
114 static int  libcfs_num_match(__u32 addr, struct list_head *list);
115
116 struct netstrfns {
117         int          nf_type;
118         char        *nf_name;
119         char        *nf_modname;
120         void       (*nf_addr2str)(__u32 addr, char *str);
121         int        (*nf_str2addr)(const char *str, int nob, __u32 *addr);
122         int        (*nf_parse_addrlist)(char *str, int len,
123                                         struct list_head *list);
124         int        (*nf_match_addr)(__u32 addr, struct list_head *list);
125 };
126
127 static struct netstrfns  libcfs_netstrfns[] = {
128         {/* .nf_type      */  LOLND,
129          /* .nf_name      */  "lo",
130          /* .nf_modname   */  "klolnd",
131          /* .nf_addr2str  */  libcfs_decnum_addr2str,
132          /* .nf_str2addr  */  libcfs_lo_str2addr,
133          /* .nf_parse_addr*/  libcfs_num_parse,
134          /* .nf_match_addr*/  libcfs_num_match},
135         {/* .nf_type      */  SOCKLND,
136          /* .nf_name      */  "tcp",
137          /* .nf_modname   */  "ksocklnd",
138          /* .nf_addr2str  */  libcfs_ip_addr2str,
139          /* .nf_str2addr  */  libcfs_ip_str2addr,
140          /* .nf_parse_addrlist*/  libcfs_ip_parse,
141          /* .nf_match_addr*/  libcfs_ip_match},
142         {/* .nf_type      */  O2IBLND,
143          /* .nf_name      */  "o2ib",
144          /* .nf_modname   */  "ko2iblnd",
145          /* .nf_addr2str  */  libcfs_ip_addr2str,
146          /* .nf_str2addr  */  libcfs_ip_str2addr,
147          /* .nf_parse_addrlist*/  libcfs_ip_parse,
148          /* .nf_match_addr*/  libcfs_ip_match},
149         {/* .nf_type      */  CIBLND,
150          /* .nf_name      */  "cib",
151          /* .nf_modname   */  "kciblnd",
152          /* .nf_addr2str  */  libcfs_ip_addr2str,
153          /* .nf_str2addr  */  libcfs_ip_str2addr,
154          /* .nf_parse_addrlist*/  libcfs_ip_parse,
155          /* .nf_match_addr*/  libcfs_ip_match},
156         {/* .nf_type      */  OPENIBLND,
157          /* .nf_name      */  "openib",
158          /* .nf_modname   */  "kopeniblnd",
159          /* .nf_addr2str  */  libcfs_ip_addr2str,
160          /* .nf_str2addr  */  libcfs_ip_str2addr,
161          /* .nf_parse_addrlist*/  libcfs_ip_parse,
162          /* .nf_match_addr*/  libcfs_ip_match},
163         {/* .nf_type      */  IIBLND,
164          /* .nf_name      */  "iib",
165          /* .nf_modname   */  "kiiblnd",
166          /* .nf_addr2str  */  libcfs_ip_addr2str,
167          /* .nf_str2addr  */  libcfs_ip_str2addr,
168          /* .nf_parse_addrlist*/  libcfs_ip_parse,
169          /* .nf_match_addr*/  libcfs_ip_match},
170         {/* .nf_type      */  VIBLND,
171          /* .nf_name      */  "vib",
172          /* .nf_modname   */  "kviblnd",
173          /* .nf_addr2str  */  libcfs_ip_addr2str,
174          /* .nf_str2addr  */  libcfs_ip_str2addr,
175          /* .nf_parse_addrlist*/  libcfs_ip_parse,
176          /* .nf_match_addr*/  libcfs_ip_match},
177         {/* .nf_type      */  RALND,
178          /* .nf_name      */  "ra",
179          /* .nf_modname   */  "kralnd",
180          /* .nf_addr2str  */  libcfs_ip_addr2str,
181          /* .nf_str2addr  */  libcfs_ip_str2addr,
182          /* .nf_parse_addrlist*/  libcfs_ip_parse,
183          /* .nf_match_addr*/  libcfs_ip_match},
184         {/* .nf_type      */  QSWLND,
185          /* .nf_name      */  "elan",
186          /* .nf_modname   */  "kqswlnd",
187          /* .nf_addr2str  */  libcfs_decnum_addr2str,
188          /* .nf_str2addr  */  libcfs_num_str2addr,
189          /* .nf_parse_addrlist*/  libcfs_num_parse,
190          /* .nf_match_addr*/  libcfs_num_match},
191         {/* .nf_type      */  GMLND,
192          /* .nf_name      */  "gm",
193          /* .nf_modname   */  "kgmlnd",
194          /* .nf_addr2str  */  libcfs_hexnum_addr2str,
195          /* .nf_str2addr  */  libcfs_num_str2addr,
196          /* .nf_parse_addrlist*/  libcfs_num_parse,
197          /* .nf_match_addr*/  libcfs_num_match},
198         {/* .nf_type      */  MXLND,
199          /* .nf_name      */  "mx",
200          /* .nf_modname   */  "kmxlnd",
201          /* .nf_addr2str  */  libcfs_ip_addr2str,
202          /* .nf_str2addr  */  libcfs_ip_str2addr,
203          /* .nf_parse_addrlist*/  libcfs_ip_parse,
204          /* .nf_match_addr*/  libcfs_ip_match},
205         {/* .nf_type      */  PTLLND,
206          /* .nf_name      */  "ptl",
207          /* .nf_modname   */  "kptllnd",
208          /* .nf_addr2str  */  libcfs_decnum_addr2str,
209          /* .nf_str2addr  */  libcfs_num_str2addr,
210          /* .nf_parse_addrlist*/  libcfs_num_parse,
211          /* .nf_match_addr*/  libcfs_num_match},
212         /* placeholder for net0 alias.  It MUST BE THE LAST ENTRY */
213         {/* .nf_type      */  -1},
214 };
215
216 const int libcfs_nnetstrfns = sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
217
218 int
219 libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
220 {
221         *addr = 0;
222         return 1;
223 }
224
225 void
226 libcfs_ip_addr2str(__u32 addr, char *str)
227 {
228 #if 0   /* never lookup */
229 #if !defined(__KERNEL__) && defined HAVE_GETHOSTBYNAME
230         __u32           netip = htonl(addr);
231         struct hostent *he = gethostbyaddr(&netip, sizeof(netip), AF_INET);
232
233         if (he != NULL) {
234                 snprintf(str, LNET_NIDSTR_SIZE, "%s", he->h_name);
235                 return;
236         }
237 #endif
238 #endif
239         snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u",
240                  (addr >> 24) & 0xff, (addr >> 16) & 0xff,
241                  (addr >> 8) & 0xff, addr & 0xff);
242 }
243
244 /* CAVEAT EMPTOR XscanfX
245  * I use "%n" at the end of a sscanf format to detect trailing junk.  However
246  * sscanf may return immediately if it sees the terminating '0' in a string, so
247  * I initialise the %n variable to the expected length.  If sscanf sets it;
248  * fine, if it doesn't, then the scan ended at the end of the string, which is
249  * fine too :) */
250
251 int
252 libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
253 {
254         int   a;
255         int   b;
256         int   c;
257         int   d;
258         int   n = nob;                          /* XscanfX */
259
260         /* numeric IP? */
261         if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
262             n == nob &&
263             (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
264             (c & ~0xff) == 0 && (d & ~0xff) == 0) {
265                 *addr = ((a<<24)|(b<<16)|(c<<8)|d);
266                 return 1;
267         }
268
269 #if !defined(__KERNEL__) && defined HAVE_GETHOSTBYNAME
270         /* known hostname? */
271         if (('a' <= str[0] && str[0] <= 'z') ||
272             ('A' <= str[0] && str[0] <= 'Z')) {
273                 char *tmp;
274
275                 LIBCFS_ALLOC(tmp, nob + 1);
276                 if (tmp != NULL) {
277                         struct hostent *he;
278
279                         memcpy(tmp, str, nob);
280                         tmp[nob] = 0;
281
282                         he = gethostbyname(tmp);
283
284                         LIBCFS_FREE(tmp, nob);
285
286                         if (he != NULL) {
287                                 __u32 ip = *(__u32 *)he->h_addr;
288
289                                 *addr = ntohl(ip);
290                                 return 1;
291                         }
292                 }
293         }
294 #endif
295         return 0;
296 }
297
298 void
299 libcfs_decnum_addr2str(__u32 addr, char *str)
300 {
301         snprintf(str, LNET_NIDSTR_SIZE, "%u", addr);
302 }
303
304 void
305 libcfs_hexnum_addr2str(__u32 addr, char *str)
306 {
307         snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr);
308 }
309
310 int
311 libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
312 {
313         int     n;
314
315         n = nob;
316         if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
317                 return 1;
318
319         n = nob;
320         if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
321                 return 1;
322
323         n = nob;
324         if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
325                 return 1;
326
327         return 0;
328 }
329
330 struct netstrfns *
331 libcfs_lnd2netstrfns(int lnd)
332 {
333         int    i;
334
335         if (lnd >= 0)
336                 for (i = 0; i < libcfs_nnetstrfns; i++)
337                         if (lnd == libcfs_netstrfns[i].nf_type)
338                                 return &libcfs_netstrfns[i];
339
340         return NULL;
341 }
342
343 struct netstrfns *
344 libcfs_namenum2netstrfns(const char *name)
345 {
346         struct netstrfns *nf;
347         int               i;
348
349         for (i = 0; i < libcfs_nnetstrfns; i++) {
350                 nf = &libcfs_netstrfns[i];
351                 if (nf->nf_type >= 0 &&
352                     !strncmp(name, nf->nf_name, strlen(nf->nf_name)))
353                         return nf;
354         }
355         return NULL;
356 }
357
358 struct netstrfns *
359 libcfs_name2netstrfns(const char *name)
360 {
361         int    i;
362
363         for (i = 0; i < libcfs_nnetstrfns; i++)
364                 if (libcfs_netstrfns[i].nf_type >= 0 &&
365                     !strcmp(libcfs_netstrfns[i].nf_name, name))
366                         return &libcfs_netstrfns[i];
367
368         return NULL;
369 }
370
371 int
372 libcfs_isknown_lnd(int type)
373 {
374         return libcfs_lnd2netstrfns(type) != NULL;
375 }
376
377 char *
378 libcfs_lnd2modname(int lnd)
379 {
380         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
381
382         return (nf == NULL) ? NULL : nf->nf_modname;
383 }
384
385 char *
386 libcfs_lnd2str(int lnd)
387 {
388         char           *str;
389         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
390
391         if (nf != NULL)
392                 return nf->nf_name;
393
394         str = libcfs_next_nidstring();
395         snprintf(str, LNET_NIDSTR_SIZE, "?%u?", lnd);
396         return str;
397 }
398
399 int
400 libcfs_str2lnd(const char *str)
401 {
402         struct netstrfns *nf = libcfs_name2netstrfns(str);
403
404         if (nf != NULL)
405                 return nf->nf_type;
406
407         return -1;
408 }
409
410 char *
411 libcfs_net2str(__u32 net)
412 {
413         int               lnd = LNET_NETTYP(net);
414         int               num = LNET_NETNUM(net);
415         struct netstrfns *nf  = libcfs_lnd2netstrfns(lnd);
416         char             *str = libcfs_next_nidstring();
417
418         if (nf == NULL)
419                 snprintf(str, LNET_NIDSTR_SIZE, "<%u:%u>", lnd, num);
420         else if (num == 0)
421                 snprintf(str, LNET_NIDSTR_SIZE, "%s", nf->nf_name);
422         else
423                 snprintf(str, LNET_NIDSTR_SIZE, "%s%u", nf->nf_name, num);
424
425         return str;
426 }
427
428 char *
429 libcfs_nid2str(lnet_nid_t nid)
430 {
431         __u32             addr = LNET_NIDADDR(nid);
432         __u32             net = LNET_NIDNET(nid);
433         int               lnd = LNET_NETTYP(net);
434         int               nnum = LNET_NETNUM(net);
435         struct netstrfns *nf;
436         char             *str;
437         int               nob;
438
439         if (nid == LNET_NID_ANY)
440                 return "LNET_NID_ANY";
441
442         nf = libcfs_lnd2netstrfns(lnd);
443         str = libcfs_next_nidstring();
444
445         if (nf == NULL)
446                 snprintf(str, LNET_NIDSTR_SIZE, "%x@<%u:%u>", addr, lnd, nnum);
447         else {
448                 nf->nf_addr2str(addr, str);
449                 nob = strlen(str);
450                 if (nnum == 0)
451                         snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s",
452                                  nf->nf_name);
453                 else
454                         snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s%u",
455                                  nf->nf_name, nnum);
456         }
457
458         return str;
459 }
460
461 static struct netstrfns *
462 libcfs_str2net_internal(const char *str, __u32 *net)
463 {
464         struct netstrfns *nf;
465         int               nob;
466         int               netnum;
467         int               i;
468
469         for (i = 0; i < libcfs_nnetstrfns; i++) {
470                 nf = &libcfs_netstrfns[i];
471                 if (nf->nf_type >= 0 &&
472                     !strncmp(str, nf->nf_name, strlen(nf->nf_name)))
473                         break;
474         }
475
476         if (i == libcfs_nnetstrfns)
477                 return NULL;
478
479         nob = strlen(nf->nf_name);
480
481         if (strlen(str) == (unsigned int)nob) {
482                 netnum = 0;
483         } else {
484                 if (nf->nf_type == LOLND) /* net number not allowed */
485                         return NULL;
486
487                 str += nob;
488                 i = strlen(str);
489                 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
490                     i != (int)strlen(str))
491                         return NULL;
492         }
493
494         *net = LNET_MKNET(nf->nf_type, netnum);
495         return nf;
496 }
497
498 __u32
499 libcfs_str2net(const char *str)
500 {
501         __u32  net;
502
503         if (libcfs_str2net_internal(str, &net) != NULL)
504                 return net;
505
506         return LNET_NIDNET(LNET_NID_ANY);
507 }
508
509 lnet_nid_t
510 libcfs_str2nid(const char *str)
511 {
512         const char       *sep = strchr(str, '@');
513         struct netstrfns *nf;
514         __u32             net;
515         __u32             addr;
516
517         if (sep != NULL) {
518                 nf = libcfs_str2net_internal(sep + 1, &net);
519                 if (nf == NULL)
520                         return LNET_NID_ANY;
521         } else {
522                 sep = str + strlen(str);
523                 net = LNET_MKNET(SOCKLND, 0);
524                 nf = libcfs_lnd2netstrfns(SOCKLND);
525                 LASSERT (nf != NULL);
526         }
527
528         if (!nf->nf_str2addr(str, (int)(sep - str), &addr))
529                 return LNET_NID_ANY;
530
531         return LNET_MKNID(net, addr);
532 }
533
534 char *
535 libcfs_id2str(lnet_process_id_t id)
536 {
537         char *str = libcfs_next_nidstring();
538
539         if (id.pid == LNET_PID_ANY) {
540                 snprintf(str, LNET_NIDSTR_SIZE,
541                          "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
542                 return str;
543         }
544
545         snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
546                  ((id.pid & LNET_PID_USERFLAG) != 0) ? "U" : "",
547                  (id.pid & ~LNET_PID_USERFLAG), libcfs_nid2str(id.nid));
548         return str;
549 }
550
551 int
552 libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
553 {
554         if (!strcmp(str, "*")) {
555                 *nidp = LNET_NID_ANY;
556                 return 1;
557         }
558
559         *nidp = libcfs_str2nid(str);
560         return *nidp != LNET_NID_ANY;
561 }
562
563 /**
564  * Nid range list syntax.
565  *
566  * <nidlist>         :== <nidrange> [ ' ' <nidrange> ]
567  * <nidrange>        :== <addrrange> '@' <net>
568  * <addrrange>       :== '*' |
569  *                       <ipaddr_range> |
570  *                       <numaddr_range>
571  * <ipaddr_range>    :== <numaddr_range>.<numaddr_range>.<numaddr_range>.
572  *                       <numaddr_range>
573  * <numaddr_range>   :== <number> |
574  *                       <expr_list>
575  * <expr_list>       :== '[' <range_expr> [ ',' <range_expr>] ']'
576  * <range_expr>      :== <number> |
577  *                       <number> '-' <number> |
578  *                       <number> '-' <number> '/' <number>
579  * <net>             :== <netname> | <netname><number>
580  * <netname>         :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" |
581  *                       "vib" | "ra" | "elan" | "gm" | "mx" | "ptl"
582  */
583
584 /**
585  * Structure to represent NULL-less strings.
586  */
587 struct lstr {
588         char *ls_str;
589         int ls_len;
590 };
591
592 /**
593  * Structure to represent <nidrange> token of the syntax.
594  *
595  * One of this is created for each <net> parsed.
596  */
597 struct nidrange {
598         /**
599          * Link to list of this structures which is built on nid range
600          * list parsing.
601          */
602         struct list_head nr_link;
603         /**
604          * List head for addrrange::ar_link.
605          */
606         struct list_head nr_addrranges;
607         /**
608          * Flag indicating that *@<net> is found.
609          */
610         int nr_all;
611         /**
612          * Pointer to corresponding element of libcfs_netstrfns.
613          */
614         struct netstrfns *nr_netstrfns;
615         /**
616          * Number of network. E.g. 5 if <net> is "elan5".
617          */
618         int nr_netnum;
619 };
620
621 /**
622  * Structure to represent <addrrange> token of the syntax.
623  */
624 struct addrrange {
625         /**
626          * Link to nidrange::nr_addrranges.
627          */
628         struct list_head ar_link;
629         /**
630          * List head for numaddr_range::nar_link.
631          */
632         struct list_head ar_numaddr_ranges;
633 };
634
635 /**
636  * Structure to represent <numaddr_range> token of the syntax.
637  */
638 struct numaddr_range {
639         /**
640          * Link to addrrange::ar_numaddr_ranges.
641          */
642         struct list_head nar_link;
643         /**
644          * List head for range_expr::re_link.
645          */
646         struct list_head nar_range_exprs;
647 };
648
649 /**
650  * Structure to represent <range_expr> token of the syntax.
651  */
652 struct range_expr {
653         /**
654          * Link to numaddr_range::nar_range_exprs.
655          */
656         struct list_head re_link;
657         __u32 re_lo;
658         __u32 re_hi;
659         __u32 re_stride;
660 };
661
662 int
663 cfs_iswhite(char c)
664 {
665         switch (c) {
666         case ' ':
667         case '\t':
668         case '\n':
669         case '\r':
670                 return 1;
671         default:
672                 break;
673         }
674         return 0;
675 }
676
677 /*
678  * Extracts tokens from strings.
679  *
680  * Looks for \a delim in string \a next, sets \a res to point to
681  * substring before the delimiter, sets \a next right after the found
682  * delimiter.
683  *
684  * \retval 1 if \a res points to a string of non-whitespace characters
685  * \retval 0 otherwise
686  */
687 static int
688 gettok(struct lstr *next, char delim, struct lstr *res)
689 {
690         char *end;
691
692         if (next->ls_str == NULL)
693                 return 0;
694
695         /* skip leading white spaces */
696         while (next->ls_len) {
697                 if (!cfs_iswhite(*next->ls_str))
698                         break;
699                 next->ls_str ++;
700                 next->ls_len --;
701         }
702         if (next->ls_len == 0)
703                 /* whitespaces only */
704                 return 0;
705
706         if (*next->ls_str == delim)
707                 /* first non-writespace is the delimiter */
708                 return 0;
709
710         res->ls_str = next->ls_str;
711         end = memchr(next->ls_str, delim, next->ls_len);
712         if (end == NULL) {
713                 /* there is no the delimeter in the string */
714                 end = next->ls_str + next->ls_len;
715                 next->ls_str = NULL;
716         } else {
717                 next->ls_str = end + 1;
718                 next->ls_len -= (end - res->ls_str + 1);
719         }
720
721         /* skip ending whitespaces */
722         while (--end != res->ls_str)
723                 if (!cfs_iswhite(*end))
724                         break;
725
726         res->ls_len = end - res->ls_str + 1;
727         return 1;
728 }
729
730 /**
731  * Converts string to integer.
732  *
733  * Accepts decimal and hexadecimal number recordings.
734  *
735  * \retval 1 if first \a nob chars of \a str convert to decimal or
736  * hexadecimal integer in the range [\a min, \a max]
737  * \retval 0 otherwise
738  */
739 static int
740 libcfs_str2num_check(const char *str, int nob, unsigned *num,
741                      unsigned min, unsigned max)
742 {
743         int n;
744         char nstr[12];
745
746         n = nob;
747         if (sscanf(str, "%u%n", num, &n) != 1 || n != nob)
748                 if (sscanf(str, "0x%x%n", num, &n) != 1 || n != nob)
749                         if (sscanf(str, "0X%x%n", num, &n) != 1 || n != nob)
750                                 return 0;
751         sprintf(nstr, "%u", *num);
752         if (n != strlen(nstr) || memcmp(nstr, str, n)) {
753                 sprintf(nstr, "0x%x", *num);
754                 if (n != strlen(nstr) || memcmp(nstr, str, n)) {
755                         sprintf(nstr, "0X%x", *num);
756                         if (n != strlen(nstr) || memcmp(nstr, str, n))
757                                 return 0;
758                 }
759         }
760         if (*num < min || *num > max)
761                 return 0;
762         return 1;
763 }
764
765 /**
766  * Parses <range_expr> token of the syntax.
767  *
768  * \retval pointer to allocated range_expr and initialized
769  * range_expr::re_lo, range_expr::re_hi and range_expr:re_stride if \a
770  * src parses to
771  * <number> |
772  * <number> '-' <number> |
773  * <number> '-' <number> '/' <number>
774  * \retval NULL othersize
775  */
776 static struct range_expr *
777 parse_range_expr(struct lstr *src, unsigned min, unsigned max)
778 {
779         struct lstr tok;
780         struct range_expr *expr;
781
782         LIBCFS_ALLOC(expr, sizeof(struct range_expr));
783         if (expr == NULL)
784                 return NULL;
785
786         if (libcfs_str2num_check(src->ls_str, src->ls_len, &expr->re_lo,
787                                  min, max)) {
788                 /* <number> is parsed */
789                 expr->re_hi = expr->re_lo;
790                 expr->re_stride = 1;
791                 return expr;
792         }
793
794         if (!gettok(src, '-', &tok))
795                 goto failed;
796         if (!libcfs_str2num_check(tok.ls_str, tok.ls_len, &expr->re_lo,
797                                   min, max))
798                 goto failed;
799         /* <number> - */
800         if (libcfs_str2num_check(src->ls_str, src->ls_len, &expr->re_hi,
801                                  min, max)) {
802                 /* <number> - <number> is parsed */
803                 expr->re_stride = 1;
804                 return expr;
805         }
806
807         /* go to check <number> '-' <number> '/' <number> */
808         if (gettok(src, '/', &tok)) {
809                 if (!libcfs_str2num_check(tok.ls_str, tok.ls_len,
810                                           &expr->re_hi, min, max))
811                         goto failed;
812                 /* <number> - <number> / ... */
813                 if (libcfs_str2num_check(src->ls_str, src->ls_len,
814                                          &expr->re_stride, min, max))
815                         /* <number> - <number> / <number> is parsed */
816                         return expr;
817         }
818
819 failed:
820         LIBCFS_FREE(expr, sizeof(struct range_expr));
821         return NULL;
822 }
823
824 /**
825  * Parsed <expr_list> token of the syntax.
826  *
827  * \retval 1 if \a str parses to '[' <range_expr> [ ',' <range_expr>] ']'
828  * \return 0 otherwise
829  */
830 static int
831 parse_expr_list(struct lstr *str, struct list_head *list,
832                 unsigned min, unsigned max)
833 {
834         struct lstr res;
835         struct range_expr *range;
836
837         if (str->ls_str[0] != '[' || str->ls_str[str->ls_len - 1] != ']')
838                 return 0;
839         str->ls_str ++;
840         str->ls_len -= 2;
841
842         while (str->ls_str) {
843                 if (gettok(str, ',', &res) == 0)
844                         return 0;
845                 range = parse_range_expr(&res, min, max);
846                 if (range == NULL)
847                         return 0;
848                 list_add_tail(&range->re_link, list);
849         }
850         return 1;
851 }
852
853 /**
854  * Parses <numaddr_range> token of the syntax.
855  *
856  * \retval 1 if \a str parses to <number> | <expr_list>
857  * \retval 0 otherwise
858  */
859 static int
860 num_parse(char *str, int len,
861           struct list_head *list, unsigned min, unsigned max)
862 {
863         __u32 num;
864         struct lstr src;
865         struct numaddr_range *numaddr;
866
867         src.ls_str = str;
868         src.ls_len = len;
869
870         LIBCFS_ALLOC(numaddr, sizeof(struct numaddr_range));
871         if (numaddr == NULL)
872                 return 0;
873         list_add_tail(&numaddr->nar_link, list);
874         CFS_INIT_LIST_HEAD(&numaddr->nar_range_exprs);
875
876         if (libcfs_str2num_check(src.ls_str, src.ls_len, &num, min, max)) {
877                 /* <number> */
878                 struct range_expr *expr;
879
880                 LIBCFS_ALLOC(expr, sizeof(struct range_expr));
881                 if (expr == NULL)
882                         return 0;
883
884                 expr->re_lo = expr->re_hi = num;
885                 expr->re_stride = 1;
886                 list_add_tail(&expr->re_link, &numaddr->nar_range_exprs);
887                 return 1;
888         }
889
890         return parse_expr_list(&src, &numaddr->nar_range_exprs, min, max);
891 }
892
893 /**
894  * Nf_parse_addrlist method for networks using numeric addresses.
895  *
896  * Examples of such networks are gm and elan.
897  *
898  * \retval 1 if \a str parsed to numeric address
899  * \retval 0 otherwise
900  */
901 static int
902 libcfs_num_parse(char *str, int len, struct list_head *list)
903 {
904         return num_parse(str, len, list, 0, MAX_NUMERIC_VALUE);
905 }
906
907 /**
908  * Nf_parse_addrlist method for networks using ip addresses.
909  *
910  * Examples of such networks are tcp and o2ib.
911  *
912  * \retval 1 if \a str parsed to ip address
913  * \retval 0 otherwise
914  */
915 static int
916 libcfs_ip_parse(char *str, int len,
917                 struct list_head *list)
918 {
919         struct lstr src, res;
920         int i;
921
922         src.ls_str = str;
923         src.ls_len = len;
924         i = 0;
925         while (src.ls_str) {
926                 if (gettok(&src, '.', &res) == 0)
927                         return 0;
928                 if (!num_parse(res.ls_str, res.ls_len, list, 0, 255))
929                         return 0;
930                 i ++;
931         }
932
933         return (i == 4) ? 1 : 0;
934 }
935
936 /**
937  * Parses <addrrange> token on the syntax.
938  *
939  * Allocates struct addrrange and links to \a nidrange via
940  * (nidrange::nr_addrranges)
941  *
942  * \retval 1 if \a src parses to '*' | <ipaddr_range> | <numaddr_range>
943  * \retval 0 otherwise
944  */
945 static int
946 parse_addrange(const struct lstr *src, struct nidrange *nidrange)
947 {
948         struct addrrange *addrrange;
949
950         if (src->ls_len == 1 && src->ls_str[0] == '*') {
951                 nidrange->nr_all = 1;
952                 return 1;
953         }
954
955         LIBCFS_ALLOC(addrrange, sizeof(struct addrrange));
956         if (addrrange == NULL)
957                 return 0;
958         list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges);
959         CFS_INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges);
960
961         return nidrange->nr_netstrfns->nf_parse_addrlist(src->ls_str,
962                                                 src->ls_len,
963                                                 &addrrange->ar_numaddr_ranges);
964 }
965
966 /**
967  * Finds or creates struct nidrange.
968  *
969  * Checks if \a src is a valid network name, looks for corresponding
970  * nidrange on the ist of nidranges (\a nidlist), creates new struct
971  * nidrange if it is not found.
972  *
973  * \retval pointer to struct nidrange matching network specified via \a src
974  * \retval NULL if \a src does not match any network
975  */
976 static struct nidrange *
977 add_nidrange(const struct lstr *src,
978              struct list_head *nidlist)
979 {
980         struct netstrfns *nf;
981         struct nidrange *nr;
982         int endlen;
983         unsigned netnum;
984
985         if (src->ls_len >= LNET_NIDSTR_SIZE)
986                 return NULL;
987
988         nf = libcfs_namenum2netstrfns(src->ls_str);
989         if (nf == NULL)
990                 return NULL;
991         endlen = src->ls_len - strlen(nf->nf_name);
992         if (endlen == 0)
993                 /* network name only, e.g. "elan" or "tcp" */
994                 netnum = 0;
995         else {
996                 /* e.g. "elan25" or "tcp23", refuse to parse if
997                  * network name is not appended with decimal or
998                  * hexadecimal number */
999                 if (!libcfs_str2num_check(src->ls_str + strlen(nf->nf_name),
1000                                           endlen, &netnum,
1001                                           0, MAX_NUMERIC_VALUE))
1002                         return NULL;
1003         }
1004
1005         list_for_each_entry(nr, nidlist, nr_link) {
1006                 if (nr->nr_netstrfns != nf)
1007                         continue;
1008                 if (nr->nr_netnum != netnum)
1009                         continue;
1010                 return nr;
1011         }
1012
1013         LIBCFS_ALLOC(nr, sizeof(struct nidrange));
1014         if (nr == NULL)
1015                 return NULL;
1016         list_add_tail(&nr->nr_link, nidlist);
1017         CFS_INIT_LIST_HEAD(&nr->nr_addrranges);
1018         nr->nr_netstrfns = nf;
1019         nr->nr_all = 0;
1020         nr->nr_netnum = netnum;
1021
1022         return nr;
1023 }
1024
1025 /**
1026  * Parses <nidrange> token of the syntax.
1027  *
1028  * \retval 1 if \a src parses to <addrrange> '@' <net>
1029  * \retval 0 otherwise
1030  */
1031 static int
1032 parse_nidrange(struct lstr *src, struct list_head *nidlist)
1033 {
1034         struct lstr addrrange, net, tmp;
1035         struct nidrange *nr;
1036
1037         tmp = *src;
1038         if (gettok(src, '@', &addrrange) == 0)
1039                 goto failed;
1040
1041         if (gettok(src, '@', &net) == 0 || src->ls_str != NULL)
1042                 goto failed;
1043
1044         nr = add_nidrange(&net, nidlist);
1045         if (nr == NULL)
1046                 goto failed;
1047
1048         if (!parse_addrange(&addrrange, nr))
1049                 goto failed;
1050
1051         return 1;
1052  failed:
1053         CWARN("can't parse nidrange: \"%.*s\"\n", tmp.ls_len, tmp.ls_str);
1054         return 0;
1055 }
1056
1057 /**
1058  * Frees range_expr structures of \a list.
1059  *
1060  * \retval none
1061  */
1062 static void
1063 free_range_exprs(struct list_head *list)
1064 {
1065         struct list_head *pos, *next;
1066
1067         list_for_each_safe(pos, next, list) {
1068                 list_del(pos);
1069                 LIBCFS_FREE(list_entry(pos, struct range_expr, re_link),
1070                             sizeof(struct range_expr));
1071         }
1072 }
1073
1074 /**
1075  * Frees numaddr_range structures of \a list.
1076  *
1077  * For each struct numaddr_range structure found on \a list it frees
1078  * range_expr list attached to it and frees the numddr_range itself.
1079  *
1080  * \retval none
1081  */
1082 static void
1083 free_numaddr_ranges(struct list_head *list)
1084 {
1085         struct list_head *pos, *next;
1086         struct numaddr_range *numaddr;
1087
1088         list_for_each_safe(pos, next, list) {
1089                 numaddr = list_entry(pos, struct numaddr_range, nar_link);
1090                 free_range_exprs(&numaddr->nar_range_exprs);
1091                 list_del(pos);
1092                 LIBCFS_FREE(numaddr, sizeof(struct numaddr_range));
1093         }
1094 }
1095
1096 /**
1097  * Frees addrrange structures of \a list.
1098  *
1099  * For each struct addrrange structure found on \a list it frees
1100  * numaddr_range list attached to it and frees the addrrange itself.
1101  *
1102  * \retval none
1103  */
1104 static void
1105 free_addrranges(struct list_head *list)
1106 {
1107         struct list_head *pos, *next;
1108         struct addrrange *ar;
1109
1110         list_for_each_safe(pos, next, list) {
1111                 ar = list_entry(pos, struct addrrange, ar_link);
1112                 free_numaddr_ranges(&ar->ar_numaddr_ranges);
1113                 list_del(pos);
1114                 LIBCFS_FREE(ar, sizeof(struct addrrange));
1115         }
1116 }
1117
1118 /**
1119  * Frees nidrange strutures of \a list.
1120  *
1121  * For each struct nidrange structure found on \a list it frees
1122  * addrrange list attached to it and frees the nidrange itself.
1123  *
1124  * \retval none
1125  */
1126 void
1127 cfs_free_nidlist(struct list_head *list)
1128 {
1129         struct list_head *pos, *next;
1130         struct nidrange *nr;
1131
1132         list_for_each_safe(pos, next, list) {
1133                 nr = list_entry(pos, struct nidrange, nr_link);
1134                 free_addrranges(&nr->nr_addrranges);
1135                 list_del(pos);
1136                 LIBCFS_FREE(nr, sizeof(struct nidrange));
1137         }
1138 }
1139
1140 /**
1141  * Parses nid range list.
1142  *
1143  * Parses with rigorous syntax and overflow checking \a str into
1144  * <nidrange> [ ' ' <nidrange> ], compiles \a str into set of
1145  * structures and links that structure to \a nidlist. The resulting
1146  * list can be used to match a NID againts set of NIDS defined by \a
1147  * str.
1148  * \see cfs_match_nid
1149  *
1150  * \retval 1 on success
1151  * \retval 0 otherwise
1152  */
1153 int
1154 cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
1155 {
1156         struct lstr src, res;
1157         int rc;
1158         ENTRY;
1159
1160         src.ls_str = str;
1161         src.ls_len = len;
1162         CFS_INIT_LIST_HEAD(nidlist);
1163         while (src.ls_str) {
1164                 rc = gettok(&src, ' ', &res);
1165                 if (rc == 0) {
1166                         cfs_free_nidlist(nidlist);
1167                         RETURN(0);
1168                 }
1169                 rc = parse_nidrange(&res, nidlist);
1170                 if (rc == 0) {
1171                         cfs_free_nidlist(nidlist);
1172                         RETURN(0);
1173                 }
1174         }
1175         RETURN(1);
1176 }
1177
1178 /**
1179  * Matches address (\a addr) against address set encoded in \a list.
1180  *
1181  * \see libcfs_num_match(), libcfs_ip_match()
1182  *
1183  * \retval 1 if \a addr matches
1184  * \retval 0 otherwise
1185  */
1186 static int
1187 match_numaddr(__u32 addr, struct list_head *list, int shift, __u32 mask)
1188 {
1189         struct numaddr_range *numaddr;
1190         struct range_expr *expr;
1191         int ip, ok;
1192         ENTRY;
1193
1194         list_for_each_entry(numaddr, list, nar_link) {
1195                 ip = (addr >> shift) & mask;
1196                 shift -= 8;
1197                 ok = 0;
1198                 list_for_each_entry(expr, &numaddr->nar_range_exprs, re_link) {
1199                         if (ip >= expr->re_lo &&
1200                             ip <= expr->re_hi &&
1201                             ((ip - expr->re_lo) % expr->re_stride) == 0) {
1202                                 ok = 1;
1203                                 break;
1204                         }
1205                 }
1206                 if (!ok)
1207                         RETURN(0);
1208         }
1209         RETURN(1);
1210 }
1211
1212 /*
1213  * Nf_match_addr method for networks using numeric addresses
1214  *
1215  * \retval 1 on match
1216  * \retval 0 otherwise
1217  */
1218 static int
1219 libcfs_num_match(__u32 addr, struct list_head *numaddr)
1220 {
1221         return match_numaddr(addr, numaddr, 0, 0xffffffff);
1222 }
1223
1224 /*
1225  * Nf_match_addr method for networks using ip addresses
1226  *
1227  * \retval 1 on match
1228  * \retval 0 otherwise
1229  */
1230 static int
1231 libcfs_ip_match(__u32 addr, struct list_head *numaddr)
1232 {
1233         return match_numaddr(addr, numaddr, 24, 0xff);
1234 }
1235
1236 /**
1237  * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
1238  *
1239  * \see cfs_parse_nidlist()
1240  *
1241  * \retval 1 on match
1242  * \retval 0  otherwises
1243  */
1244 int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist)
1245 {
1246         struct nidrange *nr;
1247         struct addrrange *ar;
1248         ENTRY;
1249
1250         list_for_each_entry(nr, nidlist, nr_link) {
1251                 if (nr->nr_netstrfns->nf_type != LNET_NETTYP(LNET_NIDNET(nid)))
1252                         continue;
1253                 if (nr->nr_netnum != LNET_NETNUM(LNET_NIDNET(nid)))
1254                         continue;
1255                 if (nr->nr_all)
1256                         RETURN(1);
1257                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
1258                         if (nr->nr_netstrfns->nf_match_addr(LNET_NIDADDR(nid),
1259                                                        &ar->ar_numaddr_ranges))
1260                                 RETURN(1);
1261         }
1262         RETURN(0);
1263 }
1264
1265 #ifdef __KERNEL__
1266
1267 EXPORT_SYMBOL(libcfs_isknown_lnd);
1268 EXPORT_SYMBOL(libcfs_lnd2modname);
1269 EXPORT_SYMBOL(libcfs_lnd2str);
1270 EXPORT_SYMBOL(libcfs_str2lnd);
1271 EXPORT_SYMBOL(libcfs_net2str);
1272 EXPORT_SYMBOL(libcfs_nid2str);
1273 EXPORT_SYMBOL(libcfs_str2net);
1274 EXPORT_SYMBOL(libcfs_str2nid);
1275 EXPORT_SYMBOL(libcfs_id2str);
1276 EXPORT_SYMBOL(libcfs_str2anynid);
1277 EXPORT_SYMBOL(cfs_iswhite);
1278 EXPORT_SYMBOL(cfs_free_nidlist);
1279 EXPORT_SYMBOL(cfs_parse_nidlist);
1280 EXPORT_SYMBOL(cfs_match_nid);
1281
1282 #endif