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