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