Whamcloud - gitweb
b=16098
[fs/lustre-release.git] / lnet / lnet / config.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 [sun.com URL with a
20  * copy of GPLv2].
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36
37 #define DEBUG_SUBSYSTEM S_LNET
38 #include <lnet/lib-lnet.h>
39
40 typedef struct {                                /* tmp struct for parsing routes */
41         struct list_head   ltb_list;            /* stash on lists */
42         int                ltb_size;            /* allocated size */
43         char               ltb_text[0];         /* text buffer */
44 } lnet_text_buf_t;
45
46 static int lnet_tbnob = 0;                      /* track text buf allocation */
47 #define LNET_MAX_TEXTBUF_NOB     (64<<10)       /* bound allocation */
48 #define LNET_SINGLE_TEXTBUF_NOB  (4<<10)
49
50 typedef struct {
51         struct list_head   lre_list;            /* stash in a list */
52         int                lre_min;             /* min value */
53         int                lre_max;             /* max value */
54         int                lre_stride;          /* stride */
55 } lnet_range_expr_t;
56
57 static int lnet_re_alloc = 0;                   /* track expr allocation */
58
59 void 
60 lnet_syntax(char *name, char *str, int offset, int width)
61 {
62         static char dots[LNET_SINGLE_TEXTBUF_NOB];
63         static char dashes[LNET_SINGLE_TEXTBUF_NOB];
64         
65         memset(dots, '.', sizeof(dots));
66         dots[sizeof(dots)-1] = 0;
67         memset(dashes, '-', sizeof(dashes));
68         dashes[sizeof(dashes)-1] = 0;
69         
70         LCONSOLE_ERROR_MSG(0x10f, "Error parsing '%s=\"%s\"'\n", name, str);
71         LCONSOLE_ERROR_MSG(0x110, "here...........%.*s..%.*s|%.*s|\n", 
72                            (int)strlen(name), dots, offset, dots,
73                             (width < 1) ? 0 : width - 1, dashes);
74 }
75
76 int 
77 lnet_issep (char c)
78 {
79         switch (c) {
80         case '\n':
81         case '\r':
82         case ';':
83                 return 1;
84         default:
85                 return 0;
86         }
87 }
88
89 int
90 lnet_iswhite (char c)
91 {
92         switch (c) {
93         case ' ':
94         case '\t':
95         case '\n':
96         case '\r':
97                 return 1;
98         default:
99                 return 0;
100         }
101 }
102
103 char *
104 lnet_trimwhite(char *str)
105 {
106         char *end;
107         
108         while (lnet_iswhite(*str))
109                 str++;
110         
111         end = str + strlen(str);
112         while (end > str) {
113                 if (!lnet_iswhite(end[-1]))
114                         break;
115                 end--;
116         }
117
118         *end = 0;
119         return str;
120 }
121
122 int
123 lnet_net_unique(__u32 net, struct list_head *nilist)
124 {
125         struct list_head *tmp;
126         lnet_ni_t        *ni;
127
128         list_for_each (tmp, nilist) {
129                 ni = list_entry(tmp, lnet_ni_t, ni_list);
130
131                 if (LNET_NIDNET(ni->ni_nid) == net)
132                         return 0;
133         }
134         
135         return 1;
136 }
137
138 lnet_ni_t *
139 lnet_new_ni(__u32 net, struct list_head *nilist)
140 {
141         lnet_ni_t *ni;
142
143         if (!lnet_net_unique(net, nilist)) {
144                 LCONSOLE_ERROR_MSG(0x111, "Duplicate network specified: %s\n",
145                                    libcfs_net2str(net));
146                 return NULL;
147         }
148         
149         LIBCFS_ALLOC(ni, sizeof(*ni));
150         if (ni == NULL) {
151                 CERROR("Out of memory creating network %s\n",
152                        libcfs_net2str(net));
153                 return NULL;
154         }
155         
156         /* zero counters/flags, NULL pointers... */
157         memset(ni, 0, sizeof(*ni));
158
159         /* LND will fill in the address part of the NID */
160         ni->ni_nid = LNET_MKNID(net, 0);
161         CFS_INIT_LIST_HEAD(&ni->ni_txq);
162
163         list_add_tail(&ni->ni_list, nilist);
164         return ni;
165 }
166
167 int
168 lnet_parse_networks(struct list_head *nilist, char *networks)
169 {
170         int        tokensize = strlen(networks) + 1;
171         char      *tokens;
172         char      *str;
173         lnet_ni_t *ni;
174         __u32      net;
175         int        nnets = 0;
176
177         if (strlen(networks) > LNET_SINGLE_TEXTBUF_NOB) {
178                 /* _WAY_ conservative */
179                 LCONSOLE_ERROR_MSG(0x112, "Can't parse networks: string too "
180                                    "long\n");
181                 return -EINVAL;
182         }
183
184         LIBCFS_ALLOC(tokens, tokensize);
185         if (tokens == NULL) {
186                 CERROR("Can't allocate net tokens\n");
187                 return -ENOMEM;
188         }
189
190         the_lnet.ln_network_tokens = tokens;
191         the_lnet.ln_network_tokens_nob = tokensize;
192         memcpy (tokens, networks, tokensize);
193         str = tokens;
194         
195         /* Add in the loopback network */
196         ni = lnet_new_ni(LNET_MKNET(LOLND, 0), nilist);
197         if (ni == NULL)
198                 goto failed;
199         
200         while (str != NULL && *str != 0) {
201                 char      *comma = strchr(str, ',');
202                 char      *bracket = strchr(str, '(');
203                 int        niface;
204                 char      *iface;
205
206                 /* NB we don't check interface conflicts here; it's the LNDs
207                  * responsibility (if it cares at all) */
208
209                 if (bracket == NULL ||
210                     (comma != NULL && comma < bracket)) {
211
212                         /* no interface list specified */
213
214                         if (comma != NULL)
215                                 *comma++ = 0;
216                         net = libcfs_str2net(lnet_trimwhite(str));
217                         
218                         if (net == LNET_NIDNET(LNET_NID_ANY)) {
219                                 lnet_syntax("networks", networks, 
220                                             str - tokens, strlen(str));
221                                 LCONSOLE_ERROR_MSG(0x113, "Unrecognised network"
222                                                    " type\n");
223                                 goto failed;
224                         }
225
226                         if (LNET_NETTYP(net) != LOLND && /* loopback is implicit */
227                             lnet_new_ni(net, nilist) == NULL)
228                                 goto failed;
229
230                         str = comma;
231                         continue;
232                 }
233
234                 *bracket = 0;
235                 net = libcfs_str2net(lnet_trimwhite(str));
236                 if (net == LNET_NIDNET(LNET_NID_ANY)) {
237                         lnet_syntax("networks", networks,
238                                     str - tokens, strlen(str));
239                         goto failed;
240                 } 
241
242                 if (nnets > 0 &&
243                     the_lnet.ln_ptlcompat > 0) {
244                         LCONSOLE_ERROR_MSG(0x114, "Only 1 network supported when"
245                                            " 'portals_compatible' is set\n");
246                         goto failed;
247                 }
248
249                 nnets++;
250                 ni = lnet_new_ni(net, nilist);
251                 if (ni == NULL)
252                         goto failed;
253
254                 niface = 0;
255                 iface = bracket + 1;
256
257                 bracket = strchr(iface, ')');
258                 if (bracket == NULL) {
259                         lnet_syntax("networks", networks,
260                                     iface - tokens, strlen(iface));
261                         goto failed;
262                 }
263
264                 *bracket = 0;
265                 do {
266                         comma = strchr(iface, ',');
267                         if (comma != NULL)
268                                 *comma++ = 0;
269                         
270                         iface = lnet_trimwhite(iface);
271                         if (*iface == 0) {
272                                 lnet_syntax("networks", networks, 
273                                             iface - tokens, strlen(iface));
274                                 goto failed;
275                         }
276
277                         if (niface == LNET_MAX_INTERFACES) {
278                                 LCONSOLE_ERROR_MSG(0x115, "Too many interfaces "
279                                                    "for net %s\n",
280                                                    libcfs_net2str(net));
281                                 goto failed;
282                         }
283
284                         ni->ni_interfaces[niface++] = iface;
285                         iface = comma;
286                 } while (iface != NULL);
287
288                 str = bracket + 1;
289                 comma = strchr(bracket + 1, ',');
290                 if (comma != NULL) {
291                         *comma = 0;
292                         str = lnet_trimwhite(str);
293                         if (*str != 0) {
294                                 lnet_syntax("networks", networks,
295                                             str - tokens, strlen(str));
296                                 goto failed;
297                         }
298                         str = comma + 1;
299                         continue;
300                 }
301                 
302                 str = lnet_trimwhite(str);
303                 if (*str != 0) {
304                         lnet_syntax("networks", networks,
305                                     str - tokens, strlen(str));
306                         goto failed;
307                 }
308         }
309
310         LASSERT (!list_empty(nilist));
311         return 0;
312
313  failed:
314         while (!list_empty(nilist)) {
315                 ni = list_entry(nilist->next, lnet_ni_t, ni_list);
316                 
317                 list_del(&ni->ni_list);
318                 LIBCFS_FREE(ni, sizeof(*ni));
319         }
320         LIBCFS_FREE(tokens, tokensize);
321         the_lnet.ln_network_tokens = NULL;
322
323         return -EINVAL;
324 }
325
326 lnet_text_buf_t *
327 lnet_new_text_buf (int str_len) 
328 {
329         lnet_text_buf_t *ltb;
330         int              nob;
331
332         /* NB allocate space for the terminating 0 */
333         nob = offsetof(lnet_text_buf_t, ltb_text[str_len + 1]);
334         if (nob > LNET_SINGLE_TEXTBUF_NOB) {
335                 /* _way_ conservative for "route net gateway..." */
336                 CERROR("text buffer too big\n");
337                 return NULL;
338         }
339
340         if (lnet_tbnob + nob > LNET_MAX_TEXTBUF_NOB) {
341                 CERROR("Too many text buffers\n");
342                 return NULL;
343         }
344         
345         LIBCFS_ALLOC(ltb, nob);
346         if (ltb == NULL)
347                 return NULL;
348
349         ltb->ltb_size = nob;
350         ltb->ltb_text[0] = 0;
351         lnet_tbnob += nob;
352         return ltb;
353 }
354
355 void
356 lnet_free_text_buf (lnet_text_buf_t *ltb)
357 {
358         lnet_tbnob -= ltb->ltb_size;
359         LIBCFS_FREE(ltb, ltb->ltb_size);
360 }
361
362 void
363 lnet_free_text_bufs(struct list_head *tbs)
364 {
365         lnet_text_buf_t  *ltb;
366         
367         while (!list_empty(tbs)) {
368                 ltb = list_entry(tbs->next, lnet_text_buf_t, ltb_list);
369                 
370                 list_del(&ltb->ltb_list);
371                 lnet_free_text_buf(ltb);
372         }
373 }
374
375 void
376 lnet_print_text_bufs(struct list_head *tbs)
377 {
378         struct list_head  *tmp;
379         lnet_text_buf_t   *ltb;
380
381         list_for_each (tmp, tbs) {
382                 ltb = list_entry(tmp, lnet_text_buf_t, ltb_list);
383
384                 CDEBUG(D_WARNING, "%s\n", ltb->ltb_text);
385         }
386
387         CDEBUG(D_WARNING, "%d allocated\n", lnet_tbnob);
388 }
389
390 int
391 lnet_str2tbs_sep (struct list_head *tbs, char *str) 
392 {
393         struct list_head  pending;
394         char             *sep;
395         int               nob;
396         int               i;
397         lnet_text_buf_t  *ltb;
398
399         CFS_INIT_LIST_HEAD(&pending);
400
401         /* Split 'str' into separate commands */
402         for (;;) {
403                 /* skip leading whitespace */
404                 while (lnet_iswhite(*str))
405                         str++;
406                 
407                 /* scan for separator or comment */
408                 for (sep = str; *sep != 0; sep++)
409                         if (lnet_issep(*sep) || *sep == '#')
410                                 break;
411
412                 nob = sep - str;
413                 if (nob > 0) {
414                         ltb = lnet_new_text_buf(nob);
415                         if (ltb == NULL) {
416                                 lnet_free_text_bufs(&pending);
417                                 return -1;
418                         }
419                         
420                         for (i = 0; i < nob; i++)
421                                 if (lnet_iswhite(str[i]))
422                                         ltb->ltb_text[i] = ' ';
423                                 else
424                                         ltb->ltb_text[i] = str[i];
425
426                         ltb->ltb_text[nob] = 0;
427
428                         list_add_tail(&ltb->ltb_list, &pending);
429                 }
430
431                 if (*sep == '#') {
432                         /* scan for separator */
433                         do {
434                                 sep++;
435                         } while (*sep != 0 && !lnet_issep(*sep));
436                 }
437                 
438                 if (*sep == 0)
439                         break;
440
441                 str = sep + 1;
442         }
443
444         list_splice(&pending, tbs->prev);
445         return 0;
446 }
447
448 int
449 lnet_expand1tb (struct list_head *list, 
450                char *str, char *sep1, char *sep2, 
451                char *item, int itemlen)
452 {
453         int              len1 = sep1 - str;
454         int              len2 = strlen(sep2 + 1);
455         lnet_text_buf_t *ltb;
456
457         LASSERT (*sep1 == '[');
458         LASSERT (*sep2 == ']');
459
460         ltb = lnet_new_text_buf(len1 + itemlen + len2);
461         if (ltb == NULL)
462                 return -ENOMEM;
463         
464         memcpy(ltb->ltb_text, str, len1);
465         memcpy(&ltb->ltb_text[len1], item, itemlen);
466         memcpy(&ltb->ltb_text[len1+itemlen], sep2 + 1, len2);
467         ltb->ltb_text[len1 + itemlen + len2] = 0;
468         
469         list_add_tail(&ltb->ltb_list, list);
470         return 0;
471 }
472
473 int
474 lnet_str2tbs_expand (struct list_head *tbs, char *str)
475 {
476         char              num[16];
477         struct list_head  pending;
478         char             *sep;
479         char             *sep2;
480         char             *parsed;
481         char             *enditem;
482         int               lo;
483         int               hi;
484         int               stride;
485         int               i;
486         int               nob;
487         int               scanned;
488
489         CFS_INIT_LIST_HEAD(&pending);
490         
491         sep = strchr(str, '[');
492         if (sep == NULL)                        /* nothing to expand */
493                 return 0;
494
495         sep2 = strchr(sep, ']');
496         if (sep2 == NULL)
497                 goto failed;
498
499         for (parsed = sep; parsed < sep2; parsed = enditem) {
500
501                 enditem = ++parsed;
502                 while (enditem < sep2 && *enditem != ',')
503                         enditem++;
504
505                 if (enditem == parsed)          /* no empty items */
506                         goto failed;
507
508                 if (sscanf(parsed, "%d-%d/%d%n", &lo, &hi, &stride, &scanned) < 3) {
509
510                         if (sscanf(parsed, "%d-%d%n", &lo, &hi, &scanned) < 2) {
511
512                                 /* simple string enumeration */
513                                 if (lnet_expand1tb(&pending, str, sep, sep2,
514                                                    parsed, enditem - parsed) != 0)
515                                         goto failed;
516                                 
517                                 continue;
518                         }
519                         
520                         stride = 1;
521                 }
522
523                 /* range expansion */
524
525                 if (enditem != parsed + scanned) /* no trailing junk */
526                         goto failed;
527                         
528                 if (hi < 0 || lo < 0 || stride < 0 || hi < lo || 
529                     (hi - lo) % stride != 0)
530                         goto failed;
531                         
532                 for (i = lo; i <= hi; i += stride) {
533
534                         snprintf(num, sizeof(num), "%d", i);
535                         nob = strlen(num);
536                         if (nob + 1 == sizeof(num))
537                                 goto failed;
538                         
539                         if (lnet_expand1tb(&pending, str, sep, sep2, 
540                                            num, nob) != 0)
541                                 goto failed;
542                 }
543         }
544                 
545         list_splice(&pending, tbs->prev);
546         return 1;
547         
548  failed:
549         lnet_free_text_bufs(&pending);
550         return -1;
551 }
552
553 int
554 lnet_parse_hops (char *str, unsigned int *hops)
555 {
556         int     len = strlen(str);
557         int     nob = len;
558         
559         return (sscanf(str, "%u%n", hops, &nob) >= 1 &&
560                 nob == len &&
561                 *hops > 0 && *hops < 256);
562 }
563
564
565 int
566 lnet_parse_route (char *str, int *im_a_router)
567 {
568         /* static scratch buffer OK (single threaded) */
569         static char       cmd[LNET_SINGLE_TEXTBUF_NOB];
570
571         struct list_head  nets;
572         struct list_head  gateways;
573         struct list_head *tmp1;
574         struct list_head *tmp2;
575         __u32             net;
576         lnet_nid_t        nid;
577         lnet_text_buf_t  *ltb;
578         int               rc;
579         char             *sep;
580         char             *token = str;
581         int               ntokens = 0;
582         int               myrc = -1;
583         unsigned int      hops;
584         int               got_hops = 0;
585
586         CFS_INIT_LIST_HEAD(&gateways);
587         CFS_INIT_LIST_HEAD(&nets);
588
589         /* save a copy of the string for error messages */
590         strncpy(cmd, str, sizeof(cmd) - 1);
591         cmd[sizeof(cmd) - 1] = 0;
592
593         sep = str;
594         for (;;) {
595                 /* scan for token start */
596                 while (lnet_iswhite(*sep))
597                         sep++;
598                 if (*sep == 0) {
599                         if (ntokens < (got_hops ? 3 : 2))
600                                 goto token_error;
601                         break;
602                 }
603
604                 ntokens++;
605                 token = sep++;
606
607                 /* scan for token end */
608                 while (*sep != 0 && !lnet_iswhite(*sep))
609                         sep++;
610                 if (*sep != 0)
611                         *sep++ = 0;
612                 
613                 if (ntokens == 1) {
614                         tmp2 = &nets;           /* expanding nets */
615                 } else if (ntokens == 2 &&
616                            lnet_parse_hops(token, &hops)) {
617                         got_hops = 1;           /* got a hop count */
618                         continue;
619                 } else {
620                         tmp2 = &gateways;       /* expanding gateways */
621                 }
622                 
623                 ltb = lnet_new_text_buf(strlen(token));
624                 if (ltb == NULL)
625                         goto out;
626
627                 strcpy(ltb->ltb_text, token);
628                 tmp1 = &ltb->ltb_list;
629                 list_add_tail(tmp1, tmp2);
630                 
631                 while (tmp1 != tmp2) {
632                         ltb = list_entry(tmp1, lnet_text_buf_t, ltb_list);
633
634                         rc = lnet_str2tbs_expand(tmp1->next, ltb->ltb_text);
635                         if (rc < 0)
636                                 goto token_error;
637
638                         tmp1 = tmp1->next;
639                         
640                         if (rc > 0) {           /* expanded! */
641                                 list_del(&ltb->ltb_list);
642                                 lnet_free_text_buf(ltb);
643                                 continue;
644                         }
645
646                         if (ntokens == 1) {
647                                 net = libcfs_str2net(ltb->ltb_text);
648                                 if (net == LNET_NIDNET(LNET_NID_ANY) ||
649                                     LNET_NETTYP(net) == LOLND)
650                                         goto token_error;
651                         } else {
652                                 nid = libcfs_str2nid(ltb->ltb_text);
653                                 if (nid == LNET_NID_ANY ||
654                                     LNET_NETTYP(LNET_NIDNET(nid)) == LOLND)
655                                         goto token_error;
656                         }
657                 }
658         }
659
660         if (!got_hops)
661                 hops = 1;
662
663         LASSERT (!list_empty(&nets));
664         LASSERT (!list_empty(&gateways));
665
666         list_for_each (tmp1, &nets) {
667                 ltb = list_entry(tmp1, lnet_text_buf_t, ltb_list);
668                 net = libcfs_str2net(ltb->ltb_text);
669                 LASSERT (net != LNET_NIDNET(LNET_NID_ANY));
670
671                 list_for_each (tmp2, &gateways) {
672                         ltb = list_entry(tmp2, lnet_text_buf_t, ltb_list);
673                         nid = libcfs_str2nid(ltb->ltb_text);
674                         LASSERT (nid != LNET_NID_ANY);
675
676                         if (lnet_islocalnid(nid)) {
677                                 *im_a_router = 1;
678                                 continue;
679                         }
680                         
681                         rc = lnet_add_route (net, hops, nid);
682                         if (rc != 0) {
683                                 CERROR("Can't create route "
684                                        "to %s via %s\n",
685                                        libcfs_net2str(net),
686                                        libcfs_nid2str(nid));
687                                 goto out;
688                         }
689                 }
690         }
691
692         myrc = 0;
693         goto out;
694         
695  token_error:
696         lnet_syntax("routes", cmd, token - str, strlen(token));
697  out:
698         lnet_free_text_bufs(&nets);
699         lnet_free_text_bufs(&gateways);
700         return myrc;
701 }
702
703 int
704 lnet_parse_route_tbs(struct list_head *tbs, int *im_a_router)
705 {
706         lnet_text_buf_t   *ltb;
707
708         while (!list_empty(tbs)) {
709                 ltb = list_entry(tbs->next, lnet_text_buf_t, ltb_list);
710
711                 if (lnet_parse_route(ltb->ltb_text, im_a_router) < 0) {
712                         lnet_free_text_bufs(tbs);
713                         return -EINVAL;
714                 }
715
716                 list_del(&ltb->ltb_list);
717                 lnet_free_text_buf(ltb);
718         }
719
720         return 0;
721 }
722
723 int
724 lnet_parse_routes (char *routes, int *im_a_router)
725 {
726         struct list_head  tbs;
727         int               rc = 0;
728
729         *im_a_router = 0;
730
731         if (the_lnet.ln_ptlcompat > 0 && 
732             routes[0] != 0) {
733                 /* Can't route when running in compatibility mode */
734                 LCONSOLE_ERROR_MSG(0x116, "Route tables are not supported when "
735                                    "'portals_compatible' is set\n");
736                 return -EINVAL;
737         }
738         
739         CFS_INIT_LIST_HEAD(&tbs);
740
741         if (lnet_str2tbs_sep(&tbs, routes) < 0) {
742                 CERROR("Error parsing routes\n");
743                 rc = -EINVAL;
744         } else {
745                 rc = lnet_parse_route_tbs(&tbs, im_a_router);
746         }
747
748         LASSERT (lnet_tbnob == 0);
749         return rc;
750 }
751
752 void
753 lnet_print_range_exprs(struct list_head *exprs)
754 {
755         struct list_head   *e;
756         lnet_range_expr_t *lre;
757         
758         list_for_each(e, exprs) {
759                 lre = list_entry(exprs->next, lnet_range_expr_t, lre_list);
760                 
761                 CDEBUG(D_WARNING, "%d-%d/%d\n", 
762                        lre->lre_min, lre->lre_max, lre->lre_stride);
763         }
764         
765         CDEBUG(D_WARNING, "%d allocated\n", lnet_re_alloc);
766 }
767
768 int
769 lnet_new_range_expr(struct list_head *exprs, int min, int max, int stride)
770 {
771         lnet_range_expr_t *lre;
772
773         CDEBUG(D_NET, "%d-%d/%d\n", min, max, stride);
774
775         if (min < 0 || min > 255 || min > max || stride < 0)
776                 return -EINVAL;
777
778         LIBCFS_ALLOC(lre, sizeof(*lre));
779         if (lre == NULL)
780                 return -ENOMEM;
781
782         lnet_re_alloc++;
783
784         lre->lre_min = min;
785         lre->lre_max = max;
786         lre->lre_stride = stride;
787         
788         list_add(&lre->lre_list, exprs);
789         return 0;
790 }
791
792 void
793 lnet_destroy_range_exprs(struct list_head *exprs)
794 {
795         lnet_range_expr_t *lre;
796         
797         while (!list_empty(exprs)) {
798                 lre = list_entry(exprs->next, lnet_range_expr_t, lre_list);
799                 
800                 list_del(&lre->lre_list);
801                 LIBCFS_FREE(lre, sizeof(*lre));
802                 lnet_re_alloc--;
803         }
804 }
805
806 int
807 lnet_parse_range_expr(struct list_head *exprs, char *str)
808 {
809         int                nob = strlen(str);
810         char              *sep;
811         int                n;
812         int                x;
813         int                y;
814         int                z;
815         int                rc;
816
817         if (nob == 0)
818                 return -EINVAL;
819
820         if (!strcmp(str, "*"))                  /* match all */
821                 return lnet_new_range_expr(exprs, 0, 255, 1);
822                 
823         n = nob;
824         if (sscanf(str, "%u%n", &x, &n) >= 1 && n == nob) {
825                 /* simple number */
826                 return lnet_new_range_expr(exprs, x, x, 1);
827         }
828
829         /* Has to be an expansion */
830         if (!(str[0] == '[' && nob > 2 && str[nob-1] == ']'))
831                 return -EINVAL;
832
833         nob -= 2;
834         str++;
835         str[nob] = 0;
836
837         do {
838                 /* Comma separated list of expressions... */
839                 sep = strchr(str, ',');
840                 if (sep != NULL)
841                         *sep++ = 0;
842                 
843                 nob = strlen(str);
844                 n = nob;
845                 if (sscanf(str, "%u%n", &x, &n) >= 1 && n == nob) {
846                         /* simple number */
847                         rc = lnet_new_range_expr(exprs, x, x, 1);
848                         if (rc != 0)
849                                 return rc;
850
851                         continue;
852                 }
853
854                 n = nob;
855                 if (sscanf(str, "%u-%u%n", &x, &y, &n) >= 2 && n == nob) {
856                         /* simple range */
857                         rc = lnet_new_range_expr(exprs, x, y, 1);
858                         if (rc != 0)
859                                 return rc;
860                         continue;
861                 }
862                         
863                 n = nob;
864                 if (sscanf(str, "%u-%u/%u%n", &x, &y, &z, &n) >= 3 && n == nob) {
865                         /* strided range */
866                         rc = lnet_new_range_expr(exprs, x, y, z);
867                         if (rc != 0)
868                                 return rc;
869                         continue;
870                 }
871                 
872                 return -EINVAL;
873
874         } while ((str = sep) != NULL);
875
876         return 0;
877 }
878
879 int
880 lnet_match_network_token(char *token, __u32 *ipaddrs, int nip)
881 {
882         struct list_head   exprs[4];
883         struct list_head  *e;
884         lnet_range_expr_t *re;
885         char              *str;
886         int                i;
887         int                j;
888         __u32              ip;
889         int                n;
890         int                match;
891         int                rc;
892
893         for (i = 0; i < 4; i++)
894                 CFS_INIT_LIST_HEAD(&exprs[i]);
895
896         for (i = 0; i < 4; i++) {
897                 str = token;
898                 if (i != 3) {
899                         token = strchr(token, '.');
900                         if (token == NULL) {
901                                 rc = -EINVAL;
902                                 goto out;
903                         }
904                         *token++ = 0;
905                 }
906
907                 rc = lnet_parse_range_expr(&exprs[i], str);
908                 if (rc != 0) {
909                         LASSERT (rc < 0);
910                         goto out;
911                 }
912         }
913
914         for (match = i = 0; !match && i < nip; i++) {
915                 ip = ipaddrs[i];
916                 
917                 for (match = 1, j = 0; match && j < 4; j++) {
918                         n = (ip >> (8 * (3 - j))) & 0xff;
919                         match = 0;
920
921                         list_for_each(e, &exprs[j]) {
922                                 re = list_entry(e, lnet_range_expr_t, lre_list);
923
924                                 if (re->lre_min <= n &&
925                                     re->lre_max >= n &&
926                                     (n - re->lre_min) % re->lre_stride == 0) {
927                                         match = 1;
928                                         break;
929                                 }
930                         }
931                 }
932         }
933         
934         rc = match ? 1 : 0;
935
936  out:
937         for (i = 0; i < 4; i++)
938                 lnet_destroy_range_exprs(&exprs[i]);
939         LASSERT (lnet_re_alloc == 0);
940         
941         return rc;
942 }
943
944 int
945 lnet_match_network_tokens(char *net_entry, __u32 *ipaddrs, int nip)
946 {
947         static char tokens[LNET_SINGLE_TEXTBUF_NOB];
948
949         int   matched = 0;
950         int   ntokens = 0;
951         int   len;
952         char *net = NULL;
953         char *sep;
954         char *token;
955         int   rc;
956
957         LASSERT (strlen(net_entry) < sizeof(tokens));
958
959         /* work on a copy of the string */
960         strcpy(tokens, net_entry);
961         sep = tokens;
962         for (;;) {
963                 /* scan for token start */
964                 while (lnet_iswhite(*sep))
965                         sep++;
966                 if (*sep == 0)
967                         break;
968                 
969                 token = sep++;
970                 
971                 /* scan for token end */
972                 while (*sep != 0 && !lnet_iswhite(*sep))
973                         sep++;
974                 if (*sep != 0)
975                         *sep++ = 0;
976                 
977                 if (ntokens++ == 0) {
978                         net = token;
979                         continue;
980                 }
981
982                 len = strlen(token);
983                 
984                 rc = lnet_match_network_token(token, ipaddrs, nip);
985                 if (rc < 0) {
986                         lnet_syntax("ip2nets", net_entry,
987                                     token - tokens, len);
988                         return rc;
989                 }
990
991                 matched |= (rc != 0);
992         }
993         
994         if (!matched)
995                 return 0;
996         
997         strcpy(net_entry, net);                 /* replace with matched net */
998         return 1;
999 }
1000
1001 __u32 
1002 lnet_netspec2net(char *netspec)
1003 {
1004         char   *bracket = strchr(netspec, '(');
1005         __u32   net;
1006
1007         if (bracket != NULL)
1008                 *bracket = 0;
1009
1010         net = libcfs_str2net(netspec);
1011
1012         if (bracket != NULL)
1013                 *bracket = '(';
1014                 
1015         return net;
1016 }
1017
1018 int
1019 lnet_splitnets(char *source, struct list_head *nets)
1020 {
1021         int               offset = 0;
1022         int               offset2;
1023         int               len;
1024         lnet_text_buf_t  *tb;
1025         lnet_text_buf_t  *tb2;
1026         struct list_head *t;
1027         char             *sep;
1028         char             *bracket;
1029         __u32             net;
1030
1031         LASSERT (!list_empty(nets));
1032         LASSERT (nets->next == nets->prev);     /* single entry */
1033         
1034         tb = list_entry(nets->next, lnet_text_buf_t, ltb_list);
1035
1036         for (;;) {
1037                 sep = strchr(tb->ltb_text, ',');
1038                 bracket = strchr(tb->ltb_text, '(');
1039
1040                 if (sep != NULL && 
1041                     bracket != NULL && 
1042                     bracket < sep) {
1043                         /* netspec lists interfaces... */
1044
1045                         offset2 = offset + (bracket - tb->ltb_text);
1046                         len = strlen(bracket);
1047
1048                         bracket = strchr(bracket + 1, ')');
1049
1050                         if (bracket == NULL ||
1051                             !(bracket[1] == ',' || bracket[1] == 0)) {
1052                                 lnet_syntax("ip2nets", source, offset2, len);
1053                                 return -EINVAL;
1054                         }
1055
1056                         sep = (bracket[1] == 0) ? NULL : bracket + 1;
1057                 }
1058
1059                 if (sep != NULL)
1060                         *sep++ = 0;
1061
1062                 net = lnet_netspec2net(tb->ltb_text);
1063                 if (net == LNET_NIDNET(LNET_NID_ANY)) {
1064                         lnet_syntax("ip2nets", source, offset,
1065                                     strlen(tb->ltb_text));
1066                         return -EINVAL;
1067                 }
1068
1069                 list_for_each(t, nets) {
1070                         tb2 = list_entry(t, lnet_text_buf_t, ltb_list);
1071
1072                         if (tb2 == tb)
1073                                 continue;
1074                         
1075                         if (net == lnet_netspec2net(tb2->ltb_text)) {
1076                                 /* duplicate network */
1077                                 lnet_syntax("ip2nets", source, offset,
1078                                             strlen(tb->ltb_text));
1079                                 return -EINVAL;
1080                         }
1081                 }
1082                 
1083                 if (sep == NULL)
1084                         return 0;
1085
1086                 offset += sep - tb->ltb_text;
1087                 tb2 = lnet_new_text_buf(strlen(sep));
1088                 if (tb2 == NULL)
1089                         return -ENOMEM;
1090                         
1091                 strcpy(tb2->ltb_text, sep);
1092                 list_add_tail(&tb2->ltb_list, nets);
1093
1094                 tb = tb2;
1095         }
1096 }
1097
1098 int
1099 lnet_match_networks (char **networksp, char *ip2nets, __u32 *ipaddrs, int nip)
1100 {
1101         static char  networks[LNET_SINGLE_TEXTBUF_NOB];
1102         static char  source[LNET_SINGLE_TEXTBUF_NOB];
1103
1104         struct list_head    raw_entries;
1105         struct list_head    matched_nets;
1106         struct list_head    current_nets;
1107         struct list_head   *t;
1108         struct list_head   *t2;
1109         lnet_text_buf_t    *tb;
1110         lnet_text_buf_t    *tb2;
1111         __u32               net1;
1112         __u32               net2;
1113         int                 len;
1114         int                 count;
1115         int                 dup;
1116         int                 rc;
1117
1118         CFS_INIT_LIST_HEAD(&raw_entries);
1119         if (lnet_str2tbs_sep(&raw_entries, ip2nets) < 0) {
1120                 CERROR("Error parsing ip2nets\n");
1121                 LASSERT (lnet_tbnob == 0);
1122                 return -EINVAL;
1123         }
1124
1125         CFS_INIT_LIST_HEAD(&matched_nets);
1126         CFS_INIT_LIST_HEAD(&current_nets);
1127         networks[0] = 0;
1128         count = 0;
1129         len = 0;
1130         rc = 0;
1131
1132         while (!list_empty(&raw_entries)) {
1133                 tb = list_entry(raw_entries.next, lnet_text_buf_t, ltb_list);
1134
1135                 strncpy(source, tb->ltb_text, sizeof(source)-1);
1136                 source[sizeof(source)-1] = 0;
1137
1138                 /* replace ltb_text with the network(s) add on match */
1139                 rc = lnet_match_network_tokens(tb->ltb_text, ipaddrs, nip);
1140                 if (rc < 0)
1141                         break;
1142
1143                 list_del(&tb->ltb_list);
1144
1145                 if (rc == 0) {                  /* no match */
1146                         lnet_free_text_buf(tb);
1147                         continue;
1148                 }
1149
1150                 /* split into separate networks */
1151                 CFS_INIT_LIST_HEAD(&current_nets);
1152                 list_add(&tb->ltb_list, &current_nets);
1153                 rc = lnet_splitnets(source, &current_nets);
1154                 if (rc < 0)
1155                         break;
1156
1157                 dup = 0;
1158                 list_for_each (t, &current_nets) {
1159                         tb = list_entry(t, lnet_text_buf_t, ltb_list);
1160                         net1 = lnet_netspec2net(tb->ltb_text);
1161                         LASSERT (net1 != LNET_NIDNET(LNET_NID_ANY));
1162
1163                         list_for_each(t2, &matched_nets) {
1164                                 tb2 = list_entry(t2, lnet_text_buf_t, ltb_list);
1165                                 net2 = lnet_netspec2net(tb2->ltb_text);
1166                                 LASSERT (net2 != LNET_NIDNET(LNET_NID_ANY));
1167
1168                                 if (net1 == net2) {
1169                                         dup = 1;
1170                                         break;
1171                                 }
1172                         }
1173
1174                         if (dup)
1175                                 break;
1176                 }
1177
1178                 if (dup) {
1179                         lnet_free_text_bufs(&current_nets);
1180                         continue;
1181                 }
1182
1183                 list_for_each_safe(t, t2, &current_nets) {
1184                         tb = list_entry(t, lnet_text_buf_t, ltb_list);
1185                         
1186                         list_del(&tb->ltb_list);
1187                         list_add_tail(&tb->ltb_list, &matched_nets);
1188
1189                         len += snprintf(networks + len, sizeof(networks) - len,
1190                                         "%s%s", (len == 0) ? "" : ",", 
1191                                         tb->ltb_text);
1192                 
1193                         if (len >= sizeof(networks)) {
1194                                 CERROR("Too many matched networks\n");
1195                                 rc = -E2BIG;
1196                                 goto out;
1197                         }
1198                 }
1199                 
1200                 count++;
1201         }
1202
1203  out:
1204         lnet_free_text_bufs(&raw_entries);
1205         lnet_free_text_bufs(&matched_nets);
1206         lnet_free_text_bufs(&current_nets);
1207         LASSERT (lnet_tbnob == 0);
1208
1209         if (rc < 0)
1210                 return rc;
1211         
1212         *networksp = networks;
1213         return count;
1214 }
1215
1216 #ifdef __KERNEL__
1217 void
1218 lnet_ipaddr_free_enumeration(__u32 *ipaddrs, int nip)
1219 {
1220         LIBCFS_FREE(ipaddrs, nip * sizeof(*ipaddrs));
1221 }
1222
1223 int
1224 lnet_ipaddr_enumerate (__u32 **ipaddrsp)
1225 {
1226         int        up;
1227         __u32      netmask;
1228         __u32     *ipaddrs;
1229         __u32     *ipaddrs2;
1230         int        nip;
1231         char     **ifnames;
1232         int        nif = libcfs_ipif_enumerate(&ifnames);
1233         int        i;
1234         int        rc;
1235
1236         if (nif <= 0)
1237                 return nif;
1238         
1239         LIBCFS_ALLOC(ipaddrs, nif * sizeof(*ipaddrs));
1240         if (ipaddrs == NULL) {
1241                 CERROR("Can't allocate ipaddrs[%d]\n", nif);
1242                 libcfs_ipif_free_enumeration(ifnames, nif);
1243                 return -ENOMEM;
1244         }
1245
1246         for (i = nip = 0; i < nif; i++) {
1247                 if (!strcmp(ifnames[i], "lo"))
1248                         continue;
1249                 
1250                 rc = libcfs_ipif_query(ifnames[i], &up, 
1251                                        &ipaddrs[nip], &netmask);
1252                 if (rc != 0) {
1253                         CWARN("Can't query interface %s: %d\n",
1254                               ifnames[i], rc);
1255                         continue;
1256                 }
1257
1258                 if (!up) {
1259                         CWARN("Ignoring interface %s: it's down\n",
1260                               ifnames[i]);
1261                         continue;
1262                 }
1263
1264                 nip++;
1265         }
1266
1267         libcfs_ipif_free_enumeration(ifnames, nif);
1268
1269         if (nip == nif) {
1270                 *ipaddrsp = ipaddrs;
1271         } else {
1272                 if (nip > 0) {
1273                         LIBCFS_ALLOC(ipaddrs2, nip * sizeof(*ipaddrs2));
1274                         if (ipaddrs2 == NULL) {
1275                                 CERROR("Can't allocate ipaddrs[%d]\n", nip);
1276                                 nip = -ENOMEM;
1277                         } else {
1278                                 memcpy(ipaddrs2, ipaddrs, 
1279                                        nip * sizeof(*ipaddrs));
1280                                 *ipaddrsp = ipaddrs2;
1281                                 rc = nip;
1282                         }
1283                 }
1284                 lnet_ipaddr_free_enumeration(ipaddrs, nif);
1285         }
1286         return nip;
1287 }
1288
1289 int
1290 lnet_parse_ip2nets (char **networksp, char *ip2nets)
1291 {
1292         __u32     *ipaddrs;
1293         int        nip = lnet_ipaddr_enumerate(&ipaddrs);
1294         int        rc;
1295
1296         if (nip < 0) {
1297                 LCONSOLE_ERROR_MSG(0x117, "Error %d enumerating local IP "
1298                                    "interfaces for ip2nets to match\n", nip);
1299                 return nip;
1300         }
1301
1302         if (nip == 0) {
1303                 LCONSOLE_ERROR_MSG(0x118, "No local IP interfaces "
1304                                    "for ip2nets to match\n");
1305                 return -ENOENT;
1306         }
1307
1308         rc = lnet_match_networks(networksp, ip2nets, ipaddrs, nip);
1309         lnet_ipaddr_free_enumeration(ipaddrs, nip);
1310
1311         if (rc < 0) {
1312                 LCONSOLE_ERROR_MSG(0x119, "Error %d parsing ip2nets\n", rc);
1313                 return rc;
1314         }
1315
1316         if (rc == 0) {
1317                 LCONSOLE_ERROR_MSG(0x11a, "ip2nets does not match "
1318                                    "any local IP interfaces\n");
1319                 return -ENOENT;
1320         }
1321
1322         return 0;
1323 }
1324
1325 int
1326 lnet_set_ip_niaddr (lnet_ni_t *ni) 
1327 {
1328         __u32  net = LNET_NIDNET(ni->ni_nid);
1329         char **names;
1330         int    n;
1331         __u32  ip;
1332         __u32  netmask;
1333         int    up;
1334         int    i;
1335         int    rc;
1336
1337         /* Convenience for LNDs that use the IP address of a local interface as
1338          * the local address part of their NID */
1339
1340         if (ni->ni_interfaces[0] != NULL) {
1341
1342                 CLASSERT (LNET_MAX_INTERFACES > 1);
1343
1344                 if (ni->ni_interfaces[1] != NULL) {
1345                         CERROR("Net %s doesn't support multiple interfaces\n",
1346                                libcfs_net2str(net));
1347                         return -EPERM;
1348                 }
1349                 
1350                 rc = libcfs_ipif_query(ni->ni_interfaces[0],
1351                                        &up, &ip, &netmask);
1352                 if (rc != 0) {
1353                         CERROR("Net %s can't query interface %s: %d\n",
1354                                libcfs_net2str(net), ni->ni_interfaces[0], rc);
1355                         return -EPERM;
1356                 }
1357
1358                 if (!up) {
1359                         CERROR("Net %s can't use interface %s: it's down\n",
1360                                libcfs_net2str(net), ni->ni_interfaces[0]);
1361                         return -ENETDOWN;
1362                 }
1363                 
1364                 ni->ni_nid = LNET_MKNID(net, ip);
1365                 return 0;
1366         }
1367
1368         n = libcfs_ipif_enumerate(&names);
1369         if (n <= 0) {
1370                 CERROR("Net %s can't enumerate interfaces: %d\n", 
1371                        libcfs_net2str(net), n);
1372                 return 0;
1373         }
1374
1375         for (i = 0; i < n; i++) {
1376                 if (!strcmp(names[i], "lo")) /* skip the loopback IF */
1377                         continue;
1378                 
1379                 rc = libcfs_ipif_query(names[i], &up, &ip, &netmask);
1380                 
1381                 if (rc != 0) {
1382                         CWARN("Net %s can't query interface %s: %d\n",
1383                               libcfs_net2str(net), names[i], rc);
1384                         continue;
1385                 }
1386                         
1387                 if (!up) {
1388                         CWARN("Net %s ignoring interface %s (down)\n",
1389                               libcfs_net2str(net), names[i]);
1390                         continue;
1391                 }
1392
1393                 libcfs_ipif_free_enumeration(names, n);
1394                 ni->ni_nid = LNET_MKNID(net, ip);
1395                 return 0;
1396         }
1397
1398         CERROR("Net %s can't find any interfaces\n", libcfs_net2str(net));
1399         libcfs_ipif_free_enumeration(names, n);
1400         return -ENOENT;
1401 }
1402 EXPORT_SYMBOL(lnet_set_ip_niaddr);
1403
1404 #endif