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