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