Whamcloud - gitweb
68c2ebce12b4f50cc9dbc4d92f5f762f4c30520f
[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 cfs_spinlock_t libcfs_nidstring_lock;
75
76 void libcfs_init_nidstrings (void)
77 {
78         cfs_spin_lock_init(&libcfs_nidstring_lock);
79 }
80
81 # define NIDSTR_LOCK(f)   cfs_spin_lock_irqsave(&libcfs_nidstring_lock, f)
82 # define NIDSTR_UNLOCK(f) cfs_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, cfs_list_t *list);
112 static int  libcfs_num_parse(char *str, int len, cfs_list_t *list);
113 static int  libcfs_ip_match(__u32 addr, cfs_list_t *list);
114 static int  libcfs_num_match(__u32 addr, cfs_list_t *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                                         cfs_list_t *list);
124         int        (*nf_match_addr)(__u32 addr, cfs_list_t *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  * \verbatim
566  *
567  * <nidlist>         :== <nidrange> [ ' ' <nidrange> ]
568  * <nidrange>        :== <addrrange> '@' <net>
569  * <addrrange>       :== '*' |
570  *                       <ipaddr_range> |
571  *                       <numaddr_range>
572  * <ipaddr_range>    :== <numaddr_range>.<numaddr_range>.<numaddr_range>.
573  *                       <numaddr_range>
574  * <numaddr_range>   :== <number> |
575  *                       <expr_list>
576  * <expr_list>       :== '[' <range_expr> [ ',' <range_expr>] ']'
577  * <range_expr>      :== <number> |
578  *                       <number> '-' <number> |
579  *                       <number> '-' <number> '/' <number>
580  * <net>             :== <netname> | <netname><number>
581  * <netname>         :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" |
582  *                       "vib" | "ra" | "elan" | "gm" | "mx" | "ptl"
583  * \endverbatim
584  */
585
586 /**
587  * Structure to represent NULL-less strings.
588  */
589 struct lstr {
590         char *ls_str;
591         int ls_len;
592 };
593
594 /**
595  * Structure to represent \<nidrange\> token of the syntax.
596  *
597  * One of this is created for each \<net\> parsed.
598  */
599 struct nidrange {
600         /**
601          * Link to list of this structures which is built on nid range
602          * list parsing.
603          */
604         cfs_list_t nr_link;
605         /**
606          * List head for addrrange::ar_link.
607          */
608         cfs_list_t nr_addrranges;
609         /**
610          * Flag indicating that *@<net> is found.
611          */
612         int nr_all;
613         /**
614          * Pointer to corresponding element of libcfs_netstrfns.
615          */
616         struct netstrfns *nr_netstrfns;
617         /**
618          * Number of network. E.g. 5 if \<net\> is "elan5".
619          */
620         int nr_netnum;
621 };
622
623 /**
624  * Structure to represent \<addrrange\> token of the syntax.
625  */
626 struct addrrange {
627         /**
628          * Link to nidrange::nr_addrranges.
629          */
630         cfs_list_t ar_link;
631         /**
632          * List head for numaddr_range::nar_link.
633          */
634         cfs_list_t ar_numaddr_ranges;
635 };
636
637 /**
638  * Structure to represent \<numaddr_range\> token of the syntax.
639  */
640 struct numaddr_range {
641         /**
642          * Link to addrrange::ar_numaddr_ranges.
643          */
644         cfs_list_t nar_link;
645         /**
646          * List head for range_expr::re_link.
647          */
648         cfs_list_t nar_range_exprs;
649 };
650
651 /**
652  * Structure to represent \<range_expr\> token of the syntax.
653  */
654 struct range_expr {
655         /**
656          * Link to numaddr_range::nar_range_exprs.
657          */
658         cfs_list_t re_link;
659         __u32 re_lo;
660         __u32 re_hi;
661         __u32 re_stride;
662 };
663
664 int
665 cfs_iswhite(char c)
666 {
667         switch (c) {
668         case ' ':
669         case '\t':
670         case '\n':
671         case '\r':
672                 return 1;
673         default:
674                 break;
675         }
676         return 0;
677 }
678
679 /*
680  * Extracts tokens from strings.
681  *
682  * Looks for \a delim in string \a next, sets \a res to point to
683  * substring before the delimiter, sets \a next right after the found
684  * delimiter.
685  *
686  * \retval 1 if \a res points to a string of non-whitespace characters
687  * \retval 0 otherwise
688  */
689 static int
690 gettok(struct lstr *next, char delim, struct lstr *res)
691 {
692         char *end;
693
694         if (next->ls_str == NULL)
695                 return 0;
696
697         /* skip leading white spaces */
698         while (next->ls_len) {
699                 if (!cfs_iswhite(*next->ls_str))
700                         break;
701                 next->ls_str ++;
702                 next->ls_len --;
703         }
704         if (next->ls_len == 0)
705                 /* whitespaces only */
706                 return 0;
707
708         if (*next->ls_str == delim)
709                 /* first non-writespace is the delimiter */
710                 return 0;
711
712         res->ls_str = next->ls_str;
713         end = memchr(next->ls_str, delim, next->ls_len);
714         if (end == NULL) {
715                 /* there is no the delimeter in the string */
716                 end = next->ls_str + next->ls_len;
717                 next->ls_str = NULL;
718         } else {
719                 next->ls_str = end + 1;
720                 next->ls_len -= (end - res->ls_str + 1);
721         }
722
723         /* skip ending whitespaces */
724         while (--end != res->ls_str)
725                 if (!cfs_iswhite(*end))
726                         break;
727
728         res->ls_len = end - res->ls_str + 1;
729         return 1;
730 }
731
732 /**
733  * Converts string to integer.
734  *
735  * Accepts decimal and hexadecimal number recordings.
736  *
737  * \retval 1 if first \a nob chars of \a str convert to decimal or
738  * hexadecimal integer in the range [\a min, \a max]
739  * \retval 0 otherwise
740  */
741 static int
742 libcfs_str2num_check(const char *str, int nob, unsigned *num,
743                      unsigned min, unsigned max)
744 {
745         int n;
746         char nstr[12];
747
748         n = nob;
749         if (sscanf(str, "%u%n", num, &n) != 1 || n != nob)
750                 if (sscanf(str, "0x%x%n", num, &n) != 1 || n != nob)
751                         if (sscanf(str, "0X%x%n", num, &n) != 1 || n != nob)
752                                 return 0;
753         sprintf(nstr, "%u", *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                         sprintf(nstr, "0X%x", *num);
758                         if (n != strlen(nstr) || memcmp(nstr, str, n))
759                                 return 0;
760                 }
761         }
762         if (*num < min || *num > max)
763                 return 0;
764         return 1;
765 }
766
767 /**
768  * Parses \<range_expr\> token of the syntax.
769  *
770  * \retval pointer to allocated range_expr and initialized
771  * range_expr::re_lo, range_expr::re_hi and range_expr:re_stride if \a
772  `* src parses to
773  * \<number\> |
774  * \<number\> '-' \<number\> |
775  * \<number\> '-' \<number\> '/' \<number\>
776  * \retval NULL othersize
777  */
778 static struct range_expr *
779 parse_range_expr(struct lstr *src, unsigned min, unsigned max)
780 {
781         struct lstr tok;
782         struct range_expr *expr;
783
784         LIBCFS_ALLOC(expr, sizeof(struct range_expr));
785         if (expr == NULL)
786                 return NULL;
787
788         if (libcfs_str2num_check(src->ls_str, src->ls_len, &expr->re_lo,
789                                  min, max)) {
790                 /* <number> is parsed */
791                 expr->re_hi = expr->re_lo;
792                 expr->re_stride = 1;
793                 return expr;
794         }
795
796         if (!gettok(src, '-', &tok))
797                 goto failed;
798         if (!libcfs_str2num_check(tok.ls_str, tok.ls_len, &expr->re_lo,
799                                   min, max))
800                 goto failed;
801         /* <number> - */
802         if (libcfs_str2num_check(src->ls_str, src->ls_len, &expr->re_hi,
803                                  min, max)) {
804                 /* <number> - <number> is parsed */
805                 expr->re_stride = 1;
806                 return expr;
807         }
808
809         /* go to check <number> '-' <number> '/' <number> */
810         if (gettok(src, '/', &tok)) {
811                 if (!libcfs_str2num_check(tok.ls_str, tok.ls_len,
812                                           &expr->re_hi, min, max))
813                         goto failed;
814                 /* <number> - <number> / ... */
815                 if (libcfs_str2num_check(src->ls_str, src->ls_len,
816                                          &expr->re_stride, min, max))
817                         /* <number> - <number> / <number> is parsed */
818                         return expr;
819         }
820
821 failed:
822         LIBCFS_FREE(expr, sizeof(struct range_expr));
823         return NULL;
824 }
825
826 /**
827  * Parses \<expr_list\> token of the syntax.
828  *
829  * \retval 1 if \a str parses to '[' \<range_expr\> [ ',' \<range_expr\>] ']'
830  * \retval 0 otherwise
831  */
832 static int
833 parse_expr_list(struct lstr *str, cfs_list_t *list,
834                 unsigned min, unsigned max)
835 {
836         struct lstr res;
837         struct range_expr *range;
838
839         if (str->ls_str[0] != '[' || str->ls_str[str->ls_len - 1] != ']')
840                 return 0;
841         str->ls_str ++;
842         str->ls_len -= 2;
843
844         while (str->ls_str) {
845                 if (gettok(str, ',', &res) == 0)
846                         return 0;
847                 range = parse_range_expr(&res, min, max);
848                 if (range == NULL)
849                         return 0;
850                 cfs_list_add_tail(&range->re_link, list);
851         }
852         return 1;
853 }
854
855 /**
856  * Parses \<numaddr_range\> token of the syntax.
857  *
858  * \retval 1 if \a str parses to \<number\> | \<expr_list\>
859  * \retval 0 otherwise
860  */
861 static int
862 num_parse(char *str, int len,
863           cfs_list_t *list, unsigned min, unsigned max)
864 {
865         __u32 num;
866         struct lstr src;
867         struct numaddr_range *numaddr;
868
869         src.ls_str = str;
870         src.ls_len = len;
871
872         LIBCFS_ALLOC(numaddr, sizeof(struct numaddr_range));
873         if (numaddr == NULL)
874                 return 0;
875         cfs_list_add_tail(&numaddr->nar_link, list);
876         CFS_INIT_LIST_HEAD(&numaddr->nar_range_exprs);
877
878         if (libcfs_str2num_check(src.ls_str, src.ls_len, &num, min, max)) {
879                 /* <number> */
880                 struct range_expr *expr;
881
882                 LIBCFS_ALLOC(expr, sizeof(struct range_expr));
883                 if (expr == NULL)
884                         return 0;
885
886                 expr->re_lo = expr->re_hi = num;
887                 expr->re_stride = 1;
888                 cfs_list_add_tail(&expr->re_link, &numaddr->nar_range_exprs);
889                 return 1;
890         }
891
892         return parse_expr_list(&src, &numaddr->nar_range_exprs, min, max);
893 }
894
895 /**
896  * Nf_parse_addrlist method for networks using numeric addresses.
897  *
898  * Examples of such networks are gm and elan.
899  *
900  * \retval 1 if \a str parsed to numeric address
901  * \retval 0 otherwise
902  */
903 static int
904 libcfs_num_parse(char *str, int len, cfs_list_t *list)
905 {
906         return num_parse(str, len, list, 0, MAX_NUMERIC_VALUE);
907 }
908
909 /**
910  * Nf_parse_addrlist method for networks using ip addresses.
911  *
912  * Examples of such networks are tcp and o2ib.
913  *
914  * \retval 1 if \a str parsed to ip address
915  * \retval 0 otherwise
916  */
917 static int
918 libcfs_ip_parse(char *str, int len,
919                 cfs_list_t *list)
920 {
921         struct lstr src, res;
922         int i;
923
924         src.ls_str = str;
925         src.ls_len = len;
926         i = 0;
927         while (src.ls_str) {
928                 if (gettok(&src, '.', &res) == 0)
929                         return 0;
930                 if (!num_parse(res.ls_str, res.ls_len, list, 0, 255))
931                         return 0;
932                 i ++;
933         }
934
935         return (i == 4) ? 1 : 0;
936 }
937
938 /**
939  * Parses \<addrrange\> token on the syntax.
940  *
941  * Allocates struct addrrange and links to \a nidrange via
942  * (nidrange::nr_addrranges)
943  *
944  * \retval 1 if \a src parses to '*' | \<ipaddr_range\> | \<numaddr_range\>
945  * \retval 0 otherwise
946  */
947 static int
948 parse_addrange(const struct lstr *src, struct nidrange *nidrange)
949 {
950         struct addrrange *addrrange;
951
952         if (src->ls_len == 1 && src->ls_str[0] == '*') {
953                 nidrange->nr_all = 1;
954                 return 1;
955         }
956
957         LIBCFS_ALLOC(addrrange, sizeof(struct addrrange));
958         if (addrrange == NULL)
959                 return 0;
960         cfs_list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges);
961         CFS_INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges);
962
963         return nidrange->nr_netstrfns->nf_parse_addrlist(src->ls_str,
964                                                 src->ls_len,
965                                                 &addrrange->ar_numaddr_ranges);
966 }
967
968 /**
969  * Finds or creates struct nidrange.
970  *
971  * Checks if \a src is a valid network name, looks for corresponding
972  * nidrange on the ist of nidranges (\a nidlist), creates new struct
973  * nidrange if it is not found.
974  *
975  * \retval pointer to struct nidrange matching network specified via \a src
976  * \retval NULL if \a src does not match any network
977  */
978 static struct nidrange *
979 add_nidrange(const struct lstr *src,
980              cfs_list_t *nidlist)
981 {
982         struct netstrfns *nf;
983         struct nidrange *nr;
984         int endlen;
985         unsigned netnum;
986
987         if (src->ls_len >= LNET_NIDSTR_SIZE)
988                 return NULL;
989
990         nf = libcfs_namenum2netstrfns(src->ls_str);
991         if (nf == NULL)
992                 return NULL;
993         endlen = src->ls_len - strlen(nf->nf_name);
994         if (endlen == 0)
995                 /* network name only, e.g. "elan" or "tcp" */
996                 netnum = 0;
997         else {
998                 /* e.g. "elan25" or "tcp23", refuse to parse if
999                  * network name is not appended with decimal or
1000                  * hexadecimal number */
1001                 if (!libcfs_str2num_check(src->ls_str + strlen(nf->nf_name),
1002                                           endlen, &netnum,
1003                                           0, MAX_NUMERIC_VALUE))
1004                         return NULL;
1005         }
1006
1007         cfs_list_for_each_entry(nr, nidlist, nr_link) {
1008                 if (nr->nr_netstrfns != nf)
1009                         continue;
1010                 if (nr->nr_netnum != netnum)
1011                         continue;
1012                 return nr;
1013         }
1014
1015         LIBCFS_ALLOC(nr, sizeof(struct nidrange));
1016         if (nr == NULL)
1017                 return NULL;
1018         cfs_list_add_tail(&nr->nr_link, nidlist);
1019         CFS_INIT_LIST_HEAD(&nr->nr_addrranges);
1020         nr->nr_netstrfns = nf;
1021         nr->nr_all = 0;
1022         nr->nr_netnum = netnum;
1023
1024         return nr;
1025 }
1026
1027 /**
1028  * Parses \<nidrange\> token of the syntax.
1029  *
1030  * \retval 1 if \a src parses to \<addrrange\> '@' \<net\>
1031  * \retval 0 otherwise
1032  */
1033 static int
1034 parse_nidrange(struct lstr *src, cfs_list_t *nidlist)
1035 {
1036         struct lstr addrrange, net, tmp;
1037         struct nidrange *nr;
1038
1039         tmp = *src;
1040         if (gettok(src, '@', &addrrange) == 0)
1041                 goto failed;
1042
1043         if (gettok(src, '@', &net) == 0 || src->ls_str != NULL)
1044                 goto failed;
1045
1046         nr = add_nidrange(&net, nidlist);
1047         if (nr == NULL)
1048                 goto failed;
1049
1050         if (!parse_addrange(&addrrange, nr))
1051                 goto failed;
1052
1053         return 1;
1054  failed:
1055         CWARN("can't parse nidrange: \"%.*s\"\n", tmp.ls_len, tmp.ls_str);
1056         return 0;
1057 }
1058
1059 /**
1060  * Frees range_expr structures of \a list.
1061  *
1062  * \retval none
1063  */
1064 static void
1065 free_range_exprs(cfs_list_t *list)
1066 {
1067         cfs_list_t *pos, *next;
1068
1069         cfs_list_for_each_safe(pos, next, list) {
1070                 cfs_list_del(pos);
1071                 LIBCFS_FREE(cfs_list_entry(pos, struct range_expr, re_link),
1072                             sizeof(struct range_expr));
1073         }
1074 }
1075
1076 /**
1077  * Frees numaddr_range structures of \a list.
1078  *
1079  * For each struct numaddr_range structure found on \a list it frees
1080  * range_expr list attached to it and frees the numddr_range itself.
1081  *
1082  * \retval none
1083  */
1084 static void
1085 free_numaddr_ranges(cfs_list_t *list)
1086 {
1087         cfs_list_t *pos, *next;
1088         struct numaddr_range *numaddr;
1089
1090         cfs_list_for_each_safe(pos, next, list) {
1091                 numaddr = cfs_list_entry(pos, struct numaddr_range, nar_link);
1092                 free_range_exprs(&numaddr->nar_range_exprs);
1093                 cfs_list_del(pos);
1094                 LIBCFS_FREE(numaddr, sizeof(struct numaddr_range));
1095         }
1096 }
1097
1098 /**
1099  * Frees addrrange structures of \a list.
1100  *
1101  * For each struct addrrange structure found on \a list it frees
1102  * numaddr_range list attached to it and frees the addrrange itself.
1103  *
1104  * \retval none
1105  */
1106 static void
1107 free_addrranges(cfs_list_t *list)
1108 {
1109         cfs_list_t *pos, *next;
1110         struct addrrange *ar;
1111
1112         cfs_list_for_each_safe(pos, next, list) {
1113                 ar = cfs_list_entry(pos, struct addrrange, ar_link);
1114                 free_numaddr_ranges(&ar->ar_numaddr_ranges);
1115                 cfs_list_del(pos);
1116                 LIBCFS_FREE(ar, sizeof(struct addrrange));
1117         }
1118 }
1119
1120 /**
1121  * Frees nidrange strutures of \a list.
1122  *
1123  * For each struct nidrange structure found on \a list it frees
1124  * addrrange list attached to it and frees the nidrange itself.
1125  *
1126  * \retval none
1127  */
1128 void
1129 cfs_free_nidlist(cfs_list_t *list)
1130 {
1131         cfs_list_t *pos, *next;
1132         struct nidrange *nr;
1133
1134         cfs_list_for_each_safe(pos, next, list) {
1135                 nr = cfs_list_entry(pos, struct nidrange, nr_link);
1136                 free_addrranges(&nr->nr_addrranges);
1137                 cfs_list_del(pos);
1138                 LIBCFS_FREE(nr, sizeof(struct nidrange));
1139         }
1140 }
1141
1142 /**
1143  * Parses nid range list.
1144  *
1145  * Parses with rigorous syntax and overflow checking \a str into
1146  * \<nidrange\> [ ' ' \<nidrange\> ], compiles \a str into set of
1147  * structures and links that structure to \a nidlist. The resulting
1148  * list can be used to match a NID againts set of NIDS defined by \a
1149  * str.
1150  * \see cfs_match_nid
1151  *
1152  * \retval 1 on success
1153  * \retval 0 otherwise
1154  */
1155 int
1156 cfs_parse_nidlist(char *str, int len, cfs_list_t *nidlist)
1157 {
1158         struct lstr src, res;
1159         int rc;
1160         ENTRY;
1161
1162         src.ls_str = str;
1163         src.ls_len = len;
1164         CFS_INIT_LIST_HEAD(nidlist);
1165         while (src.ls_str) {
1166                 rc = gettok(&src, ' ', &res);
1167                 if (rc == 0) {
1168                         cfs_free_nidlist(nidlist);
1169                         RETURN(0);
1170                 }
1171                 rc = parse_nidrange(&res, nidlist);
1172                 if (rc == 0) {
1173                         cfs_free_nidlist(nidlist);
1174                         RETURN(0);
1175                 }
1176         }
1177         RETURN(1);
1178 }
1179
1180 /**
1181  * Matches address (\a addr) against address set encoded in \a list.
1182  *
1183  * \see libcfs_num_match(), libcfs_ip_match()
1184  *
1185  * \retval 1 if \a addr matches
1186  * \retval 0 otherwise
1187  */
1188 static int
1189 match_numaddr(__u32 addr, cfs_list_t *list, int shift, __u32 mask)
1190 {
1191         struct numaddr_range *numaddr;
1192         struct range_expr *expr;
1193         int ip, ok;
1194         ENTRY;
1195
1196         cfs_list_for_each_entry(numaddr, list, nar_link) {
1197                 ip = (addr >> shift) & mask;
1198                 shift -= 8;
1199                 ok = 0;
1200                 cfs_list_for_each_entry(expr, &numaddr->nar_range_exprs,
1201                                         re_link) {
1202                         if (ip >= expr->re_lo &&
1203                             ip <= expr->re_hi &&
1204                             ((ip - expr->re_lo) % expr->re_stride) == 0) {
1205                                 ok = 1;
1206                                 break;
1207                         }
1208                 }
1209                 if (!ok)
1210                         RETURN(0);
1211         }
1212         RETURN(1);
1213 }
1214
1215 /*
1216  * Nf_match_addr method for networks using numeric addresses
1217  *
1218  * \retval 1 on match
1219  * \retval 0 otherwise
1220  */
1221 static int
1222 libcfs_num_match(__u32 addr, cfs_list_t *numaddr)
1223 {
1224         return match_numaddr(addr, numaddr, 0, 0xffffffff);
1225 }
1226
1227 /*
1228  * Nf_match_addr method for networks using ip addresses
1229  *
1230  * \retval 1 on match
1231  * \retval 0 otherwise
1232  */
1233 static int
1234 libcfs_ip_match(__u32 addr, cfs_list_t *numaddr)
1235 {
1236         return match_numaddr(addr, numaddr, 24, 0xff);
1237 }
1238
1239 /**
1240  * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
1241  *
1242  * \see cfs_parse_nidlist()
1243  *
1244  * \retval 1 on match
1245  * \retval 0  otherwises
1246  */
1247 int cfs_match_nid(lnet_nid_t nid, cfs_list_t *nidlist)
1248 {
1249         struct nidrange *nr;
1250         struct addrrange *ar;
1251         ENTRY;
1252
1253         cfs_list_for_each_entry(nr, nidlist, nr_link) {
1254                 if (nr->nr_netstrfns->nf_type != LNET_NETTYP(LNET_NIDNET(nid)))
1255                         continue;
1256                 if (nr->nr_netnum != LNET_NETNUM(LNET_NIDNET(nid)))
1257                         continue;
1258                 if (nr->nr_all)
1259                         RETURN(1);
1260                 cfs_list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
1261                         if (nr->nr_netstrfns->nf_match_addr(LNET_NIDADDR(nid),
1262                                                        &ar->ar_numaddr_ranges))
1263                                 RETURN(1);
1264         }
1265         RETURN(0);
1266 }
1267
1268 #ifdef __KERNEL__
1269
1270 EXPORT_SYMBOL(libcfs_isknown_lnd);
1271 EXPORT_SYMBOL(libcfs_lnd2modname);
1272 EXPORT_SYMBOL(libcfs_lnd2str);
1273 EXPORT_SYMBOL(libcfs_str2lnd);
1274 EXPORT_SYMBOL(libcfs_net2str);
1275 EXPORT_SYMBOL(libcfs_nid2str);
1276 EXPORT_SYMBOL(libcfs_str2net);
1277 EXPORT_SYMBOL(libcfs_str2nid);
1278 EXPORT_SYMBOL(libcfs_id2str);
1279 EXPORT_SYMBOL(libcfs_str2anynid);
1280 EXPORT_SYMBOL(cfs_iswhite);
1281 EXPORT_SYMBOL(cfs_free_nidlist);
1282 EXPORT_SYMBOL(cfs_parse_nidlist);
1283 EXPORT_SYMBOL(cfs_match_nid);
1284
1285 #endif