]> Pileus Git - ~andy/linux/blob - drivers/staging/lustre/lustre/libcfs/nidstrings.c
Merge tag 'pci-v3.14-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaa...
[~andy/linux] / drivers / staging / lustre / lustre / libcfs / nidstrings.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2012, Intel Corporation.
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 #define DEBUG_SUBSYSTEM S_LNET
42
43 #include <linux/libcfs/libcfs.h>
44 #include <linux/lnet/lnet.h>
45
46 /* CAVEAT VENDITOR! Keep the canonical string representation of nets/nids
47  * consistent in all conversion functions.  Some code fragments are copied
48  * around for the sake of clarity...
49  */
50
51 /* CAVEAT EMPTOR! Racey temporary buffer allocation!
52  * Choose the number of nidstrings to support the MAXIMUM expected number of
53  * concurrent users.  If there are more, the returned string will be volatile.
54  * NB this number must allow for a process to be descheduled for a timeslice
55  * between getting its string and using it.
56  */
57
58 static char      libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE];
59 static int       libcfs_nidstring_idx;
60
61 static spinlock_t libcfs_nidstring_lock;
62
63 void libcfs_init_nidstrings(void)
64 {
65         spin_lock_init(&libcfs_nidstring_lock);
66 }
67
68 # define NIDSTR_LOCK(f)   spin_lock_irqsave(&libcfs_nidstring_lock, f)
69 # define NIDSTR_UNLOCK(f) spin_unlock_irqrestore(&libcfs_nidstring_lock, f)
70
71 static char *
72 libcfs_next_nidstring(void)
73 {
74         char      *str;
75         unsigned long  flags;
76
77         NIDSTR_LOCK(flags);
78
79         str = libcfs_nidstrings[libcfs_nidstring_idx++];
80         if (libcfs_nidstring_idx ==
81             sizeof(libcfs_nidstrings)/sizeof(libcfs_nidstrings[0]))
82                 libcfs_nidstring_idx = 0;
83
84         NIDSTR_UNLOCK(flags);
85         return str;
86 }
87
88 static int  libcfs_lo_str2addr(const char *str, int nob, __u32 *addr);
89 static void libcfs_ip_addr2str(__u32 addr, char *str);
90 static int  libcfs_ip_str2addr(const char *str, int nob, __u32 *addr);
91 static void libcfs_decnum_addr2str(__u32 addr, char *str);
92 static void libcfs_hexnum_addr2str(__u32 addr, char *str);
93 static int  libcfs_num_str2addr(const char *str, int nob, __u32 *addr);
94 static int  libcfs_num_parse(char *str, int len, struct list_head *list);
95 static int  libcfs_num_match(__u32 addr, struct list_head *list);
96
97 struct netstrfns {
98         int       nf_type;
99         char    *nf_name;
100         char    *nf_modname;
101         void       (*nf_addr2str)(__u32 addr, char *str);
102         int     (*nf_str2addr)(const char *str, int nob, __u32 *addr);
103         int     (*nf_parse_addrlist)(char *str, int len,
104                                         struct list_head *list);
105         int     (*nf_match_addr)(__u32 addr, struct list_head *list);
106 };
107
108 static struct netstrfns  libcfs_netstrfns[] = {
109         {/* .nf_type      */  LOLND,
110          /* .nf_name      */  "lo",
111          /* .nf_modname   */  "klolnd",
112          /* .nf_addr2str  */  libcfs_decnum_addr2str,
113          /* .nf_str2addr  */  libcfs_lo_str2addr,
114          /* .nf_parse_addr*/  libcfs_num_parse,
115          /* .nf_match_addr*/  libcfs_num_match},
116         {/* .nf_type      */  SOCKLND,
117          /* .nf_name      */  "tcp",
118          /* .nf_modname   */  "ksocklnd",
119          /* .nf_addr2str  */  libcfs_ip_addr2str,
120          /* .nf_str2addr  */  libcfs_ip_str2addr,
121          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
122          /* .nf_match_addr*/  cfs_ip_addr_match},
123         {/* .nf_type      */  O2IBLND,
124          /* .nf_name      */  "o2ib",
125          /* .nf_modname   */  "ko2iblnd",
126          /* .nf_addr2str  */  libcfs_ip_addr2str,
127          /* .nf_str2addr  */  libcfs_ip_str2addr,
128          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
129          /* .nf_match_addr*/  cfs_ip_addr_match},
130         {/* .nf_type      */  CIBLND,
131          /* .nf_name      */  "cib",
132          /* .nf_modname   */  "kciblnd",
133          /* .nf_addr2str  */  libcfs_ip_addr2str,
134          /* .nf_str2addr  */  libcfs_ip_str2addr,
135          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
136          /* .nf_match_addr*/  cfs_ip_addr_match},
137         {/* .nf_type      */  OPENIBLND,
138          /* .nf_name      */  "openib",
139          /* .nf_modname   */  "kopeniblnd",
140          /* .nf_addr2str  */  libcfs_ip_addr2str,
141          /* .nf_str2addr  */  libcfs_ip_str2addr,
142          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
143          /* .nf_match_addr*/  cfs_ip_addr_match},
144         {/* .nf_type      */  IIBLND,
145          /* .nf_name      */  "iib",
146          /* .nf_modname   */  "kiiblnd",
147          /* .nf_addr2str  */  libcfs_ip_addr2str,
148          /* .nf_str2addr  */  libcfs_ip_str2addr,
149          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
150          /* .nf_match_addr*/  cfs_ip_addr_match},
151         {/* .nf_type      */  VIBLND,
152          /* .nf_name      */  "vib",
153          /* .nf_modname   */  "kviblnd",
154          /* .nf_addr2str  */  libcfs_ip_addr2str,
155          /* .nf_str2addr  */  libcfs_ip_str2addr,
156          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
157          /* .nf_match_addr*/  cfs_ip_addr_match},
158         {/* .nf_type      */  RALND,
159          /* .nf_name      */  "ra",
160          /* .nf_modname   */  "kralnd",
161          /* .nf_addr2str  */  libcfs_ip_addr2str,
162          /* .nf_str2addr  */  libcfs_ip_str2addr,
163          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
164          /* .nf_match_addr*/  cfs_ip_addr_match},
165         {/* .nf_type      */  QSWLND,
166          /* .nf_name      */  "elan",
167          /* .nf_modname   */  "kqswlnd",
168          /* .nf_addr2str  */  libcfs_decnum_addr2str,
169          /* .nf_str2addr  */  libcfs_num_str2addr,
170          /* .nf_parse_addrlist*/  libcfs_num_parse,
171          /* .nf_match_addr*/  libcfs_num_match},
172         {/* .nf_type      */  GMLND,
173          /* .nf_name      */  "gm",
174          /* .nf_modname   */  "kgmlnd",
175          /* .nf_addr2str  */  libcfs_hexnum_addr2str,
176          /* .nf_str2addr  */  libcfs_num_str2addr,
177          /* .nf_parse_addrlist*/  libcfs_num_parse,
178          /* .nf_match_addr*/  libcfs_num_match},
179         {/* .nf_type      */  MXLND,
180          /* .nf_name      */  "mx",
181          /* .nf_modname   */  "kmxlnd",
182          /* .nf_addr2str  */  libcfs_ip_addr2str,
183          /* .nf_str2addr  */  libcfs_ip_str2addr,
184          /* .nf_parse_addrlist*/  cfs_ip_addr_parse,
185          /* .nf_match_addr*/  cfs_ip_addr_match},
186         {/* .nf_type      */  PTLLND,
187          /* .nf_name      */  "ptl",
188          /* .nf_modname   */  "kptllnd",
189          /* .nf_addr2str  */  libcfs_decnum_addr2str,
190          /* .nf_str2addr  */  libcfs_num_str2addr,
191          /* .nf_parse_addrlist*/  libcfs_num_parse,
192          /* .nf_match_addr*/  libcfs_num_match},
193         {/* .nf_type      */  GNILND,
194          /* .nf_name      */  "gni",
195          /* .nf_modname   */  "kgnilnd",
196          /* .nf_addr2str  */  libcfs_decnum_addr2str,
197          /* .nf_str2addr  */  libcfs_num_str2addr,
198          /* .nf_parse_addrlist*/  libcfs_num_parse,
199          /* .nf_match_addr*/  libcfs_num_match},
200         /* placeholder for net0 alias.  It MUST BE THE LAST ENTRY */
201         {/* .nf_type      */  -1},
202 };
203
204 const int libcfs_nnetstrfns = sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
205
206 int
207 libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
208 {
209         *addr = 0;
210         return 1;
211 }
212
213 void
214 libcfs_ip_addr2str(__u32 addr, char *str)
215 {
216 #if 0   /* never lookup */
217 #endif
218         snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u",
219                  (addr >> 24) & 0xff, (addr >> 16) & 0xff,
220                  (addr >> 8) & 0xff, addr & 0xff);
221 }
222
223 /* CAVEAT EMPTOR XscanfX
224  * I use "%n" at the end of a sscanf format to detect trailing junk.  However
225  * sscanf may return immediately if it sees the terminating '0' in a string, so
226  * I initialise the %n variable to the expected length.  If sscanf sets it;
227  * fine, if it doesn't, then the scan ended at the end of the string, which is
228  * fine too :) */
229
230 int
231 libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
232 {
233         int   a;
234         int   b;
235         int   c;
236         int   d;
237         int   n = nob;                    /* XscanfX */
238
239         /* numeric IP? */
240         if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
241             n == nob &&
242             (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
243             (c & ~0xff) == 0 && (d & ~0xff) == 0) {
244                 *addr = ((a<<24)|(b<<16)|(c<<8)|d);
245                 return 1;
246         }
247
248         return 0;
249 }
250
251 void
252 libcfs_decnum_addr2str(__u32 addr, char *str)
253 {
254         snprintf(str, LNET_NIDSTR_SIZE, "%u", addr);
255 }
256
257 void
258 libcfs_hexnum_addr2str(__u32 addr, char *str)
259 {
260         snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr);
261 }
262
263 int
264 libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
265 {
266         int     n;
267
268         n = nob;
269         if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
270                 return 1;
271
272         n = nob;
273         if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
274                 return 1;
275
276         n = nob;
277         if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
278                 return 1;
279
280         return 0;
281 }
282
283 struct netstrfns *
284 libcfs_lnd2netstrfns(int lnd)
285 {
286         int    i;
287
288         if (lnd >= 0)
289                 for (i = 0; i < libcfs_nnetstrfns; i++)
290                         if (lnd == libcfs_netstrfns[i].nf_type)
291                                 return &libcfs_netstrfns[i];
292
293         return NULL;
294 }
295
296 struct netstrfns *
297 libcfs_namenum2netstrfns(const char *name)
298 {
299         struct netstrfns *nf;
300         int            i;
301
302         for (i = 0; i < libcfs_nnetstrfns; i++) {
303                 nf = &libcfs_netstrfns[i];
304                 if (nf->nf_type >= 0 &&
305                     !strncmp(name, nf->nf_name, strlen(nf->nf_name)))
306                         return nf;
307         }
308         return NULL;
309 }
310
311 struct netstrfns *
312 libcfs_name2netstrfns(const char *name)
313 {
314         int    i;
315
316         for (i = 0; i < libcfs_nnetstrfns; i++)
317                 if (libcfs_netstrfns[i].nf_type >= 0 &&
318                     !strcmp(libcfs_netstrfns[i].nf_name, name))
319                         return &libcfs_netstrfns[i];
320
321         return NULL;
322 }
323
324 int
325 libcfs_isknown_lnd(int type)
326 {
327         return libcfs_lnd2netstrfns(type) != NULL;
328 }
329 EXPORT_SYMBOL(libcfs_isknown_lnd);
330
331 char *
332 libcfs_lnd2modname(int lnd)
333 {
334         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
335
336         return (nf == NULL) ? NULL : nf->nf_modname;
337 }
338 EXPORT_SYMBOL(libcfs_lnd2modname);
339
340 char *
341 libcfs_lnd2str(int lnd)
342 {
343         char       *str;
344         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
345
346         if (nf != NULL)
347                 return nf->nf_name;
348
349         str = libcfs_next_nidstring();
350         snprintf(str, LNET_NIDSTR_SIZE, "?%u?", lnd);
351         return str;
352 }
353 EXPORT_SYMBOL(libcfs_lnd2str);
354
355 int
356 libcfs_str2lnd(const char *str)
357 {
358         struct netstrfns *nf = libcfs_name2netstrfns(str);
359
360         if (nf != NULL)
361                 return nf->nf_type;
362
363         return -1;
364 }
365 EXPORT_SYMBOL(libcfs_str2lnd);
366
367 char *
368 libcfs_net2str(__u32 net)
369 {
370         int            lnd = LNET_NETTYP(net);
371         int            num = LNET_NETNUM(net);
372         struct netstrfns *nf  = libcfs_lnd2netstrfns(lnd);
373         char         *str = libcfs_next_nidstring();
374
375         if (nf == NULL)
376                 snprintf(str, LNET_NIDSTR_SIZE, "<%u:%u>", lnd, num);
377         else if (num == 0)
378                 snprintf(str, LNET_NIDSTR_SIZE, "%s", nf->nf_name);
379         else
380                 snprintf(str, LNET_NIDSTR_SIZE, "%s%u", nf->nf_name, num);
381
382         return str;
383 }
384 EXPORT_SYMBOL(libcfs_net2str);
385
386 char *
387 libcfs_nid2str(lnet_nid_t nid)
388 {
389         __u32        addr = LNET_NIDADDR(nid);
390         __u32        net = LNET_NIDNET(nid);
391         int            lnd = LNET_NETTYP(net);
392         int            nnum = LNET_NETNUM(net);
393         struct netstrfns *nf;
394         char         *str;
395         int            nob;
396
397         if (nid == LNET_NID_ANY)
398                 return "<?>";
399
400         nf = libcfs_lnd2netstrfns(lnd);
401         str = libcfs_next_nidstring();
402
403         if (nf == NULL)
404                 snprintf(str, LNET_NIDSTR_SIZE, "%x@<%u:%u>", addr, lnd, nnum);
405         else {
406                 nf->nf_addr2str(addr, str);
407                 nob = strlen(str);
408                 if (nnum == 0)
409                         snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s",
410                                  nf->nf_name);
411                 else
412                         snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s%u",
413                                  nf->nf_name, nnum);
414         }
415
416         return str;
417 }
418 EXPORT_SYMBOL(libcfs_nid2str);
419
420 static struct netstrfns *
421 libcfs_str2net_internal(const char *str, __u32 *net)
422 {
423         struct netstrfns *uninitialized_var(nf);
424         int            nob;
425         int            netnum;
426         int            i;
427
428         for (i = 0; i < libcfs_nnetstrfns; i++) {
429                 nf = &libcfs_netstrfns[i];
430                 if (nf->nf_type >= 0 &&
431                     !strncmp(str, nf->nf_name, strlen(nf->nf_name)))
432                         break;
433         }
434
435         if (i == libcfs_nnetstrfns)
436                 return NULL;
437
438         nob = strlen(nf->nf_name);
439
440         if (strlen(str) == (unsigned int)nob) {
441                 netnum = 0;
442         } else {
443                 if (nf->nf_type == LOLND) /* net number not allowed */
444                         return NULL;
445
446                 str += nob;
447                 i = strlen(str);
448                 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
449                     i != (int)strlen(str))
450                         return NULL;
451         }
452
453         *net = LNET_MKNET(nf->nf_type, netnum);
454         return nf;
455 }
456
457 __u32
458 libcfs_str2net(const char *str)
459 {
460         __u32  net;
461
462         if (libcfs_str2net_internal(str, &net) != NULL)
463                 return net;
464
465         return LNET_NIDNET(LNET_NID_ANY);
466 }
467 EXPORT_SYMBOL(libcfs_str2net);
468
469 lnet_nid_t
470 libcfs_str2nid(const char *str)
471 {
472         const char       *sep = strchr(str, '@');
473         struct netstrfns *nf;
474         __u32        net;
475         __u32        addr;
476
477         if (sep != NULL) {
478                 nf = libcfs_str2net_internal(sep + 1, &net);
479                 if (nf == NULL)
480                         return LNET_NID_ANY;
481         } else {
482                 sep = str + strlen(str);
483                 net = LNET_MKNET(SOCKLND, 0);
484                 nf = libcfs_lnd2netstrfns(SOCKLND);
485                 LASSERT(nf != NULL);
486         }
487
488         if (!nf->nf_str2addr(str, (int)(sep - str), &addr))
489                 return LNET_NID_ANY;
490
491         return LNET_MKNID(net, addr);
492 }
493 EXPORT_SYMBOL(libcfs_str2nid);
494
495 char *
496 libcfs_id2str(lnet_process_id_t id)
497 {
498         char *str = libcfs_next_nidstring();
499
500         if (id.pid == LNET_PID_ANY) {
501                 snprintf(str, LNET_NIDSTR_SIZE,
502                          "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
503                 return str;
504         }
505
506         snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
507                  ((id.pid & LNET_PID_USERFLAG) != 0) ? "U" : "",
508                  (id.pid & ~LNET_PID_USERFLAG), libcfs_nid2str(id.nid));
509         return str;
510 }
511 EXPORT_SYMBOL(libcfs_id2str);
512
513 int
514 libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
515 {
516         if (!strcmp(str, "*")) {
517                 *nidp = LNET_NID_ANY;
518                 return 1;
519         }
520
521         *nidp = libcfs_str2nid(str);
522         return *nidp != LNET_NID_ANY;
523 }
524 EXPORT_SYMBOL(libcfs_str2anynid);
525
526 /**
527  * Nid range list syntax.
528  * \verbatim
529  *
530  * <nidlist>     :== <nidrange> [ ' ' <nidrange> ]
531  * <nidrange>   :== <addrrange> '@' <net>
532  * <addrrange>       :== '*' |
533  *                     <ipaddr_range> |
534  *                       <cfs_expr_list>
535  * <ipaddr_range>    :== <cfs_expr_list>.<cfs_expr_list>.<cfs_expr_list>.
536  *                       <cfs_expr_list>
537  * <cfs_expr_list>   :== <number> |
538  *                     <expr_list>
539  * <expr_list>       :== '[' <range_expr> [ ',' <range_expr>] ']'
540  * <range_expr>      :== <number> |
541  *                     <number> '-' <number> |
542  *                     <number> '-' <number> '/' <number>
543  * <net>             :== <netname> | <netname><number>
544  * <netname>     :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" |
545  *                     "vib" | "ra" | "elan" | "mx" | "ptl"
546  * \endverbatim
547  */
548
549 /**
550  * Structure to represent \<nidrange\> token of the syntax.
551  *
552  * One of this is created for each \<net\> parsed.
553  */
554 struct nidrange {
555         /**
556          * Link to list of this structures which is built on nid range
557          * list parsing.
558          */
559         struct list_head nr_link;
560         /**
561          * List head for addrrange::ar_link.
562          */
563         struct list_head nr_addrranges;
564         /**
565          * Flag indicating that *@<net> is found.
566          */
567         int nr_all;
568         /**
569          * Pointer to corresponding element of libcfs_netstrfns.
570          */
571         struct netstrfns *nr_netstrfns;
572         /**
573          * Number of network. E.g. 5 if \<net\> is "elan5".
574          */
575         int nr_netnum;
576 };
577
578 /**
579  * Structure to represent \<addrrange\> token of the syntax.
580  */
581 struct addrrange {
582         /**
583          * Link to nidrange::nr_addrranges.
584          */
585         struct list_head ar_link;
586         /**
587          * List head for cfs_expr_list::el_list.
588          */
589         struct list_head ar_numaddr_ranges;
590 };
591
592 /**
593  * Nf_parse_addrlist method for networks using numeric addresses.
594  *
595  * Examples of such networks are gm and elan.
596  *
597  * \retval 0 if \a str parsed to numeric address
598  * \retval errno otherwise
599  */
600 static int
601 libcfs_num_parse(char *str, int len, struct list_head *list)
602 {
603         struct cfs_expr_list *el;
604         int     rc;
605
606         rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
607         if (rc == 0)
608                 list_add_tail(&el->el_link, list);
609
610         return rc;
611 }
612
613 /**
614  * Parses \<addrrange\> token on the syntax.
615  *
616  * Allocates struct addrrange and links to \a nidrange via
617  * (nidrange::nr_addrranges)
618  *
619  * \retval 1 if \a src parses to '*' | \<ipaddr_range\> | \<cfs_expr_list\>
620  * \retval 0 otherwise
621  */
622 static int
623 parse_addrange(const struct cfs_lstr *src, struct nidrange *nidrange)
624 {
625         struct addrrange *addrrange;
626
627         if (src->ls_len == 1 && src->ls_str[0] == '*') {
628                 nidrange->nr_all = 1;
629                 return 1;
630         }
631
632         LIBCFS_ALLOC(addrrange, sizeof(struct addrrange));
633         if (addrrange == NULL)
634                 return 0;
635         list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges);
636         INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges);
637
638         return nidrange->nr_netstrfns->nf_parse_addrlist(src->ls_str,
639                                                 src->ls_len,
640                                                 &addrrange->ar_numaddr_ranges);
641 }
642
643 /**
644  * Finds or creates struct nidrange.
645  *
646  * Checks if \a src is a valid network name, looks for corresponding
647  * nidrange on the ist of nidranges (\a nidlist), creates new struct
648  * nidrange if it is not found.
649  *
650  * \retval pointer to struct nidrange matching network specified via \a src
651  * \retval NULL if \a src does not match any network
652  */
653 static struct nidrange *
654 add_nidrange(const struct cfs_lstr *src,
655              struct list_head *nidlist)
656 {
657         struct netstrfns *nf;
658         struct nidrange *nr;
659         int endlen;
660         unsigned netnum;
661
662         if (src->ls_len >= LNET_NIDSTR_SIZE)
663                 return NULL;
664
665         nf = libcfs_namenum2netstrfns(src->ls_str);
666         if (nf == NULL)
667                 return NULL;
668         endlen = src->ls_len - strlen(nf->nf_name);
669         if (endlen == 0)
670                 /* network name only, e.g. "elan" or "tcp" */
671                 netnum = 0;
672         else {
673                 /* e.g. "elan25" or "tcp23", refuse to parse if
674                  * network name is not appended with decimal or
675                  * hexadecimal number */
676                 if (!cfs_str2num_check(src->ls_str + strlen(nf->nf_name),
677                                        endlen, &netnum, 0, MAX_NUMERIC_VALUE))
678                         return NULL;
679         }
680
681         list_for_each_entry(nr, nidlist, nr_link) {
682                 if (nr->nr_netstrfns != nf)
683                         continue;
684                 if (nr->nr_netnum != netnum)
685                         continue;
686                 return nr;
687         }
688
689         LIBCFS_ALLOC(nr, sizeof(struct nidrange));
690         if (nr == NULL)
691                 return NULL;
692         list_add_tail(&nr->nr_link, nidlist);
693         INIT_LIST_HEAD(&nr->nr_addrranges);
694         nr->nr_netstrfns = nf;
695         nr->nr_all = 0;
696         nr->nr_netnum = netnum;
697
698         return nr;
699 }
700
701 /**
702  * Parses \<nidrange\> token of the syntax.
703  *
704  * \retval 1 if \a src parses to \<addrrange\> '@' \<net\>
705  * \retval 0 otherwise
706  */
707 static int
708 parse_nidrange(struct cfs_lstr *src, struct list_head *nidlist)
709 {
710         struct cfs_lstr addrrange;
711         struct cfs_lstr net;
712         struct cfs_lstr tmp;
713         struct nidrange *nr;
714
715         tmp = *src;
716         if (cfs_gettok(src, '@', &addrrange) == 0)
717                 goto failed;
718
719         if (cfs_gettok(src, '@', &net) == 0 || src->ls_str != NULL)
720                 goto failed;
721
722         nr = add_nidrange(&net, nidlist);
723         if (nr == NULL)
724                 goto failed;
725
726         if (parse_addrange(&addrrange, nr) != 0)
727                 goto failed;
728
729         return 1;
730  failed:
731         CWARN("can't parse nidrange: \"%.*s\"\n", tmp.ls_len, tmp.ls_str);
732         return 0;
733 }
734
735 /**
736  * Frees addrrange structures of \a list.
737  *
738  * For each struct addrrange structure found on \a list it frees
739  * cfs_expr_list list attached to it and frees the addrrange itself.
740  *
741  * \retval none
742  */
743 static void
744 free_addrranges(struct list_head *list)
745 {
746         while (!list_empty(list)) {
747                 struct addrrange *ar;
748
749                 ar = list_entry(list->next, struct addrrange, ar_link);
750
751                 cfs_expr_list_free_list(&ar->ar_numaddr_ranges);
752                 list_del(&ar->ar_link);
753                 LIBCFS_FREE(ar, sizeof(struct addrrange));
754         }
755 }
756
757 /**
758  * Frees nidrange strutures of \a list.
759  *
760  * For each struct nidrange structure found on \a list it frees
761  * addrrange list attached to it and frees the nidrange itself.
762  *
763  * \retval none
764  */
765 void
766 cfs_free_nidlist(struct list_head *list)
767 {
768         struct list_head *pos, *next;
769         struct nidrange *nr;
770
771         list_for_each_safe(pos, next, list) {
772                 nr = list_entry(pos, struct nidrange, nr_link);
773                 free_addrranges(&nr->nr_addrranges);
774                 list_del(pos);
775                 LIBCFS_FREE(nr, sizeof(struct nidrange));
776         }
777 }
778 EXPORT_SYMBOL(cfs_free_nidlist);
779
780 /**
781  * Parses nid range list.
782  *
783  * Parses with rigorous syntax and overflow checking \a str into
784  * \<nidrange\> [ ' ' \<nidrange\> ], compiles \a str into set of
785  * structures and links that structure to \a nidlist. The resulting
786  * list can be used to match a NID againts set of NIDS defined by \a
787  * str.
788  * \see cfs_match_nid
789  *
790  * \retval 1 on success
791  * \retval 0 otherwise
792  */
793 int
794 cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
795 {
796         struct cfs_lstr src;
797         struct cfs_lstr res;
798         int rc;
799
800         src.ls_str = str;
801         src.ls_len = len;
802         INIT_LIST_HEAD(nidlist);
803         while (src.ls_str) {
804                 rc = cfs_gettok(&src, ' ', &res);
805                 if (rc == 0) {
806                         cfs_free_nidlist(nidlist);
807                         return 0;
808                 }
809                 rc = parse_nidrange(&res, nidlist);
810                 if (rc == 0) {
811                         cfs_free_nidlist(nidlist);
812                         return 0;
813                 }
814         }
815         return 1;
816 }
817 EXPORT_SYMBOL(cfs_parse_nidlist);
818
819 /*
820  * Nf_match_addr method for networks using numeric addresses
821  *
822  * \retval 1 on match
823  * \retval 0 otherwise
824  */
825 static int
826 libcfs_num_match(__u32 addr, struct list_head *numaddr)
827 {
828         struct cfs_expr_list *el;
829
830         LASSERT(!list_empty(numaddr));
831         el = list_entry(numaddr->next, struct cfs_expr_list, el_link);
832
833         return cfs_expr_list_match(addr, el);
834 }
835
836 /**
837  * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
838  *
839  * \see cfs_parse_nidlist()
840  *
841  * \retval 1 on match
842  * \retval 0  otherwises
843  */
844 int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist)
845 {
846         struct nidrange *nr;
847         struct addrrange *ar;
848
849         list_for_each_entry(nr, nidlist, nr_link) {
850                 if (nr->nr_netstrfns->nf_type != LNET_NETTYP(LNET_NIDNET(nid)))
851                         continue;
852                 if (nr->nr_netnum != LNET_NETNUM(LNET_NIDNET(nid)))
853                         continue;
854                 if (nr->nr_all)
855                         return 1;
856                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
857                         if (nr->nr_netstrfns->nf_match_addr(LNET_NIDADDR(nid),
858                                                        &ar->ar_numaddr_ranges))
859                                 return 1;
860         }
861         return 0;
862 }
863 EXPORT_SYMBOL(cfs_match_nid);