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