Merge branch 'x86-iommu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / drivers / staging / lustre / lnet / lnet / config.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.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 <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 = cfs_time_current_sec();
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 (cfs_iswhite(*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 (cfs_iswhite(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
607 int
608 lnet_parse_route(char *str, int *im_a_router)
609 {
610         /* static scratch buffer OK (single threaded) */
611         static char       cmd[LNET_SINGLE_TEXTBUF_NOB];
612
613         struct list_head        nets;
614         struct list_head        gateways;
615         struct list_head       *tmp1;
616         struct list_head       *tmp2;
617         __u32        net;
618         lnet_nid_t      nid;
619         lnet_text_buf_t  *ltb;
620         int            rc;
621         char         *sep;
622         char         *token = str;
623         int            ntokens = 0;
624         int            myrc = -1;
625         unsigned int      hops;
626         int            got_hops = 0;
627
628         INIT_LIST_HEAD(&gateways);
629         INIT_LIST_HEAD(&nets);
630
631         /* save a copy of the string for error messages */
632         strncpy(cmd, str, sizeof(cmd) - 1);
633         cmd[sizeof(cmd) - 1] = 0;
634
635         sep = str;
636         for (;;) {
637                 /* scan for token start */
638                 while (cfs_iswhite(*sep))
639                         sep++;
640                 if (*sep == 0) {
641                         if (ntokens < (got_hops ? 3 : 2))
642                                 goto token_error;
643                         break;
644                 }
645
646                 ntokens++;
647                 token = sep++;
648
649                 /* scan for token end */
650                 while (*sep != 0 && !cfs_iswhite(*sep))
651                         sep++;
652                 if (*sep != 0)
653                         *sep++ = 0;
654
655                 if (ntokens == 1) {
656                         tmp2 = &nets;           /* expanding nets */
657                 } else if (ntokens == 2 &&
658                            lnet_parse_hops(token, &hops)) {
659                         got_hops = 1;      /* got a hop count */
660                         continue;
661                 } else {
662                         tmp2 = &gateways;       /* expanding gateways */
663                 }
664
665                 ltb = lnet_new_text_buf(strlen(token));
666                 if (ltb == NULL)
667                         goto out;
668
669                 strcpy(ltb->ltb_text, token);
670                 tmp1 = &ltb->ltb_list;
671                 list_add_tail(tmp1, tmp2);
672
673                 while (tmp1 != tmp2) {
674                         ltb = list_entry(tmp1, lnet_text_buf_t, ltb_list);
675
676                         rc = lnet_str2tbs_expand(tmp1->next, ltb->ltb_text);
677                         if (rc < 0)
678                                 goto token_error;
679
680                         tmp1 = tmp1->next;
681
682                         if (rc > 0) {           /* expanded! */
683                                 list_del(&ltb->ltb_list);
684                                 lnet_free_text_buf(ltb);
685                                 continue;
686                         }
687
688                         if (ntokens == 1) {
689                                 net = libcfs_str2net(ltb->ltb_text);
690                                 if (net == LNET_NIDNET(LNET_NID_ANY) ||
691                                     LNET_NETTYP(net) == LOLND)
692                                         goto token_error;
693                         } else {
694                                 nid = libcfs_str2nid(ltb->ltb_text);
695                                 if (nid == LNET_NID_ANY ||
696                                     LNET_NETTYP(LNET_NIDNET(nid)) == LOLND)
697                                         goto token_error;
698                         }
699                 }
700         }
701
702         if (!got_hops)
703                 hops = 1;
704
705         LASSERT(!list_empty(&nets));
706         LASSERT(!list_empty(&gateways));
707
708         list_for_each(tmp1, &nets) {
709                 ltb = list_entry(tmp1, lnet_text_buf_t, ltb_list);
710                 net = libcfs_str2net(ltb->ltb_text);
711                 LASSERT(net != LNET_NIDNET(LNET_NID_ANY));
712
713                 list_for_each(tmp2, &gateways) {
714                         ltb = list_entry(tmp2, lnet_text_buf_t, ltb_list);
715                         nid = libcfs_str2nid(ltb->ltb_text);
716                         LASSERT(nid != LNET_NID_ANY);
717
718                         if (lnet_islocalnid(nid)) {
719                                 *im_a_router = 1;
720                                 continue;
721                         }
722
723                         rc = lnet_add_route(net, hops, nid);
724                         if (rc != 0) {
725                                 CERROR("Can't create route to %s via %s\n",
726                                        libcfs_net2str(net),
727                                        libcfs_nid2str(nid));
728                                 goto out;
729                         }
730                 }
731         }
732
733         myrc = 0;
734         goto out;
735
736  token_error:
737         lnet_syntax("routes", cmd, (int)(token - str), strlen(token));
738  out:
739         lnet_free_text_bufs(&nets);
740         lnet_free_text_bufs(&gateways);
741         return myrc;
742 }
743
744 int
745 lnet_parse_route_tbs(struct list_head *tbs, int *im_a_router)
746 {
747         lnet_text_buf_t   *ltb;
748
749         while (!list_empty(tbs)) {
750                 ltb = list_entry(tbs->next, lnet_text_buf_t, ltb_list);
751
752                 if (lnet_parse_route(ltb->ltb_text, im_a_router) < 0) {
753                         lnet_free_text_bufs(tbs);
754                         return -EINVAL;
755                 }
756
757                 list_del(&ltb->ltb_list);
758                 lnet_free_text_buf(ltb);
759         }
760
761         return 0;
762 }
763
764 int
765 lnet_parse_routes(char *routes, int *im_a_router)
766 {
767         struct list_head        tbs;
768         int            rc = 0;
769
770         *im_a_router = 0;
771
772         INIT_LIST_HEAD(&tbs);
773
774         if (lnet_str2tbs_sep(&tbs, routes) < 0) {
775                 CERROR("Error parsing routes\n");
776                 rc = -EINVAL;
777         } else {
778                 rc = lnet_parse_route_tbs(&tbs, im_a_router);
779         }
780
781         LASSERT(lnet_tbnob == 0);
782         return rc;
783 }
784
785 int
786 lnet_match_network_token(char *token, int len, __u32 *ipaddrs, int nip)
787 {
788         LIST_HEAD(list);
789         int             rc;
790         int             i;
791
792         rc = cfs_ip_addr_parse(token, len, &list);
793         if (rc != 0)
794                 return rc;
795
796         for (rc = i = 0; !rc && i < nip; i++)
797                 rc = cfs_ip_addr_match(ipaddrs[i], &list);
798
799         cfs_ip_addr_free(&list);
800
801         return rc;
802 }
803
804 int
805 lnet_match_network_tokens(char *net_entry, __u32 *ipaddrs, int nip)
806 {
807         static char tokens[LNET_SINGLE_TEXTBUF_NOB];
808
809         int   matched = 0;
810         int   ntokens = 0;
811         int   len;
812         char *net = NULL;
813         char *sep;
814         char *token;
815         int   rc;
816
817         LASSERT(strlen(net_entry) < sizeof(tokens));
818
819         /* work on a copy of the string */
820         strcpy(tokens, net_entry);
821         sep = tokens;
822         for (;;) {
823                 /* scan for token start */
824                 while (cfs_iswhite(*sep))
825                         sep++;
826                 if (*sep == 0)
827                         break;
828
829                 token = sep++;
830
831                 /* scan for token end */
832                 while (*sep != 0 && !cfs_iswhite(*sep))
833                         sep++;
834                 if (*sep != 0)
835                         *sep++ = 0;
836
837                 if (ntokens++ == 0) {
838                         net = token;
839                         continue;
840                 }
841
842                 len = strlen(token);
843
844                 rc = lnet_match_network_token(token, len, ipaddrs, nip);
845                 if (rc < 0) {
846                         lnet_syntax("ip2nets", net_entry,
847                                     (int)(token - tokens), len);
848                         return rc;
849                 }
850
851                 matched |= (rc != 0);
852         }
853
854         if (!matched)
855                 return 0;
856
857         strcpy(net_entry, net);          /* replace with matched net */
858         return 1;
859 }
860
861 __u32
862 lnet_netspec2net(char *netspec)
863 {
864         char   *bracket = strchr(netspec, '(');
865         __u32   net;
866
867         if (bracket != NULL)
868                 *bracket = 0;
869
870         net = libcfs_str2net(netspec);
871
872         if (bracket != NULL)
873                 *bracket = '(';
874
875         return net;
876 }
877
878 int
879 lnet_splitnets(char *source, struct list_head *nets)
880 {
881         int            offset = 0;
882         int            offset2;
883         int            len;
884         lnet_text_buf_t  *tb;
885         lnet_text_buf_t  *tb2;
886         struct list_head       *t;
887         char         *sep;
888         char         *bracket;
889         __u32        net;
890
891         LASSERT(!list_empty(nets));
892         LASSERT(nets->next == nets->prev);     /* single entry */
893
894         tb = list_entry(nets->next, lnet_text_buf_t, ltb_list);
895
896         for (;;) {
897                 sep = strchr(tb->ltb_text, ',');
898                 bracket = strchr(tb->ltb_text, '(');
899
900                 if (sep != NULL &&
901                     bracket != NULL &&
902                     bracket < sep) {
903                         /* netspec lists interfaces... */
904
905                         offset2 = offset + (int)(bracket - tb->ltb_text);
906                         len = strlen(bracket);
907
908                         bracket = strchr(bracket + 1, ')');
909
910                         if (bracket == NULL ||
911                             !(bracket[1] == ',' || bracket[1] == 0)) {
912                                 lnet_syntax("ip2nets", source, offset2, len);
913                                 return -EINVAL;
914                         }
915
916                         sep = (bracket[1] == 0) ? NULL : bracket + 1;
917                 }
918
919                 if (sep != NULL)
920                         *sep++ = 0;
921
922                 net = lnet_netspec2net(tb->ltb_text);
923                 if (net == LNET_NIDNET(LNET_NID_ANY)) {
924                         lnet_syntax("ip2nets", source, offset,
925                                     strlen(tb->ltb_text));
926                         return -EINVAL;
927                 }
928
929                 list_for_each(t, nets) {
930                         tb2 = list_entry(t, lnet_text_buf_t, ltb_list);
931
932                         if (tb2 == tb)
933                                 continue;
934
935                         if (net == lnet_netspec2net(tb2->ltb_text)) {
936                                 /* duplicate network */
937                                 lnet_syntax("ip2nets", source, offset,
938                                             strlen(tb->ltb_text));
939                                 return -EINVAL;
940                         }
941                 }
942
943                 if (sep == NULL)
944                         return 0;
945
946                 offset += (int)(sep - tb->ltb_text);
947                 tb2 = lnet_new_text_buf(strlen(sep));
948                 if (tb2 == NULL)
949                         return -ENOMEM;
950
951                 strcpy(tb2->ltb_text, sep);
952                 list_add_tail(&tb2->ltb_list, nets);
953
954                 tb = tb2;
955         }
956 }
957
958 int
959 lnet_match_networks(char **networksp, char *ip2nets, __u32 *ipaddrs, int nip)
960 {
961         static char     networks[LNET_SINGLE_TEXTBUF_NOB];
962         static char     source[LNET_SINGLE_TEXTBUF_NOB];
963
964         struct list_head          raw_entries;
965         struct list_head          matched_nets;
966         struct list_head          current_nets;
967         struct list_head         *t;
968         struct list_head         *t2;
969         lnet_text_buf_t    *tb;
970         lnet_text_buf_t    *tb2;
971         __u32          net1;
972         __u32          net2;
973         int              len;
974         int              count;
975         int              dup;
976         int              rc;
977
978         INIT_LIST_HEAD(&raw_entries);
979         if (lnet_str2tbs_sep(&raw_entries, ip2nets) < 0) {
980                 CERROR("Error parsing ip2nets\n");
981                 LASSERT(lnet_tbnob == 0);
982                 return -EINVAL;
983         }
984
985         INIT_LIST_HEAD(&matched_nets);
986         INIT_LIST_HEAD(&current_nets);
987         networks[0] = 0;
988         count = 0;
989         len = 0;
990         rc = 0;
991
992         while (!list_empty(&raw_entries)) {
993                 tb = list_entry(raw_entries.next, lnet_text_buf_t,
994                                     ltb_list);
995
996                 strncpy(source, tb->ltb_text, sizeof(source)-1);
997                 source[sizeof(source)-1] = 0;
998
999                 /* replace ltb_text with the network(s) add on match */
1000                 rc = lnet_match_network_tokens(tb->ltb_text, ipaddrs, nip);
1001                 if (rc < 0)
1002                         break;
1003
1004                 list_del(&tb->ltb_list);
1005
1006                 if (rc == 0) {            /* no match */
1007                         lnet_free_text_buf(tb);
1008                         continue;
1009                 }
1010
1011                 /* split into separate networks */
1012                 INIT_LIST_HEAD(&current_nets);
1013                 list_add(&tb->ltb_list, &current_nets);
1014                 rc = lnet_splitnets(source, &current_nets);
1015                 if (rc < 0)
1016                         break;
1017
1018                 dup = 0;
1019                 list_for_each(t, &current_nets) {
1020                         tb = list_entry(t, lnet_text_buf_t, ltb_list);
1021                         net1 = lnet_netspec2net(tb->ltb_text);
1022                         LASSERT(net1 != LNET_NIDNET(LNET_NID_ANY));
1023
1024                         list_for_each(t2, &matched_nets) {
1025                                 tb2 = list_entry(t2, lnet_text_buf_t,
1026                                                      ltb_list);
1027                                 net2 = lnet_netspec2net(tb2->ltb_text);
1028                                 LASSERT(net2 != LNET_NIDNET(LNET_NID_ANY));
1029
1030                                 if (net1 == net2) {
1031                                         dup = 1;
1032                                         break;
1033                                 }
1034                         }
1035
1036                         if (dup)
1037                                 break;
1038                 }
1039
1040                 if (dup) {
1041                         lnet_free_text_bufs(&current_nets);
1042                         continue;
1043                 }
1044
1045                 list_for_each_safe(t, t2, &current_nets) {
1046                         tb = list_entry(t, lnet_text_buf_t, ltb_list);
1047
1048                         list_del(&tb->ltb_list);
1049                         list_add_tail(&tb->ltb_list, &matched_nets);
1050
1051                         len += snprintf(networks + len, sizeof(networks) - len,
1052                                         "%s%s", (len == 0) ? "" : ",",
1053                                         tb->ltb_text);
1054
1055                         if (len >= sizeof(networks)) {
1056                                 CERROR("Too many matched networks\n");
1057                                 rc = -E2BIG;
1058                                 goto out;
1059                         }
1060                 }
1061
1062                 count++;
1063         }
1064
1065  out:
1066         lnet_free_text_bufs(&raw_entries);
1067         lnet_free_text_bufs(&matched_nets);
1068         lnet_free_text_bufs(&current_nets);
1069         LASSERT(lnet_tbnob == 0);
1070
1071         if (rc < 0)
1072                 return rc;
1073
1074         *networksp = networks;
1075         return count;
1076 }
1077
1078 void
1079 lnet_ipaddr_free_enumeration(__u32 *ipaddrs, int nip)
1080 {
1081         LIBCFS_FREE(ipaddrs, nip * sizeof(*ipaddrs));
1082 }
1083
1084 int
1085 lnet_ipaddr_enumerate(__u32 **ipaddrsp)
1086 {
1087         int     up;
1088         __u32      netmask;
1089         __u32     *ipaddrs;
1090         __u32     *ipaddrs2;
1091         int     nip;
1092         char     **ifnames;
1093         int     nif = libcfs_ipif_enumerate(&ifnames);
1094         int     i;
1095         int     rc;
1096
1097         if (nif <= 0)
1098                 return nif;
1099
1100         LIBCFS_ALLOC(ipaddrs, nif * sizeof(*ipaddrs));
1101         if (ipaddrs == NULL) {
1102                 CERROR("Can't allocate ipaddrs[%d]\n", nif);
1103                 libcfs_ipif_free_enumeration(ifnames, nif);
1104                 return -ENOMEM;
1105         }
1106
1107         for (i = nip = 0; i < nif; i++) {
1108                 if (!strcmp(ifnames[i], "lo"))
1109                         continue;
1110
1111                 rc = libcfs_ipif_query(ifnames[i], &up,
1112                                        &ipaddrs[nip], &netmask);
1113                 if (rc != 0) {
1114                         CWARN("Can't query interface %s: %d\n",
1115                               ifnames[i], rc);
1116                         continue;
1117                 }
1118
1119                 if (!up) {
1120                         CWARN("Ignoring interface %s: it's down\n",
1121                               ifnames[i]);
1122                         continue;
1123                 }
1124
1125                 nip++;
1126         }
1127
1128         libcfs_ipif_free_enumeration(ifnames, nif);
1129
1130         if (nip == nif) {
1131                 *ipaddrsp = ipaddrs;
1132         } else {
1133                 if (nip > 0) {
1134                         LIBCFS_ALLOC(ipaddrs2, nip * sizeof(*ipaddrs2));
1135                         if (ipaddrs2 == NULL) {
1136                                 CERROR("Can't allocate ipaddrs[%d]\n", nip);
1137                                 nip = -ENOMEM;
1138                         } else {
1139                                 memcpy(ipaddrs2, ipaddrs,
1140                                        nip * sizeof(*ipaddrs));
1141                                 *ipaddrsp = ipaddrs2;
1142                                 rc = nip;
1143                         }
1144                 }
1145                 lnet_ipaddr_free_enumeration(ipaddrs, nif);
1146         }
1147         return nip;
1148 }
1149
1150 int
1151 lnet_parse_ip2nets(char **networksp, char *ip2nets)
1152 {
1153         __u32     *ipaddrs;
1154         int     nip = lnet_ipaddr_enumerate(&ipaddrs);
1155         int     rc;
1156
1157         if (nip < 0) {
1158                 LCONSOLE_ERROR_MSG(0x117,
1159                                    "Error %d enumerating local IP interfaces for ip2nets to match\n",
1160                                    nip);
1161                 return nip;
1162         }
1163
1164         if (nip == 0) {
1165                 LCONSOLE_ERROR_MSG(0x118,
1166                                    "No local IP interfaces for ip2nets to match\n");
1167                 return -ENOENT;
1168         }
1169
1170         rc = lnet_match_networks(networksp, ip2nets, ipaddrs, nip);
1171         lnet_ipaddr_free_enumeration(ipaddrs, nip);
1172
1173         if (rc < 0) {
1174                 LCONSOLE_ERROR_MSG(0x119, "Error %d parsing ip2nets\n", rc);
1175                 return rc;
1176         }
1177
1178         if (rc == 0) {
1179                 LCONSOLE_ERROR_MSG(0x11a,
1180                                    "ip2nets does not match any local IP interfaces\n");
1181                 return -ENOENT;
1182         }
1183
1184         return 0;
1185 }
1186
1187 int
1188 lnet_set_ip_niaddr(lnet_ni_t *ni)
1189 {
1190         __u32  net = LNET_NIDNET(ni->ni_nid);
1191         char **names;
1192         int    n;
1193         __u32  ip;
1194         __u32  netmask;
1195         int    up;
1196         int    i;
1197         int    rc;
1198
1199         /* Convenience for LNDs that use the IP address of a local interface as
1200          * the local address part of their NID */
1201
1202         if (ni->ni_interfaces[0] != NULL) {
1203
1204                 CLASSERT(LNET_MAX_INTERFACES > 1);
1205
1206                 if (ni->ni_interfaces[1] != NULL) {
1207                         CERROR("Net %s doesn't support multiple interfaces\n",
1208                                libcfs_net2str(net));
1209                         return -EPERM;
1210                 }
1211
1212                 rc = libcfs_ipif_query(ni->ni_interfaces[0],
1213                                        &up, &ip, &netmask);
1214                 if (rc != 0) {
1215                         CERROR("Net %s can't query interface %s: %d\n",
1216                                libcfs_net2str(net), ni->ni_interfaces[0], rc);
1217                         return -EPERM;
1218                 }
1219
1220                 if (!up) {
1221                         CERROR("Net %s can't use interface %s: it's down\n",
1222                                libcfs_net2str(net), ni->ni_interfaces[0]);
1223                         return -ENETDOWN;
1224                 }
1225
1226                 ni->ni_nid = LNET_MKNID(net, ip);
1227                 return 0;
1228         }
1229
1230         n = libcfs_ipif_enumerate(&names);
1231         if (n <= 0) {
1232                 CERROR("Net %s can't enumerate interfaces: %d\n",
1233                        libcfs_net2str(net), n);
1234                 return 0;
1235         }
1236
1237         for (i = 0; i < n; i++) {
1238                 if (!strcmp(names[i], "lo")) /* skip the loopback IF */
1239                         continue;
1240
1241                 rc = libcfs_ipif_query(names[i], &up, &ip, &netmask);
1242
1243                 if (rc != 0) {
1244                         CWARN("Net %s can't query interface %s: %d\n",
1245                               libcfs_net2str(net), names[i], rc);
1246                         continue;
1247                 }
1248
1249                 if (!up) {
1250                         CWARN("Net %s ignoring interface %s (down)\n",
1251                               libcfs_net2str(net), names[i]);
1252                         continue;
1253                 }
1254
1255                 libcfs_ipif_free_enumeration(names, n);
1256                 ni->ni_nid = LNET_MKNID(net, ip);
1257                 return 0;
1258         }
1259
1260         CERROR("Net %s can't find any interfaces\n", libcfs_net2str(net));
1261         libcfs_ipif_free_enumeration(names, n);
1262         return -ENOENT;
1263 }
1264 EXPORT_SYMBOL(lnet_set_ip_niaddr);