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