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