Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / 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 struct lnet_text_buf_t {            /* 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 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 struct lnet_text_buf_t *
369 lnet_new_text_buf(int str_len)
370 {
371         struct lnet_text_buf_t *ltb;
372         int           nob;
373
374         /* NB allocate space for the terminating 0 */
375         nob = offsetof(struct 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(struct 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         struct lnet_text_buf_t  *ltb;
408
409         while (!list_empty(tbs)) {
410                 ltb = list_entry(tbs->next, struct 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         struct 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         struct 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,
536                            &stride, &scanned) < 3) {
537
538                         if (sscanf(parsed, "%d-%d%n", &lo, &hi, &scanned) < 2) {
539
540                                 /* simple string enumeration */
541                                 if (lnet_expand1tb(
542                                      &pending, str, sep, sep2,
543                                      parsed,
544                                      (int)(enditem - parsed)) != 0) {
545                                         goto failed;
546                                 }
547
548                                 continue;
549                         }
550
551                         stride = 1;
552                 }
553
554                 /* range expansion */
555
556                 if (enditem != parsed + scanned) /* no trailing junk */
557                         goto failed;
558
559                 if (hi < 0 || lo < 0 || stride < 0 || hi < lo ||
560                     (hi - lo) % stride != 0)
561                         goto failed;
562
563                 for (i = lo; i <= hi; i += stride) {
564
565                         snprintf(num, sizeof(num), "%d", i);
566                         nob = strlen(num);
567                         if (nob + 1 == sizeof(num))
568                                 goto failed;
569
570                         if (lnet_expand1tb(&pending, str, sep, sep2,
571                                            num, nob) != 0)
572                                 goto failed;
573                 }
574         }
575
576         list_splice(&pending, tbs->prev);
577         return 1;
578
579  failed:
580         lnet_free_text_bufs(&pending);
581         return -1;
582 }
583
584 static int
585 lnet_parse_hops(char *str, unsigned int *hops)
586 {
587         int     len = strlen(str);
588         int     nob = len;
589
590         return (sscanf(str, "%u%n", hops, &nob) >= 1 &&
591                 nob == len &&
592                 *hops > 0 && *hops < 256);
593 }
594
595 #define LNET_PRIORITY_SEPARATOR (':')
596
597 static int
598 lnet_parse_priority(char *str, unsigned int *priority, char **token)
599 {
600         int   nob;
601         char *sep;
602         int   len;
603
604         sep = strchr(str, LNET_PRIORITY_SEPARATOR);
605         if (sep == NULL) {
606                 *priority = 0;
607                 return 0;
608         }
609         len = strlen(sep + 1);
610
611         if ((sscanf((sep+1), "%u%n", priority, &nob) < 1) || (len != nob)) {
612                 /* Update the caller's token pointer so it treats the found
613                    priority as the token to report in the error message. */
614                 *token += sep - str + 1;
615                 return -1;
616         }
617
618         CDEBUG(D_NET, "gateway %s, priority %d, nob %d\n", str, *priority, nob);
619
620         /*
621          * Change priority separator to \0 to be able to parse NID
622          */
623         *sep = '\0';
624         return 0;
625 }
626
627 static int
628 lnet_parse_route(char *str, int *im_a_router)
629 {
630         /* static scratch buffer OK (single threaded) */
631         static char       cmd[LNET_SINGLE_TEXTBUF_NOB];
632
633         struct list_head        nets;
634         struct list_head        gateways;
635         struct list_head       *tmp1;
636         struct list_head       *tmp2;
637         __u32        net;
638         lnet_nid_t      nid;
639         struct lnet_text_buf_t  *ltb;
640         int            rc;
641         char         *sep;
642         char         *token = str;
643         int            ntokens = 0;
644         int            myrc = -1;
645         unsigned int      hops;
646         int            got_hops = 0;
647         unsigned int      priority = 0;
648
649         INIT_LIST_HEAD(&gateways);
650         INIT_LIST_HEAD(&nets);
651
652         /* save a copy of the string for error messages */
653         strncpy(cmd, str, sizeof(cmd) - 1);
654         cmd[sizeof(cmd) - 1] = 0;
655
656         sep = str;
657         for (;;) {
658                 /* scan for token start */
659                 while (isspace(*sep))
660                         sep++;
661                 if (*sep == 0) {
662                         if (ntokens < (got_hops ? 3 : 2))
663                                 goto token_error;
664                         break;
665                 }
666
667                 ntokens++;
668                 token = sep++;
669
670                 /* scan for token end */
671                 while (*sep != 0 && !isspace(*sep))
672                         sep++;
673                 if (*sep != 0)
674                         *sep++ = 0;
675
676                 if (ntokens == 1) {
677                         tmp2 = &nets;           /* expanding nets */
678                 } else if (ntokens == 2 &&
679                            lnet_parse_hops(token, &hops)) {
680                         got_hops = 1;      /* got a hop count */
681                         continue;
682                 } else {
683                         tmp2 = &gateways;       /* expanding gateways */
684                 }
685
686                 ltb = lnet_new_text_buf(strlen(token));
687                 if (ltb == NULL)
688                         goto out;
689
690                 strcpy(ltb->ltb_text, token);
691                 tmp1 = &ltb->ltb_list;
692                 list_add_tail(tmp1, tmp2);
693
694                 while (tmp1 != tmp2) {
695                         ltb = list_entry(tmp1, struct lnet_text_buf_t,
696                                          ltb_list);
697
698                         rc = lnet_str2tbs_expand(tmp1->next, ltb->ltb_text);
699                         if (rc < 0)
700                                 goto token_error;
701
702                         tmp1 = tmp1->next;
703
704                         if (rc > 0) {           /* expanded! */
705                                 list_del(&ltb->ltb_list);
706                                 lnet_free_text_buf(ltb);
707                                 continue;
708                         }
709
710                         if (ntokens == 1) {
711                                 net = libcfs_str2net(ltb->ltb_text);
712                                 if (net == LNET_NIDNET(LNET_NID_ANY) ||
713                                     LNET_NETTYP(net) == LOLND)
714                                         goto token_error;
715                         } else {
716                                 rc = lnet_parse_priority(ltb->ltb_text,
717                                                          &priority, &token);
718                                 if (rc < 0)
719                                         goto token_error;
720
721                                 nid = libcfs_str2nid(ltb->ltb_text);
722                                 if (nid == LNET_NID_ANY ||
723                                     LNET_NETTYP(LNET_NIDNET(nid)) == LOLND)
724                                         goto token_error;
725                         }
726                 }
727         }
728
729         if (!got_hops)
730                 hops = 1;
731
732         LASSERT(!list_empty(&nets));
733         LASSERT(!list_empty(&gateways));
734
735         list_for_each(tmp1, &nets) {
736                 ltb = list_entry(tmp1, struct lnet_text_buf_t, ltb_list);
737                 net = libcfs_str2net(ltb->ltb_text);
738                 LASSERT(net != LNET_NIDNET(LNET_NID_ANY));
739
740                 list_for_each(tmp2, &gateways) {
741                         ltb = list_entry(tmp2, struct lnet_text_buf_t,
742                                          ltb_list);
743                         nid = libcfs_str2nid(ltb->ltb_text);
744                         LASSERT(nid != LNET_NID_ANY);
745
746                         if (lnet_islocalnid(nid)) {
747                                 *im_a_router = 1;
748                                 continue;
749                         }
750
751                         rc = lnet_add_route(net, hops, nid, priority);
752                         if (rc != 0) {
753                                 CERROR("Can't create route to %s via %s\n",
754                                        libcfs_net2str(net),
755                                        libcfs_nid2str(nid));
756                                 goto out;
757                         }
758                 }
759         }
760
761         myrc = 0;
762         goto out;
763
764  token_error:
765         lnet_syntax("routes", cmd, (int)(token - str), strlen(token));
766  out:
767         lnet_free_text_bufs(&nets);
768         lnet_free_text_bufs(&gateways);
769         return myrc;
770 }
771
772 static int
773 lnet_parse_route_tbs(struct list_head *tbs, int *im_a_router)
774 {
775         struct lnet_text_buf_t   *ltb;
776
777         while (!list_empty(tbs)) {
778                 ltb = list_entry(tbs->next, struct lnet_text_buf_t, ltb_list);
779
780                 if (lnet_parse_route(ltb->ltb_text, im_a_router) < 0) {
781                         lnet_free_text_bufs(tbs);
782                         return -EINVAL;
783                 }
784
785                 list_del(&ltb->ltb_list);
786                 lnet_free_text_buf(ltb);
787         }
788
789         return 0;
790 }
791
792 int
793 lnet_parse_routes(char *routes, int *im_a_router)
794 {
795         struct list_head        tbs;
796         int            rc = 0;
797
798         *im_a_router = 0;
799
800         INIT_LIST_HEAD(&tbs);
801
802         if (lnet_str2tbs_sep(&tbs, routes) < 0) {
803                 CERROR("Error parsing routes\n");
804                 rc = -EINVAL;
805         } else {
806                 rc = lnet_parse_route_tbs(&tbs, im_a_router);
807         }
808
809         LASSERT(lnet_tbnob == 0);
810         return rc;
811 }
812
813 static int
814 lnet_match_network_token(char *token, int len, __u32 *ipaddrs, int nip)
815 {
816         LIST_HEAD(list);
817         int             rc;
818         int             i;
819
820         rc = cfs_ip_addr_parse(token, len, &list);
821         if (rc != 0)
822                 return rc;
823
824         for (rc = i = 0; !rc && i < nip; i++)
825                 rc = cfs_ip_addr_match(ipaddrs[i], &list);
826
827         cfs_ip_addr_free(&list);
828
829         return rc;
830 }
831
832 static int
833 lnet_match_network_tokens(char *net_entry, __u32 *ipaddrs, int nip)
834 {
835         static char tokens[LNET_SINGLE_TEXTBUF_NOB];
836
837         int   matched = 0;
838         int   ntokens = 0;
839         int   len;
840         char *net = NULL;
841         char *sep;
842         char *token;
843         int   rc;
844
845         LASSERT(strlen(net_entry) < sizeof(tokens));
846
847         /* work on a copy of the string */
848         strcpy(tokens, net_entry);
849         sep = tokens;
850         for (;;) {
851                 /* scan for token start */
852                 while (isspace(*sep))
853                         sep++;
854                 if (*sep == 0)
855                         break;
856
857                 token = sep++;
858
859                 /* scan for token end */
860                 while (*sep != 0 && !isspace(*sep))
861                         sep++;
862                 if (*sep != 0)
863                         *sep++ = 0;
864
865                 if (ntokens++ == 0) {
866                         net = token;
867                         continue;
868                 }
869
870                 len = strlen(token);
871
872                 rc = lnet_match_network_token(token, len, ipaddrs, nip);
873                 if (rc < 0) {
874                         lnet_syntax("ip2nets", net_entry,
875                                     (int)(token - tokens), len);
876                         return rc;
877                 }
878
879                 matched |= (rc != 0);
880         }
881
882         if (!matched)
883                 return 0;
884
885         strcpy(net_entry, net);          /* replace with matched net */
886         return 1;
887 }
888
889 static __u32
890 lnet_netspec2net(char *netspec)
891 {
892         char   *bracket = strchr(netspec, '(');
893         __u32   net;
894
895         if (bracket != NULL)
896                 *bracket = 0;
897
898         net = libcfs_str2net(netspec);
899
900         if (bracket != NULL)
901                 *bracket = '(';
902
903         return net;
904 }
905
906 static int
907 lnet_splitnets(char *source, struct list_head *nets)
908 {
909         int            offset = 0;
910         int            offset2;
911         int            len;
912         struct lnet_text_buf_t  *tb;
913         struct lnet_text_buf_t  *tb2;
914         struct list_head       *t;
915         char         *sep;
916         char         *bracket;
917         __u32        net;
918
919         LASSERT(!list_empty(nets));
920         LASSERT(nets->next == nets->prev);     /* single entry */
921
922         tb = list_entry(nets->next, struct lnet_text_buf_t, ltb_list);
923
924         for (;;) {
925                 sep = strchr(tb->ltb_text, ',');
926                 bracket = strchr(tb->ltb_text, '(');
927
928                 if (sep != NULL &&
929                     bracket != NULL &&
930                     bracket < sep) {
931                         /* netspec lists interfaces... */
932
933                         offset2 = offset + (int)(bracket - tb->ltb_text);
934                         len = strlen(bracket);
935
936                         bracket = strchr(bracket + 1, ')');
937
938                         if (bracket == NULL ||
939                             !(bracket[1] == ',' || bracket[1] == 0)) {
940                                 lnet_syntax("ip2nets", source, offset2, len);
941                                 return -EINVAL;
942                         }
943
944                         sep = (bracket[1] == 0) ? NULL : bracket + 1;
945                 }
946
947                 if (sep != NULL)
948                         *sep++ = 0;
949
950                 net = lnet_netspec2net(tb->ltb_text);
951                 if (net == LNET_NIDNET(LNET_NID_ANY)) {
952                         lnet_syntax("ip2nets", source, offset,
953                                     strlen(tb->ltb_text));
954                         return -EINVAL;
955                 }
956
957                 list_for_each(t, nets) {
958                         tb2 = list_entry(t, struct lnet_text_buf_t, ltb_list);
959
960                         if (tb2 == tb)
961                                 continue;
962
963                         if (net == lnet_netspec2net(tb2->ltb_text)) {
964                                 /* duplicate network */
965                                 lnet_syntax("ip2nets", source, offset,
966                                             strlen(tb->ltb_text));
967                                 return -EINVAL;
968                         }
969                 }
970
971                 if (sep == NULL)
972                         return 0;
973
974                 offset += (int)(sep - tb->ltb_text);
975                 tb2 = lnet_new_text_buf(strlen(sep));
976                 if (tb2 == NULL)
977                         return -ENOMEM;
978
979                 strcpy(tb2->ltb_text, sep);
980                 list_add_tail(&tb2->ltb_list, nets);
981
982                 tb = tb2;
983         }
984 }
985
986 static int
987 lnet_match_networks(char **networksp, char *ip2nets, __u32 *ipaddrs, int nip)
988 {
989         static char     networks[LNET_SINGLE_TEXTBUF_NOB];
990         static char     source[LNET_SINGLE_TEXTBUF_NOB];
991
992         struct list_head          raw_entries;
993         struct list_head          matched_nets;
994         struct list_head          current_nets;
995         struct list_head         *t;
996         struct list_head         *t2;
997         struct lnet_text_buf_t    *tb;
998         struct lnet_text_buf_t    *tb2;
999         __u32          net1;
1000         __u32          net2;
1001         int              len;
1002         int              count;
1003         int              dup;
1004         int              rc;
1005
1006         INIT_LIST_HEAD(&raw_entries);
1007         if (lnet_str2tbs_sep(&raw_entries, ip2nets) < 0) {
1008                 CERROR("Error parsing ip2nets\n");
1009                 LASSERT(lnet_tbnob == 0);
1010                 return -EINVAL;
1011         }
1012
1013         INIT_LIST_HEAD(&matched_nets);
1014         INIT_LIST_HEAD(&current_nets);
1015         networks[0] = 0;
1016         count = 0;
1017         len = 0;
1018         rc = 0;
1019
1020         while (!list_empty(&raw_entries)) {
1021                 tb = list_entry(raw_entries.next, struct lnet_text_buf_t,
1022                                     ltb_list);
1023
1024                 strncpy(source, tb->ltb_text, sizeof(source)-1);
1025                 source[sizeof(source)-1] = 0;
1026
1027                 /* replace ltb_text with the network(s) add on match */
1028                 rc = lnet_match_network_tokens(tb->ltb_text, ipaddrs, nip);
1029                 if (rc < 0)
1030                         break;
1031
1032                 list_del(&tb->ltb_list);
1033
1034                 if (rc == 0) {            /* no match */
1035                         lnet_free_text_buf(tb);
1036                         continue;
1037                 }
1038
1039                 /* split into separate networks */
1040                 INIT_LIST_HEAD(&current_nets);
1041                 list_add(&tb->ltb_list, &current_nets);
1042                 rc = lnet_splitnets(source, &current_nets);
1043                 if (rc < 0)
1044                         break;
1045
1046                 dup = 0;
1047                 list_for_each(t, &current_nets) {
1048                         tb = list_entry(t, struct lnet_text_buf_t, ltb_list);
1049                         net1 = lnet_netspec2net(tb->ltb_text);
1050                         LASSERT(net1 != LNET_NIDNET(LNET_NID_ANY));
1051
1052                         list_for_each(t2, &matched_nets) {
1053                                 tb2 = list_entry(t2, struct lnet_text_buf_t,
1054                                                      ltb_list);
1055                                 net2 = lnet_netspec2net(tb2->ltb_text);
1056                                 LASSERT(net2 != LNET_NIDNET(LNET_NID_ANY));
1057
1058                                 if (net1 == net2) {
1059                                         dup = 1;
1060                                         break;
1061                                 }
1062                         }
1063
1064                         if (dup)
1065                                 break;
1066                 }
1067
1068                 if (dup) {
1069                         lnet_free_text_bufs(&current_nets);
1070                         continue;
1071                 }
1072
1073                 list_for_each_safe(t, t2, &current_nets) {
1074                         tb = list_entry(t, struct lnet_text_buf_t, ltb_list);
1075
1076                         list_del(&tb->ltb_list);
1077                         list_add_tail(&tb->ltb_list, &matched_nets);
1078
1079                         len += snprintf(networks + len, sizeof(networks) - len,
1080                                         "%s%s", (len == 0) ? "" : ",",
1081                                         tb->ltb_text);
1082
1083                         if (len >= sizeof(networks)) {
1084                                 CERROR("Too many matched networks\n");
1085                                 rc = -E2BIG;
1086                                 goto out;
1087                         }
1088                 }
1089
1090                 count++;
1091         }
1092
1093  out:
1094         lnet_free_text_bufs(&raw_entries);
1095         lnet_free_text_bufs(&matched_nets);
1096         lnet_free_text_bufs(&current_nets);
1097         LASSERT(lnet_tbnob == 0);
1098
1099         if (rc < 0)
1100                 return rc;
1101
1102         *networksp = networks;
1103         return count;
1104 }
1105
1106 static void
1107 lnet_ipaddr_free_enumeration(__u32 *ipaddrs, int nip)
1108 {
1109         LIBCFS_FREE(ipaddrs, nip * sizeof(*ipaddrs));
1110 }
1111
1112 static int
1113 lnet_ipaddr_enumerate(__u32 **ipaddrsp)
1114 {
1115         int     up;
1116         __u32      netmask;
1117         __u32     *ipaddrs;
1118         __u32     *ipaddrs2;
1119         int     nip;
1120         char     **ifnames;
1121         int     nif = libcfs_ipif_enumerate(&ifnames);
1122         int     i;
1123         int     rc;
1124
1125         if (nif <= 0)
1126                 return nif;
1127
1128         LIBCFS_ALLOC(ipaddrs, nif * sizeof(*ipaddrs));
1129         if (ipaddrs == NULL) {
1130                 CERROR("Can't allocate ipaddrs[%d]\n", nif);
1131                 libcfs_ipif_free_enumeration(ifnames, nif);
1132                 return -ENOMEM;
1133         }
1134
1135         for (i = nip = 0; i < nif; i++) {
1136                 if (!strcmp(ifnames[i], "lo"))
1137                         continue;
1138
1139                 rc = libcfs_ipif_query(ifnames[i], &up,
1140                                        &ipaddrs[nip], &netmask);
1141                 if (rc != 0) {
1142                         CWARN("Can't query interface %s: %d\n",
1143                               ifnames[i], rc);
1144                         continue;
1145                 }
1146
1147                 if (!up) {
1148                         CWARN("Ignoring interface %s: it's down\n",
1149                               ifnames[i]);
1150                         continue;
1151                 }
1152
1153                 nip++;
1154         }
1155
1156         libcfs_ipif_free_enumeration(ifnames, nif);
1157
1158         if (nip == nif) {
1159                 *ipaddrsp = ipaddrs;
1160         } else {
1161                 if (nip > 0) {
1162                         LIBCFS_ALLOC(ipaddrs2, nip * sizeof(*ipaddrs2));
1163                         if (ipaddrs2 == NULL) {
1164                                 CERROR("Can't allocate ipaddrs[%d]\n", nip);
1165                                 nip = -ENOMEM;
1166                         } else {
1167                                 memcpy(ipaddrs2, ipaddrs,
1168                                        nip * sizeof(*ipaddrs));
1169                                 *ipaddrsp = ipaddrs2;
1170                                 rc = nip;
1171                         }
1172                 }
1173                 lnet_ipaddr_free_enumeration(ipaddrs, nif);
1174         }
1175         return nip;
1176 }
1177
1178 int
1179 lnet_parse_ip2nets(char **networksp, char *ip2nets)
1180 {
1181         __u32     *ipaddrs = NULL;
1182         int     nip = lnet_ipaddr_enumerate(&ipaddrs);
1183         int     rc;
1184
1185         if (nip < 0) {
1186                 LCONSOLE_ERROR_MSG(0x117,
1187                                    "Error %d enumerating local IP interfaces for ip2nets to match\n",
1188                                    nip);
1189                 return nip;
1190         }
1191
1192         if (nip == 0) {
1193                 LCONSOLE_ERROR_MSG(0x118,
1194                                    "No local IP interfaces for ip2nets to match\n");
1195                 return -ENOENT;
1196         }
1197
1198         rc = lnet_match_networks(networksp, ip2nets, ipaddrs, nip);
1199         lnet_ipaddr_free_enumeration(ipaddrs, nip);
1200
1201         if (rc < 0) {
1202                 LCONSOLE_ERROR_MSG(0x119, "Error %d parsing ip2nets\n", rc);
1203                 return rc;
1204         }
1205
1206         if (rc == 0) {
1207                 LCONSOLE_ERROR_MSG(0x11a,
1208                                    "ip2nets does not match any local IP interfaces\n");
1209                 return -ENOENT;
1210         }
1211
1212         return 0;
1213 }
1214
1215 int
1216 lnet_set_ip_niaddr(lnet_ni_t *ni)
1217 {
1218         __u32  net = LNET_NIDNET(ni->ni_nid);
1219         char **names;
1220         int    n;
1221         __u32  ip;
1222         __u32  netmask;
1223         int    up;
1224         int    i;
1225         int    rc;
1226
1227         /* Convenience for LNDs that use the IP address of a local interface as
1228          * the local address part of their NID */
1229
1230         if (ni->ni_interfaces[0] != NULL) {
1231
1232                 CLASSERT(LNET_MAX_INTERFACES > 1);
1233
1234                 if (ni->ni_interfaces[1] != NULL) {
1235                         CERROR("Net %s doesn't support multiple interfaces\n",
1236                                libcfs_net2str(net));
1237                         return -EPERM;
1238                 }
1239
1240                 rc = libcfs_ipif_query(ni->ni_interfaces[0],
1241                                        &up, &ip, &netmask);
1242                 if (rc != 0) {
1243                         CERROR("Net %s can't query interface %s: %d\n",
1244                                libcfs_net2str(net), ni->ni_interfaces[0], rc);
1245                         return -EPERM;
1246                 }
1247
1248                 if (!up) {
1249                         CERROR("Net %s can't use interface %s: it's down\n",
1250                                libcfs_net2str(net), ni->ni_interfaces[0]);
1251                         return -ENETDOWN;
1252                 }
1253
1254                 ni->ni_nid = LNET_MKNID(net, ip);
1255                 return 0;
1256         }
1257
1258         n = libcfs_ipif_enumerate(&names);
1259         if (n <= 0) {
1260                 CERROR("Net %s can't enumerate interfaces: %d\n",
1261                        libcfs_net2str(net), n);
1262                 return 0;
1263         }
1264
1265         for (i = 0; i < n; i++) {
1266                 if (!strcmp(names[i], "lo")) /* skip the loopback IF */
1267                         continue;
1268
1269                 rc = libcfs_ipif_query(names[i], &up, &ip, &netmask);
1270
1271                 if (rc != 0) {
1272                         CWARN("Net %s can't query interface %s: %d\n",
1273                               libcfs_net2str(net), names[i], rc);
1274                         continue;
1275                 }
1276
1277                 if (!up) {
1278                         CWARN("Net %s ignoring interface %s (down)\n",
1279                               libcfs_net2str(net), names[i]);
1280                         continue;
1281                 }
1282
1283                 libcfs_ipif_free_enumeration(names, n);
1284                 ni->ni_nid = LNET_MKNID(net, ip);
1285                 return 0;
1286         }
1287
1288         CERROR("Net %s can't find any interfaces\n", libcfs_net2str(net));
1289         libcfs_ipif_free_enumeration(names, n);
1290         return -ENOENT;
1291 }
1292 EXPORT_SYMBOL(lnet_set_ip_niaddr);