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