Whamcloud - gitweb
LU-12682 llite: fake symlink type of foreign file/dir
[fs/lustre-release.git] / libcfs / libcfs / util / nidstrings.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * libcfs/libcfs/util/nidstrings.c
33  *
34  * Author: Phil Schwan <phil@clusterfs.com>
35  */
36
37 #define DEBUG_SUBSYSTEM S_LNET
38
39 #include <assert.h>
40 #include <errno.h>
41 #include <stdio.h>
42 #include <stdbool.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include <libcfs/util/string.h>
47 #include <linux/lnet/lnet-types.h>
48 #include <linux/lnet/nidstr.h>
49 #ifdef HAVE_NETDB_H
50 # include <netdb.h>
51 #endif
52
53 /* max value for numeric network address */
54 #define MAX_NUMERIC_VALUE 0xffffffff
55
56 #define IPSTRING_LENGTH 16
57
58 /* CAVEAT VENDITOR! Keep the canonical string representation of nets/nids
59  * consistent in all conversion functions.  Some code fragments are copied
60  * around for the sake of clarity...
61  */
62
63 /* CAVEAT EMPTOR! Racey temporary buffer allocation!
64  * Choose the number of nidstrings to support the MAXIMUM expected number of
65  * concurrent users.  If there are more, the returned string will be volatile.
66  * NB this number must allow for a process to be descheduled for a timeslice
67  * between getting its string and using it.
68  */
69
70 static char      libcfs_nidstrings[LNET_NIDSTR_COUNT][LNET_NIDSTR_SIZE];
71 static int       libcfs_nidstring_idx;
72
73 char *
74 libcfs_next_nidstring(void)
75 {
76         char          *str;
77
78         str = libcfs_nidstrings[libcfs_nidstring_idx++];
79         if (libcfs_nidstring_idx ==
80             sizeof(libcfs_nidstrings)/sizeof(libcfs_nidstrings[0]))
81                 libcfs_nidstring_idx = 0;
82
83         return str;
84 }
85
86 static int
87 libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
88 {
89         *addr = 0;
90         return 1;
91 }
92
93 static void
94 libcfs_ip_addr2str(__u32 addr, char *str, size_t size)
95 {
96         snprintf(str, size, "%u.%u.%u.%u",
97                  (addr >> 24) & 0xff, (addr >> 16) & 0xff,
98                  (addr >> 8) & 0xff, addr & 0xff);
99 }
100
101 /* CAVEAT EMPTOR XscanfX
102  * I use "%n" at the end of a sscanf format to detect trailing junk.  However
103  * sscanf may return immediately if it sees the terminating '0' in a string, so
104  * I initialise the %n variable to the expected length.  If sscanf sets it;
105  * fine, if it doesn't, then the scan ended at the end of the string, which is
106  * fine too :) */
107 static int
108 libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
109 {
110         unsigned int    a;
111         unsigned int    b;
112         unsigned int    c;
113         unsigned int    d;
114         int             n = nob; /* XscanfX */
115
116         /* numeric IP? */
117         if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
118             n == nob &&
119             (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
120             (c & ~0xff) == 0 && (d & ~0xff) == 0) {
121                 *addr = ((a<<24)|(b<<16)|(c<<8)|d);
122                 return 1;
123         }
124
125 #ifdef HAVE_GETHOSTBYNAME
126         /* known hostname? */
127         if (('a' <= str[0] && str[0] <= 'z') ||
128             ('A' <= str[0] && str[0] <= 'Z')) {
129                 char *tmp;
130
131                 tmp = calloc(1, nob + 1);
132                 if (tmp != NULL) {
133                         struct hostent *he;
134
135                         memcpy(tmp, str, nob);
136                         tmp[nob] = 0;
137
138                         he = gethostbyname(tmp);
139
140                         free(tmp);
141
142                         if (he != NULL) {
143                                 __u32 ip = *(__u32 *)he->h_addr;
144
145                                 *addr = ntohl(ip);
146                                 return 1;
147                         }
148                 }
149         }
150 #endif
151         return 0;
152 }
153
154 int
155 cfs_ip_addr_parse(char *str, int len, struct list_head *list)
156 {
157         struct cfs_expr_list *el;
158         struct cfs_lstr src;
159         int rc;
160         int i;
161
162         src.ls_str = str;
163         src.ls_len = len;
164         i = 0;
165
166         while (src.ls_str != NULL) {
167                 struct cfs_lstr res;
168
169                 if (!cfs_gettok(&src, '.', &res)) {
170                         rc = -EINVAL;
171                         goto out;
172                 }
173
174                 rc = cfs_expr_list_parse(res.ls_str, res.ls_len, 0, 255, &el);
175                 if (rc != 0)
176                         goto out;
177
178                 list_add_tail(&el->el_link, list);
179                 i++;
180         }
181
182         if (i == 4)
183                 return 0;
184
185         rc = -EINVAL;
186 out:
187         cfs_expr_list_free_list(list);
188
189         return rc;
190 }
191
192 static int
193 libcfs_num_addr_range_expand(struct list_head *addrranges, __u32 *addrs,
194                              int max_addrs)
195 {
196         struct cfs_expr_list *expr_list;
197         struct cfs_range_expr *range;
198         int i;
199         int max_idx = max_addrs - 1;
200         int addrs_idx = max_idx;
201
202         list_for_each_entry(expr_list, addrranges, el_link) {
203                 list_for_each_entry(range, &expr_list->el_exprs, re_link) {
204                         for (i = range->re_lo; i <= range->re_hi;
205                              i += range->re_stride) {
206                                 if (addrs_idx < 0)
207                                         return -1;
208
209                                 addrs[addrs_idx] = i;
210                                 addrs_idx--;
211                         }
212                 }
213         }
214
215         return max_idx - addrs_idx;
216 }
217
218 static int
219 libcfs_ip_addr_range_expand(struct list_head *addrranges, __u32 *addrs,
220                             int max_addrs)
221 {
222         int rc = 0;
223
224         rc = cfs_ip_addr_range_gen(addrs, max_addrs, addrranges);
225
226         if (rc == -1)
227                 return rc;
228         else
229                 return max_addrs - rc - 1;
230 }
231
232 static int
233 libcfs_ip_addr_range_print(char *buffer, int count, struct list_head *list)
234 {
235         int i = 0, j = 0;
236         struct cfs_expr_list *el;
237
238         list_for_each_entry(el, list, el_link) {
239                 assert(j++ < 4);
240                 if (i != 0)
241                         i += scnprintf(buffer + i, count - i, ".");
242                 i += cfs_expr_list_print(buffer + i, count - i, el);
243         }
244         return i;
245 }
246
247 static int
248 cfs_ip_addr_range_gen_recurse(__u32 *ip_list, int *count, int shift,
249                               __u32 result, struct list_head *head_el,
250                               struct cfs_expr_list *octet_el)
251 {
252         __u32 value = 0;
253         int i;
254         struct cfs_expr_list *next_octet_el;
255         struct cfs_range_expr *octet_expr;
256
257         /*
258          * each octet can have multiple expressions so we need to traverse
259          * all of the expressions
260          */
261         list_for_each_entry(octet_expr, &octet_el->el_exprs, re_link) {
262                 for (i = octet_expr->re_lo; i <= octet_expr->re_hi; i++) {
263                         if (((i - octet_expr->re_lo) % octet_expr->re_stride) == 0) {
264                                 /*
265                                  * we have a hit calculate the result and
266                                  * pass it forward to the next iteration
267                                  * of the recursion.
268                                  */
269                                 next_octet_el =
270                                         list_entry(octet_el->el_link.next,
271                                                         typeof(*next_octet_el),
272                                                         el_link);
273                                 value = result | (i << (shift * 8));
274                                 if (next_octet_el->el_link.next != head_el) {
275                                         /*
276                                          * We still have more octets in
277                                          * the IP address so traverse
278                                          * that. We're doing a depth first
279                                          * recursion here.
280                                          */
281                                         if (cfs_ip_addr_range_gen_recurse(ip_list, count,
282                                                                           shift - 1, value,
283                                                                           head_el,
284                                                                           next_octet_el) == -1)
285                                                 return -1;
286                                 } else {
287                                         /*
288                                          * We have hit a leaf so store the
289                                          * calculated IP address in the
290                                          * list. If we have run out of
291                                          * space stop the recursion.
292                                          */
293                                         if (*count == -1)
294                                                 return -1;
295                                         /* add ip to the list */
296                                         ip_list[*count] = value;
297                                         (*count)--;
298                                 }
299                         }
300                 }
301         }
302         return 0;
303 }
304
305 /*
306  * only generate maximum of count ip addresses from the given expression
307  */
308 int
309 cfs_ip_addr_range_gen(__u32 *ip_list, int count, struct list_head *ip_addr_expr)
310 {
311         struct cfs_expr_list *octet_el;
312         int idx = count - 1;
313
314         octet_el = list_entry(ip_addr_expr->next, typeof(*octet_el), el_link);
315
316         (void) cfs_ip_addr_range_gen_recurse(ip_list, &idx, 3, 0, &octet_el->el_link, octet_el);
317
318         return idx;
319 }
320
321 /**
322  * Matches address (\a addr) against address set encoded in \a list.
323  *
324  * \retval 1 if \a addr matches
325  * \retval 0 otherwise
326  */
327 int
328 cfs_ip_addr_match(__u32 addr, struct list_head *list)
329 {
330         struct cfs_expr_list *el;
331         int i = 0;
332
333         list_for_each_entry_reverse(el, list, el_link) {
334                 if (!cfs_expr_list_match(addr & 0xff, el))
335                         return 0;
336                 addr >>= 8;
337                 i++;
338         }
339
340         return i == 4;
341 }
342
343 static void
344 libcfs_decnum_addr2str(__u32 addr, char *str, size_t size)
345 {
346         snprintf(str, size, "%u", addr);
347 }
348
349 static int
350 libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
351 {
352         int     n;
353
354         n = nob;
355         if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
356                 return 1;
357
358         n = nob;
359         if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
360                 return 1;
361
362         n = nob;
363         if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
364                 return 1;
365
366         return 0;
367 }
368
369 /**
370  * Nf_parse_addrlist method for networks using numeric addresses.
371  *
372  * Examples of such networks are gm and elan.
373  *
374  * \retval 0 if \a str parsed to numeric address
375  * \retval errno otherwise
376  */
377 static int
378 libcfs_num_parse(char *str, int len, struct list_head *list)
379 {
380         struct cfs_expr_list *el;
381         int     rc;
382
383         rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
384         if (rc == 0)
385                 list_add_tail(&el->el_link, list);
386
387         return rc;
388 }
389
390 static int
391 libcfs_num_addr_range_print(char *buffer, int count, struct list_head *list)
392 {
393         struct cfs_expr_list *el;
394         int i = 0, j = 0;
395
396         list_for_each_entry(el, list, el_link) {
397                 assert(j++ < 1);
398                 i += cfs_expr_list_print(buffer + i, count - i, el);
399         }
400         return i;
401 }
402
403 /*
404  * Nf_match_addr method for networks using numeric addresses
405  *
406  * \retval 1 on match
407  * \retval 0 otherwise
408  */
409 static int
410 libcfs_num_match(__u32 addr, struct list_head *numaddr)
411 {
412         struct cfs_expr_list *el;
413
414         assert(!list_empty(numaddr));
415         el = list_entry(numaddr->next, struct cfs_expr_list, el_link);
416
417         return cfs_expr_list_match(addr, el);
418 }
419
420 static int cfs_ip_min_max(struct list_head *nidlist, __u32 *min, __u32 *max);
421 static int cfs_num_min_max(struct list_head *nidlist, __u32 *min, __u32 *max);
422
423 static struct netstrfns libcfs_netstrfns[] = {
424         {
425                 .nf_type                = LOLND,
426                 .nf_name                = "lo",
427                 .nf_modname             = "klolnd",
428                 .nf_addr2str            = libcfs_decnum_addr2str,
429                 .nf_str2addr            = libcfs_lo_str2addr,
430                 .nf_parse_addrlist      = libcfs_num_parse,
431                 .nf_print_addrlist      = libcfs_num_addr_range_print,
432                 .nf_match_addr          = libcfs_num_match,
433                 .nf_min_max             = cfs_num_min_max,
434                 .nf_expand_addrrange    = libcfs_num_addr_range_expand
435         },
436         {
437                 .nf_type                = SOCKLND,
438                 .nf_name                = "tcp",
439                 .nf_modname             = "ksocklnd",
440                 .nf_addr2str            = libcfs_ip_addr2str,
441                 .nf_str2addr            = libcfs_ip_str2addr,
442                 .nf_parse_addrlist      = cfs_ip_addr_parse,
443                 .nf_print_addrlist      = libcfs_ip_addr_range_print,
444                 .nf_match_addr          = cfs_ip_addr_match,
445                 .nf_min_max             = cfs_ip_min_max,
446                 .nf_expand_addrrange    = libcfs_ip_addr_range_expand
447         },
448         {
449                 .nf_type                = O2IBLND,
450                 .nf_name                = "o2ib",
451                 .nf_modname             = "ko2iblnd",
452                 .nf_addr2str            = libcfs_ip_addr2str,
453                 .nf_str2addr            = libcfs_ip_str2addr,
454                 .nf_parse_addrlist      = cfs_ip_addr_parse,
455                 .nf_print_addrlist      = libcfs_ip_addr_range_print,
456                 .nf_match_addr          = cfs_ip_addr_match,
457                 .nf_min_max             = cfs_ip_min_max,
458                 .nf_expand_addrrange    = libcfs_ip_addr_range_expand
459         },
460         {
461                 .nf_type                = GNILND,
462                 .nf_name                = "gni",
463                 .nf_modname             = "kgnilnd",
464                 .nf_addr2str            = libcfs_decnum_addr2str,
465                 .nf_str2addr            = libcfs_num_str2addr,
466                 .nf_parse_addrlist      = libcfs_num_parse,
467                 .nf_print_addrlist      = libcfs_num_addr_range_print,
468                 .nf_match_addr          = libcfs_num_match,
469                 .nf_min_max             = cfs_num_min_max,
470                 .nf_expand_addrrange    = libcfs_num_addr_range_expand
471         },
472         {
473                 .nf_type                = GNIIPLND,
474                 .nf_name                = "gip",
475                 .nf_modname             = "kgnilnd",
476                 .nf_addr2str            = libcfs_ip_addr2str,
477                 .nf_str2addr            = libcfs_ip_str2addr,
478                 .nf_parse_addrlist      = cfs_ip_addr_parse,
479                 .nf_print_addrlist      = libcfs_ip_addr_range_print,
480                 .nf_match_addr          = cfs_ip_addr_match,
481                 .nf_min_max             = cfs_ip_min_max,
482                 .nf_expand_addrrange    = libcfs_ip_addr_range_expand
483         },
484         {
485                 .nf_type                = PTL4LND,
486                 .nf_name                = "ptlf",
487                 .nf_modname             = "kptl4lnd",
488                 .nf_addr2str            = libcfs_decnum_addr2str,
489                 .nf_str2addr            = libcfs_num_str2addr,
490                 .nf_parse_addrlist      = libcfs_num_parse,
491                 .nf_print_addrlist      = libcfs_num_addr_range_print,
492                 .nf_match_addr          = libcfs_num_match,
493                 .nf_min_max             = cfs_num_min_max,
494                 .nf_expand_addrrange    = libcfs_num_addr_range_expand
495         }
496 };
497
498 static const size_t libcfs_nnetstrfns =
499         sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
500
501 static struct netstrfns *
502 libcfs_lnd2netstrfns(__u32 lnd)
503 {
504         int     i;
505
506         for (i = 0; i < libcfs_nnetstrfns; i++)
507                 if (lnd == libcfs_netstrfns[i].nf_type)
508                         return &libcfs_netstrfns[i];
509
510         return NULL;
511 }
512
513 static struct netstrfns *
514 libcfs_namenum2netstrfns(const char *name)
515 {
516         struct netstrfns *nf;
517         int               i;
518
519         for (i = 0; i < libcfs_nnetstrfns; i++) {
520                 nf = &libcfs_netstrfns[i];
521                 if (!strncmp(name, nf->nf_name, strlen(nf->nf_name)))
522                         return nf;
523         }
524         return NULL;
525 }
526
527 static struct netstrfns *
528 libcfs_name2netstrfns(const char *name)
529 {
530         int    i;
531
532         for (i = 0; i < libcfs_nnetstrfns; i++)
533                 if (!strcmp(libcfs_netstrfns[i].nf_name, name))
534                         return &libcfs_netstrfns[i];
535
536         return NULL;
537 }
538
539 int
540 libcfs_isknown_lnd(__u32 lnd)
541 {
542         return libcfs_lnd2netstrfns(lnd) != NULL;
543 }
544
545 char *
546 libcfs_lnd2modname(__u32 lnd)
547 {
548         struct netstrfns *nf = libcfs_lnd2netstrfns(lnd);
549
550         return (nf == NULL) ? NULL : nf->nf_modname;
551 }
552
553 int
554 libcfs_str2lnd(const char *str)
555 {
556         struct netstrfns *nf = libcfs_name2netstrfns(str);
557
558         if (nf != NULL)
559                 return nf->nf_type;
560
561         return -1;
562 }
563
564 char *
565 libcfs_lnd2str_r(__u32 lnd, char *buf, size_t buf_size)
566 {
567         struct netstrfns *nf;
568
569         nf = libcfs_lnd2netstrfns(lnd);
570         if (nf == NULL)
571                 snprintf(buf, buf_size, "?%u?", lnd);
572         else
573                 snprintf(buf, buf_size, "%s", nf->nf_name);
574
575         return buf;
576 }
577
578 char *
579 libcfs_net2str_r(__u32 net, char *buf, size_t buf_size)
580 {
581         __u32             nnum = LNET_NETNUM(net);
582         __u32             lnd  = LNET_NETTYP(net);
583         struct netstrfns *nf;
584
585         nf = libcfs_lnd2netstrfns(lnd);
586         if (nf == NULL)
587                 snprintf(buf, buf_size, "<%u:%u>", lnd, nnum);
588         else if (nnum == 0)
589                 snprintf(buf, buf_size, "%s", nf->nf_name);
590         else
591                 snprintf(buf, buf_size, "%s%u", nf->nf_name, nnum);
592
593         return buf;
594 }
595
596 char *
597 libcfs_nid2str_r(lnet_nid_t nid, char *buf, size_t buf_size)
598 {
599         __u32             addr = LNET_NIDADDR(nid);
600         __u32             net  = LNET_NIDNET(nid);
601         __u32             nnum = LNET_NETNUM(net);
602         __u32             lnd  = LNET_NETTYP(net);
603         struct netstrfns *nf;
604
605         if (nid == LNET_NID_ANY) {
606                 strncpy(buf, "<?>", buf_size);
607                 buf[buf_size - 1] = '\0';
608                 return buf;
609         }
610
611         nf = libcfs_lnd2netstrfns(lnd);
612         if (nf == NULL) {
613                 snprintf(buf, buf_size, "%x@<%u:%u>", addr, lnd, nnum);
614         } else {
615                 size_t addr_len;
616
617                 nf->nf_addr2str(addr, buf, buf_size);
618                 addr_len = strlen(buf);
619                 if (nnum == 0)
620                         snprintf(buf + addr_len, buf_size - addr_len, "@%s",
621                                  nf->nf_name);
622                 else
623                         snprintf(buf + addr_len, buf_size - addr_len, "@%s%u",
624                                  nf->nf_name, nnum);
625         }
626
627         return buf;
628 }
629
630 static struct netstrfns *
631 libcfs_str2net_internal(const char *str, __u32 *net)
632 {
633         struct netstrfns *nf = NULL;
634         int               nob;
635         unsigned int      netnum;
636         int               i;
637
638         for (i = 0; i < libcfs_nnetstrfns; i++) {
639                 nf = &libcfs_netstrfns[i];
640                 if (!strncmp(str, nf->nf_name, strlen(nf->nf_name)))
641                         break;
642         }
643
644         if (i == libcfs_nnetstrfns)
645                 return NULL;
646
647         nob = strlen(nf->nf_name);
648
649         if (strlen(str) == (unsigned int)nob) {
650                 netnum = 0;
651         } else {
652                 if (nf->nf_type == LOLND) /* net number not allowed */
653                         return NULL;
654
655                 str += nob;
656                 i = strlen(str);
657                 if (sscanf(str, "%u%n", &netnum, &i) < 1 ||
658                     i != (int)strlen(str))
659                         return NULL;
660         }
661
662         *net = LNET_MKNET(nf->nf_type, netnum);
663         return nf;
664 }
665
666 __u32
667 libcfs_str2net(const char *str)
668 {
669         __u32  net;
670
671         if (libcfs_str2net_internal(str, &net) != NULL)
672                 return net;
673
674         return LNET_NET_ANY;
675 }
676
677 lnet_nid_t
678 libcfs_str2nid(const char *str)
679 {
680         const char       *sep = strchr(str, '@');
681         struct netstrfns *nf;
682         __u32             net;
683         __u32             addr;
684
685         if (sep != NULL) {
686                 nf = libcfs_str2net_internal(sep + 1, &net);
687                 if (nf == NULL)
688                         return LNET_NID_ANY;
689         } else {
690                 sep = str + strlen(str);
691                 net = LNET_MKNET(SOCKLND, 0);
692                 nf = libcfs_lnd2netstrfns(SOCKLND);
693                 assert(nf != NULL);
694         }
695
696         if (!nf->nf_str2addr(str, (int)(sep - str), &addr))
697                 return LNET_NID_ANY;
698
699         return LNET_MKNID(net, addr);
700 }
701
702 char *
703 libcfs_id2str(struct lnet_process_id id)
704 {
705         char *str = libcfs_next_nidstring();
706
707         if (id.pid == LNET_PID_ANY) {
708                 snprintf(str, LNET_NIDSTR_SIZE,
709                          "LNET_PID_ANY-%s", libcfs_nid2str(id.nid));
710                 return str;
711         }
712
713         snprintf(str, LNET_NIDSTR_SIZE, "%s%u-%s",
714                  ((id.pid & LNET_PID_USERFLAG) != 0) ? "U" : "",
715                  (id.pid & ~LNET_PID_USERFLAG), libcfs_nid2str(id.nid));
716         return str;
717 }
718
719 int
720 libcfs_str2anynid(lnet_nid_t *nidp, const char *str)
721 {
722         if (!strcmp(str, "*")) {
723                 *nidp = LNET_NID_ANY;
724                 return 1;
725         }
726
727         *nidp = libcfs_str2nid(str);
728         return *nidp != LNET_NID_ANY;
729 }
730
731 /**
732  * Nid range list syntax.
733  * \verbatim
734  *
735  * <nidlist>         :== <nidrange> [ ' ' <nidrange> ]
736  * <nidrange>        :== <addrrange> '@' <net>
737  * <addrrange>       :== '*' |
738  *                       <ipaddr_range> |
739  *                       <cfs_expr_list>
740  * <ipaddr_range>    :== <cfs_expr_list>.<cfs_expr_list>.<cfs_expr_list>.
741  *                       <cfs_expr_list>
742  * <cfs_expr_list>   :== <number> |
743  *                       <expr_list>
744  * <expr_list>       :== '[' <range_expr> [ ',' <range_expr>] ']'
745  * <range_expr>      :== <number> |
746  *                       <number> '-' <number> |
747  *                       <number> '-' <number> '/' <number>
748  * <net>             :== <netname> | <netname><number>
749  * <netname>         :== "lo" | "tcp" | "o2ib" | "cib" | "openib" | "iib" |
750  *                       "vib" | "ra" | "elan" | "mx" | "ptl"
751  * \endverbatim
752  */
753
754 /**
755  * Structure to represent \<nidrange\> token of the syntax.
756  *
757  * One of this is created for each \<net\> parsed.
758  */
759 struct nidrange {
760         /**
761          * Link to list of this structures which is built on nid range
762          * list parsing.
763          */
764         struct list_head nr_link;
765         /**
766          * List head for addrrange::ar_link.
767          */
768         struct list_head nr_addrranges;
769         /**
770          * Flag indicating that *@<net> is found.
771          */
772         int nr_all;
773         /**
774          * Pointer to corresponding element of libcfs_netstrfns.
775          */
776         struct netstrfns *nr_netstrfns;
777         /**
778          * Number of network. E.g. 5 if \<net\> is "elan5".
779          */
780         int nr_netnum;
781 };
782
783 /**
784  * Structure to represent \<addrrange\> token of the syntax.
785  */
786 struct addrrange {
787         /**
788          * Link to nidrange::nr_addrranges.
789          */
790         struct list_head ar_link;
791         /**
792          * List head for cfs_expr_list::el_list.
793          */
794         struct list_head ar_numaddr_ranges;
795 };
796
797 /**
798  * Parses \<addrrange\> token on the syntax.
799  *
800  * Allocates struct addrrange and links to \a nidrange via
801  * (nidrange::nr_addrranges)
802  *
803  * \retval 0 if \a src parses to '*' | \<ipaddr_range\> | \<cfs_expr_list\>
804  * \retval -errno otherwise
805  */
806 static int
807 parse_addrange(const struct cfs_lstr *src, struct nidrange *nidrange)
808 {
809         struct addrrange *addrrange;
810
811         if (src->ls_len == 1 && src->ls_str[0] == '*') {
812                 nidrange->nr_all = 1;
813                 return 0;
814         }
815
816         addrrange = calloc(1, sizeof(struct addrrange));
817         if (addrrange == NULL)
818                 return -ENOMEM;
819         list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges);
820         INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges);
821
822         return nidrange->nr_netstrfns->nf_parse_addrlist(src->ls_str,
823                                                 src->ls_len,
824                                                 &addrrange->ar_numaddr_ranges);
825 }
826
827 /**
828  * Finds or creates struct nidrange.
829  *
830  * Checks if \a src is a valid network name, looks for corresponding
831  * nidrange on the ist of nidranges (\a nidlist), creates new struct
832  * nidrange if it is not found.
833  *
834  * \retval pointer to struct nidrange matching network specified via \a src
835  * \retval NULL if \a src does not match any network
836  */
837 static struct nidrange *
838 add_nidrange(const struct cfs_lstr *src,
839              struct list_head *nidlist)
840 {
841         struct netstrfns *nf;
842         struct nidrange *nr;
843         int endlen;
844         unsigned netnum;
845
846         if (src->ls_len >= LNET_NIDSTR_SIZE)
847                 return NULL;
848
849         nf = libcfs_namenum2netstrfns(src->ls_str);
850         if (nf == NULL)
851                 return NULL;
852         endlen = src->ls_len - strlen(nf->nf_name);
853         if (endlen == 0)
854                 /* network name only, e.g. "elan" or "tcp" */
855                 netnum = 0;
856         else {
857                 /* e.g. "elan25" or "tcp23", refuse to parse if
858                  * network name is not appended with decimal or
859                  * hexadecimal number */
860                 if (!cfs_str2num_check(src->ls_str + strlen(nf->nf_name),
861                                        endlen, &netnum, 0, MAX_NUMERIC_VALUE))
862                         return NULL;
863         }
864
865         list_for_each_entry(nr, nidlist, nr_link) {
866                 if (nr->nr_netstrfns != nf)
867                         continue;
868                 if (nr->nr_netnum != netnum)
869                         continue;
870                 return nr;
871         }
872
873         nr = calloc(1, sizeof(struct nidrange));
874         if (nr == NULL)
875                 return NULL;
876         list_add_tail(&nr->nr_link, nidlist);
877         INIT_LIST_HEAD(&nr->nr_addrranges);
878         nr->nr_netstrfns = nf;
879         nr->nr_all = 0;
880         nr->nr_netnum = netnum;
881
882         return nr;
883 }
884
885 /**
886  * Parses \<nidrange\> token of the syntax.
887  *
888  * \retval 1 if \a src parses to \<addrrange\> '@' \<net\>
889  * \retval 0 otherwise
890  */
891 static int
892 parse_nidrange(struct cfs_lstr *src, struct list_head *nidlist)
893 {
894         struct cfs_lstr addrrange;
895         struct cfs_lstr net;
896         struct cfs_lstr tmp;
897         struct nidrange *nr;
898
899         tmp = *src;
900         if (cfs_gettok(src, '@', &addrrange) == 0)
901                 goto failed;
902
903         if (cfs_gettok(src, '@', &net) == 0 || src->ls_str != NULL)
904                 goto failed;
905
906         nr = add_nidrange(&net, nidlist);
907         if (nr == NULL)
908                 goto failed;
909
910         if (parse_addrange(&addrrange, nr) != 0)
911                 goto failed;
912
913         return 1;
914  failed:
915         fprintf(stderr, "can't parse nidrange: \"%.*s\"\n",
916                 tmp.ls_len, tmp.ls_str);
917         return 0;
918 }
919
920 /**
921  * Frees addrrange structures of \a list.
922  *
923  * For each struct addrrange structure found on \a list it frees
924  * cfs_expr_list list attached to it and frees the addrrange itself.
925  *
926  * \retval none
927  */
928 static void
929 free_addrranges(struct list_head *list)
930 {
931         while (!list_empty(list)) {
932                 struct addrrange *ar;
933
934                 ar = list_entry(list->next, struct addrrange, ar_link);
935
936                 cfs_expr_list_free_list(&ar->ar_numaddr_ranges);
937                 list_del(&ar->ar_link);
938                 free(ar);
939         }
940 }
941
942 /**
943  * Frees nidrange strutures of \a list.
944  *
945  * For each struct nidrange structure found on \a list it frees
946  * addrrange list attached to it and frees the nidrange itself.
947  *
948  * \retval none
949  */
950 void
951 cfs_free_nidlist(struct list_head *list)
952 {
953         struct list_head *pos, *next;
954         struct nidrange *nr;
955
956         list_for_each_safe(pos, next, list) {
957                 nr = list_entry(pos, struct nidrange, nr_link);
958                 free_addrranges(&nr->nr_addrranges);
959                 list_del(pos);
960                 free(nr);
961         }
962 }
963
964 /**
965  * Parses nid range list.
966  *
967  * Parses with rigorous syntax and overflow checking \a str into
968  * \<nidrange\> [ ' ' \<nidrange\> ], compiles \a str into set of
969  * structures and links that structure to \a nidlist. The resulting
970  * list can be used to match a NID againts set of NIDS defined by \a
971  * str.
972  * \see cfs_match_nid
973  *
974  * \retval 1 on success
975  * \retval 0 otherwise
976  */
977 int
978 cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
979 {
980         struct cfs_lstr src;
981         struct cfs_lstr res;
982         int rc;
983
984         src.ls_str = str;
985         src.ls_len = len;
986         INIT_LIST_HEAD(nidlist);
987         while (src.ls_str) {
988                 rc = cfs_gettok(&src, ' ', &res);
989                 if (rc == 0) {
990                         cfs_free_nidlist(nidlist);
991                         return 0;
992                 }
993                 rc = parse_nidrange(&res, nidlist);
994                 if (rc == 0) {
995                         cfs_free_nidlist(nidlist);
996                         return 0;
997                 }
998         }
999         return 1;
1000 }
1001
1002 /**
1003  * Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
1004  *
1005  * \see cfs_parse_nidlist()
1006  *
1007  * \retval 1 on match
1008  * \retval 0  otherwises
1009  */
1010 int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist)
1011 {
1012         struct nidrange *nr;
1013         struct addrrange *ar;
1014
1015         list_for_each_entry(nr, nidlist, nr_link) {
1016                 if (nr->nr_netstrfns->nf_type != LNET_NETTYP(LNET_NIDNET(nid)))
1017                         continue;
1018                 if (nr->nr_netnum != LNET_NETNUM(LNET_NIDNET(nid)))
1019                         continue;
1020                 if (nr->nr_all)
1021                         return 1;
1022                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
1023                         if (nr->nr_netstrfns->nf_match_addr(LNET_NIDADDR(nid),
1024                                                         &ar->ar_numaddr_ranges))
1025                                 return 1;
1026         }
1027         return 0;
1028 }
1029
1030 /**
1031  * Print the network part of the nidrange \a nr into the specified \a buffer.
1032  *
1033  * \retval number of characters written
1034  */
1035 static int
1036 cfs_print_network(char *buffer, int count, struct nidrange *nr)
1037 {
1038         struct netstrfns *nf = nr->nr_netstrfns;
1039
1040         if (nr->nr_netnum == 0)
1041                 return snprintf(buffer, count, "@%s", nf->nf_name);
1042         else
1043                 return snprintf(buffer, count, "@%s%u",
1044                                     nf->nf_name, nr->nr_netnum);
1045 }
1046
1047
1048 /**
1049  * Print a list of addrrange (\a addrranges) into the specified \a buffer.
1050  * At max \a count characters can be printed into \a buffer.
1051  *
1052  * \retval number of characters written
1053  */
1054 static int
1055 cfs_print_addrranges(char *buffer, int count, struct list_head *addrranges,
1056                      struct nidrange *nr)
1057 {
1058         int i = 0;
1059         struct addrrange *ar;
1060         struct netstrfns *nf = nr->nr_netstrfns;
1061
1062         list_for_each_entry(ar, addrranges, ar_link) {
1063                 if (i != 0)
1064                         i += scnprintf(buffer + i, count - i, " ");
1065                 i += nf->nf_print_addrlist(buffer + i, count - i,
1066                                            &ar->ar_numaddr_ranges);
1067                 i += cfs_print_network(buffer + i, count - i, nr);
1068         }
1069         return i;
1070 }
1071
1072 /**
1073  * Print a list of nidranges (\a nidlist) into the specified \a buffer.
1074  * At max \a count characters can be printed into \a buffer.
1075  * Nidranges are separated by a space character.
1076  *
1077  * \retval number of characters written
1078  */
1079 int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist)
1080 {
1081         int i = 0;
1082         struct nidrange *nr;
1083
1084         if (count <= 0)
1085                 return 0;
1086
1087         list_for_each_entry(nr, nidlist, nr_link) {
1088                 if (i != 0)
1089                         i += scnprintf(buffer + i, count - i, " ");
1090
1091                 if (nr->nr_all != 0) {
1092                         assert(list_empty(&nr->nr_addrranges));
1093                         i += scnprintf(buffer + i, count - i, "*");
1094                         i += cfs_print_network(buffer + i, count - i, nr);
1095                 } else {
1096                         i += cfs_print_addrranges(buffer + i, count - i,
1097                                                   &nr->nr_addrranges, nr);
1098                 }
1099         }
1100         return i;
1101 }
1102
1103 /**
1104  * Determines minimum and maximum addresses for a single
1105  * numeric address range
1106  *
1107  * \param       ar
1108  * \param[out]  *min_nid __u32 representation of min NID
1109  * \param[out]  *max_nid __u32 representation of max NID
1110  * \retval      -EINVAL unsupported LNET range
1111  * \retval      -ERANGE non-contiguous LNET range
1112  */
1113 static int cfs_ip_ar_min_max(struct addrrange *ar, __u32 *min_nid,
1114                               __u32 *max_nid)
1115 {
1116         struct cfs_expr_list *expr_list;
1117         struct cfs_range_expr *range;
1118         unsigned int min_ip[4] = {0};
1119         unsigned int max_ip[4] = {0};
1120         int cur_octet = 0;
1121         bool expect_full_octet = false;
1122
1123         list_for_each_entry(expr_list, &ar->ar_numaddr_ranges, el_link) {
1124                 int re_count = 0;
1125
1126                 list_for_each_entry(range, &expr_list->el_exprs, re_link) {
1127                         /* XXX: add support for multiple & non-contig. re's */
1128                         if (re_count > 0)
1129                                 return -EINVAL;
1130
1131                         /* if a previous octet was ranged, then all remaining
1132                          * octets must be full for contiguous range */
1133                         if (expect_full_octet && (range->re_lo != 0 ||
1134                                                   range->re_hi != 255))
1135                                 return -ERANGE;
1136
1137                         if (range->re_stride != 1)
1138                                 return -ERANGE;
1139
1140                         if (range->re_lo > range->re_hi)
1141                                 return -EINVAL;
1142
1143                         if (range->re_lo != range->re_hi)
1144                                 expect_full_octet = true;
1145
1146                         min_ip[cur_octet] = range->re_lo;
1147                         max_ip[cur_octet] = range->re_hi;
1148
1149                         re_count++;
1150                 }
1151
1152                 cur_octet++;
1153         }
1154
1155         if (min_nid != NULL)
1156                 *min_nid = ((min_ip[0] << 24) | (min_ip[1] << 16) |
1157                             (min_ip[2] << 8) | min_ip[3]);
1158
1159         if (max_nid != NULL)
1160                 *max_nid = ((max_ip[0] << 24) | (max_ip[1] << 16) |
1161                             (max_ip[2] << 8) | max_ip[3]);
1162
1163         return 0;
1164 }
1165
1166 /**
1167  * Determines minimum and maximum addresses for a single
1168  * numeric address range
1169  *
1170  * \param       ar
1171  * \param[out]  *min_nid __u32 representation of min NID
1172  * \param[out]  *max_nid __u32 representation of max NID
1173  * \retval      -EINVAL unsupported LNET range
1174  */
1175 static int cfs_num_ar_min_max(struct addrrange *ar, __u32 *min_nid,
1176                                __u32 *max_nid)
1177 {
1178         struct cfs_expr_list *el;
1179         struct cfs_range_expr *re;
1180         unsigned int min_addr = 0;
1181         unsigned int max_addr = 0;
1182
1183         list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) {
1184                 int re_count = 0;
1185
1186                 list_for_each_entry(re, &el->el_exprs, re_link) {
1187                         if (re_count > 0)
1188                                 return -EINVAL;
1189                         if (re->re_lo > re->re_hi)
1190                                 return -EINVAL;
1191
1192                         if (re->re_lo < min_addr || min_addr == 0)
1193                                 min_addr = re->re_lo;
1194                         if (re->re_hi > max_addr)
1195                                 max_addr = re->re_hi;
1196
1197                         re_count++;
1198                 }
1199         }
1200
1201         if (min_nid != NULL)
1202                 *min_nid = min_addr;
1203         if (max_nid != NULL)
1204                 *max_nid = max_addr;
1205
1206         return 0;
1207 }
1208
1209 /**
1210  * Takes a linked list of nidrange expressions, determines the minimum
1211  * and maximum nid and creates appropriate nid structures
1212  *
1213  * \param       *nidlist
1214  * \param[out]  *min_nid string representation of min NID
1215  * \param[out]  *max_nid string representation of max NID
1216  * \retval      -EINVAL unsupported LNET range
1217  * \retval      -ERANGE non-contiguous LNET range
1218  */
1219 int cfs_nidrange_find_min_max(struct list_head *nidlist, char *min_nid,
1220                               char *max_nid, size_t nidstr_length)
1221 {
1222         struct nidrange *first_nidrange;
1223         int netnum;
1224         struct netstrfns *nf;
1225         char *lndname;
1226         __u32 min_addr;
1227         __u32 max_addr;
1228         char min_addr_str[IPSTRING_LENGTH];
1229         char max_addr_str[IPSTRING_LENGTH];
1230         int rc;
1231
1232         first_nidrange = list_entry(nidlist->next, struct nidrange, nr_link);
1233
1234         netnum = first_nidrange->nr_netnum;
1235         nf = first_nidrange->nr_netstrfns;
1236         lndname = nf->nf_name;
1237
1238         rc = nf->nf_min_max(nidlist, &min_addr, &max_addr);
1239         if (rc < 0)
1240                 return rc;
1241
1242         nf->nf_addr2str(min_addr, min_addr_str, sizeof(min_addr_str));
1243         nf->nf_addr2str(max_addr, max_addr_str, sizeof(max_addr_str));
1244
1245         snprintf(min_nid, nidstr_length, "%s@%s%d", min_addr_str, lndname,
1246                  netnum);
1247         snprintf(max_nid, nidstr_length, "%s@%s%d", max_addr_str, lndname,
1248                  netnum);
1249
1250         return 0;
1251 }
1252
1253 /**
1254  * Determines the min and max NID values for num LNDs
1255  *
1256  * \param       *nidlist
1257  * \param[out]  *min_nid if provided, returns string representation of min NID
1258  * \param[out]  *max_nid if provided, returns string representation of max NID
1259  * \retval      -EINVAL unsupported LNET range
1260  * \retval      -ERANGE non-contiguous LNET range
1261  */
1262 static int cfs_num_min_max(struct list_head *nidlist, __u32 *min_nid,
1263                             __u32 *max_nid)
1264 {
1265         struct nidrange *nr;
1266         struct addrrange *ar;
1267         unsigned int tmp_min_addr = 0;
1268         unsigned int tmp_max_addr = 0;
1269         unsigned int min_addr = 0;
1270         unsigned int max_addr = 0;
1271         int nidlist_count = 0;
1272         int rc;
1273
1274         list_for_each_entry(nr, nidlist, nr_link) {
1275                 if (nidlist_count > 0)
1276                         return -EINVAL;
1277
1278                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1279                         rc = cfs_num_ar_min_max(ar, &tmp_min_addr,
1280                                                 &tmp_max_addr);
1281                         if (rc < 0)
1282                                 return rc;
1283
1284                         if (tmp_min_addr < min_addr || min_addr == 0)
1285                                 min_addr = tmp_min_addr;
1286                         if (tmp_max_addr > max_addr)
1287                                 max_addr = tmp_min_addr;
1288                 }
1289         }
1290         if (max_nid != NULL)
1291                 *max_nid = max_addr;
1292         if (min_nid != NULL)
1293                 *min_nid = min_addr;
1294
1295         return 0;
1296 }
1297
1298 /**
1299  * Takes an nidlist and determines the minimum and maximum
1300  * ip addresses.
1301  *
1302  * \param       *nidlist
1303  * \param[out]  *min_nid if provided, returns string representation of min NID
1304  * \param[out]  *max_nid if provided, returns string representation of max NID
1305  * \retval      -EINVAL unsupported LNET range
1306  * \retval      -ERANGE non-contiguous LNET range
1307  */
1308 static int cfs_ip_min_max(struct list_head *nidlist, __u32 *min_nid,
1309                            __u32 *max_nid)
1310 {
1311         struct nidrange *nr;
1312         struct addrrange *ar;
1313         __u32 tmp_min_ip_addr = 0;
1314         __u32 tmp_max_ip_addr = 0;
1315         __u32 min_ip_addr = 0;
1316         __u32 max_ip_addr = 0;
1317         int nidlist_count = 0;
1318         int rc;
1319
1320         list_for_each_entry(nr, nidlist, nr_link) {
1321                 if (nidlist_count > 0)
1322                         return -EINVAL;
1323
1324                 if (nr->nr_all) {
1325                         min_ip_addr = 0;
1326                         max_ip_addr = 0xffffffff;
1327                         break;
1328                 }
1329
1330                 list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1331                         rc = cfs_ip_ar_min_max(ar, &tmp_min_ip_addr,
1332                                                &tmp_max_ip_addr);
1333                         if (rc < 0)
1334                                 return rc;
1335
1336                         if (tmp_min_ip_addr < min_ip_addr || min_ip_addr == 0)
1337                                 min_ip_addr = tmp_min_ip_addr;
1338                         if (tmp_max_ip_addr > max_ip_addr)
1339                                 max_ip_addr = tmp_max_ip_addr;
1340                 }
1341
1342                 nidlist_count++;
1343         }
1344
1345         if (max_nid != NULL)
1346                 *max_nid = max_ip_addr;
1347         if (min_nid != NULL)
1348                 *min_nid = min_ip_addr;
1349
1350         return 0;
1351 }
1352
1353 static int
1354 libcfs_expand_nidrange(struct nidrange *nr, __u32 *addrs, int max_nids)
1355 {
1356         struct addrrange *ar;
1357         int rc = 0, count = max_nids;
1358         struct netstrfns *nf = nr->nr_netstrfns;
1359
1360         list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
1361                 rc = nf->nf_expand_addrrange(&ar->ar_numaddr_ranges, addrs,
1362                                              count);
1363                 if (rc < 0)
1364                         return rc;
1365
1366                 count -= rc;
1367         }
1368
1369         return max_nids - count;
1370 }
1371
1372 int cfs_expand_nidlist(struct list_head *nidlist, lnet_nid_t *lnet_nidlist,
1373                        int max_nids)
1374 {
1375         struct nidrange *nr;
1376         int rc = 0, count = max_nids;
1377         int i, j = 0;
1378         __u32 *addrs;
1379         struct netstrfns *nf;
1380         __u32 net;
1381
1382         addrs = calloc(max_nids, sizeof(__u32));
1383         if (!addrs)
1384                 return -ENOMEM;
1385
1386         list_for_each_entry(nr, nidlist, nr_link) {
1387                 rc = libcfs_expand_nidrange(nr, addrs, count);
1388
1389                 if (rc < 0) {
1390                         free(addrs);
1391                         return rc;
1392                 }
1393
1394                 nf = nr->nr_netstrfns;
1395                 net = LNET_MKNET(nf->nf_type, nr->nr_netnum);
1396
1397                 for (i = count - 1; i >= count - rc; i--)
1398                         lnet_nidlist[j++] = LNET_MKNID(net, addrs[i]);
1399
1400                 count -= rc;
1401         }
1402
1403         free(addrs);
1404         return max_nids - count;
1405 }