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