staging: lustre: Ignore hops if not explicitly set
[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 __u32 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 /**
751 * if there are no hops set then we want to flag this value as
752 * unset since hops is an optional parameter
753 */
754 if (!got_hops)
755 hops = LNET_UNDEFINED_HOPS;
756
757 LASSERT(!list_empty(&nets));
758 LASSERT(!list_empty(&gateways));
759
760 list_for_each(tmp1, &nets) {
761 ltb = list_entry(tmp1, struct lnet_text_buf, ltb_list);
762 net = libcfs_str2net(ltb->ltb_text);
763 LASSERT(net != LNET_NIDNET(LNET_NID_ANY));
764
765 list_for_each(tmp2, &gateways) {
766 ltb = list_entry(tmp2, struct lnet_text_buf, ltb_list);
767 nid = libcfs_str2nid(ltb->ltb_text);
768 LASSERT(nid != LNET_NID_ANY);
769
770 if (lnet_islocalnid(nid)) {
771 *im_a_router = 1;
772 continue;
773 }
774
775 rc = lnet_add_route(net, hops, nid, priority);
776 if (rc && rc != -EEXIST && rc != -EHOSTUNREACH) {
777 CERROR("Can't create route to %s via %s\n",
778 libcfs_net2str(net),
779 libcfs_nid2str(nid));
780 goto out;
781 }
782 }
783 }
784
785 myrc = 0;
786 goto out;
787
788 token_error:
789 lnet_syntax("routes", cmd, (int)(token - str), strlen(token));
790 out:
791 lnet_free_text_bufs(&nets);
792 lnet_free_text_bufs(&gateways);
793 return myrc;
794 }
795
796 static int
797 lnet_parse_route_tbs(struct list_head *tbs, int *im_a_router)
798 {
799 struct lnet_text_buf *ltb;
800
801 while (!list_empty(tbs)) {
802 ltb = list_entry(tbs->next, struct lnet_text_buf, ltb_list);
803
804 if (lnet_parse_route(ltb->ltb_text, im_a_router) < 0) {
805 lnet_free_text_bufs(tbs);
806 return -EINVAL;
807 }
808
809 list_del(&ltb->ltb_list);
810 lnet_free_text_buf(ltb);
811 }
812
813 return 0;
814 }
815
816 int
817 lnet_parse_routes(char *routes, int *im_a_router)
818 {
819 struct list_head tbs;
820 int rc = 0;
821
822 *im_a_router = 0;
823
824 INIT_LIST_HEAD(&tbs);
825
826 if (lnet_str2tbs_sep(&tbs, routes) < 0) {
827 CERROR("Error parsing routes\n");
828 rc = -EINVAL;
829 } else {
830 rc = lnet_parse_route_tbs(&tbs, im_a_router);
831 }
832
833 LASSERT(!lnet_tbnob);
834 return rc;
835 }
836
837 static int
838 lnet_match_network_token(char *token, int len, __u32 *ipaddrs, int nip)
839 {
840 LIST_HEAD(list);
841 int rc;
842 int i;
843
844 rc = cfs_ip_addr_parse(token, len, &list);
845 if (rc)
846 return rc;
847
848 for (rc = i = 0; !rc && i < nip; i++)
849 rc = cfs_ip_addr_match(ipaddrs[i], &list);
850
851 cfs_expr_list_free_list(&list);
852
853 return rc;
854 }
855
856 static int
857 lnet_match_network_tokens(char *net_entry, __u32 *ipaddrs, int nip)
858 {
859 static char tokens[LNET_SINGLE_TEXTBUF_NOB];
860
861 int matched = 0;
862 int ntokens = 0;
863 int len;
864 char *net = NULL;
865 char *sep;
866 char *token;
867 int rc;
868
869 LASSERT(strlen(net_entry) < sizeof(tokens));
870
871 /* work on a copy of the string */
872 strcpy(tokens, net_entry);
873 sep = tokens;
874 for (;;) {
875 /* scan for token start */
876 while (isspace(*sep))
877 sep++;
878 if (!*sep)
879 break;
880
881 token = sep++;
882
883 /* scan for token end */
884 while (*sep && !isspace(*sep))
885 sep++;
886 if (*sep)
887 *sep++ = 0;
888
889 if (!ntokens++) {
890 net = token;
891 continue;
892 }
893
894 len = strlen(token);
895
896 rc = lnet_match_network_token(token, len, ipaddrs, nip);
897 if (rc < 0) {
898 lnet_syntax("ip2nets", net_entry,
899 (int)(token - tokens), len);
900 return rc;
901 }
902
903 if (rc)
904 matched |= 1;
905 }
906
907 if (!matched)
908 return 0;
909
910 strcpy(net_entry, net); /* replace with matched net */
911 return 1;
912 }
913
914 static __u32
915 lnet_netspec2net(char *netspec)
916 {
917 char *bracket = strchr(netspec, '(');
918 __u32 net;
919
920 if (bracket)
921 *bracket = 0;
922
923 net = libcfs_str2net(netspec);
924
925 if (bracket)
926 *bracket = '(';
927
928 return net;
929 }
930
931 static int
932 lnet_splitnets(char *source, struct list_head *nets)
933 {
934 int offset = 0;
935 int offset2;
936 int len;
937 struct lnet_text_buf *tb;
938 struct lnet_text_buf *tb2;
939 struct list_head *t;
940 char *sep;
941 char *bracket;
942 __u32 net;
943
944 LASSERT(!list_empty(nets));
945 LASSERT(nets->next == nets->prev); /* single entry */
946
947 tb = list_entry(nets->next, struct lnet_text_buf, ltb_list);
948
949 for (;;) {
950 sep = strchr(tb->ltb_text, ',');
951 bracket = strchr(tb->ltb_text, '(');
952
953 if (sep && bracket && bracket < sep) {
954 /* netspec lists interfaces... */
955
956 offset2 = offset + (int)(bracket - tb->ltb_text);
957 len = strlen(bracket);
958
959 bracket = strchr(bracket + 1, ')');
960
961 if (!bracket ||
962 !(bracket[1] == ',' || !bracket[1])) {
963 lnet_syntax("ip2nets", source, offset2, len);
964 return -EINVAL;
965 }
966
967 sep = !bracket[1] ? NULL : bracket + 1;
968 }
969
970 if (sep)
971 *sep++ = 0;
972
973 net = lnet_netspec2net(tb->ltb_text);
974 if (net == LNET_NIDNET(LNET_NID_ANY)) {
975 lnet_syntax("ip2nets", source, offset,
976 strlen(tb->ltb_text));
977 return -EINVAL;
978 }
979
980 list_for_each(t, nets) {
981 tb2 = list_entry(t, struct lnet_text_buf, ltb_list);
982
983 if (tb2 == tb)
984 continue;
985
986 if (net == lnet_netspec2net(tb2->ltb_text)) {
987 /* duplicate network */
988 lnet_syntax("ip2nets", source, offset,
989 strlen(tb->ltb_text));
990 return -EINVAL;
991 }
992 }
993
994 if (!sep)
995 return 0;
996
997 offset += (int)(sep - tb->ltb_text);
998 len = strlen(sep);
999 tb2 = lnet_new_text_buf(len);
1000 if (!tb2)
1001 return -ENOMEM;
1002
1003 strncpy(tb2->ltb_text, sep, len);
1004 tb2->ltb_text[len] = '\0';
1005 list_add_tail(&tb2->ltb_list, nets);
1006
1007 tb = tb2;
1008 }
1009 }
1010
1011 static int
1012 lnet_match_networks(char **networksp, char *ip2nets, __u32 *ipaddrs, int nip)
1013 {
1014 static char networks[LNET_SINGLE_TEXTBUF_NOB];
1015 static char source[LNET_SINGLE_TEXTBUF_NOB];
1016
1017 struct list_head raw_entries;
1018 struct list_head matched_nets;
1019 struct list_head current_nets;
1020 struct list_head *t;
1021 struct list_head *t2;
1022 struct lnet_text_buf *tb;
1023 struct lnet_text_buf *tb2;
1024 __u32 net1;
1025 __u32 net2;
1026 int len;
1027 int count;
1028 int dup;
1029 int rc;
1030
1031 INIT_LIST_HEAD(&raw_entries);
1032 if (lnet_str2tbs_sep(&raw_entries, ip2nets) < 0) {
1033 CERROR("Error parsing ip2nets\n");
1034 LASSERT(!lnet_tbnob);
1035 return -EINVAL;
1036 }
1037
1038 INIT_LIST_HEAD(&matched_nets);
1039 INIT_LIST_HEAD(&current_nets);
1040 networks[0] = 0;
1041 count = 0;
1042 len = 0;
1043 rc = 0;
1044
1045 while (!list_empty(&raw_entries)) {
1046 tb = list_entry(raw_entries.next, struct lnet_text_buf,
1047 ltb_list);
1048 strncpy(source, tb->ltb_text, sizeof(source));
1049 source[sizeof(source) - 1] = '\0';
1050
1051 /* replace ltb_text with the network(s) add on match */
1052 rc = lnet_match_network_tokens(tb->ltb_text, ipaddrs, nip);
1053 if (rc < 0)
1054 break;
1055
1056 list_del(&tb->ltb_list);
1057
1058 if (!rc) { /* no match */
1059 lnet_free_text_buf(tb);
1060 continue;
1061 }
1062
1063 /* split into separate networks */
1064 INIT_LIST_HEAD(&current_nets);
1065 list_add(&tb->ltb_list, &current_nets);
1066 rc = lnet_splitnets(source, &current_nets);
1067 if (rc < 0)
1068 break;
1069
1070 dup = 0;
1071 list_for_each(t, &current_nets) {
1072 tb = list_entry(t, struct lnet_text_buf, ltb_list);
1073 net1 = lnet_netspec2net(tb->ltb_text);
1074 LASSERT(net1 != LNET_NIDNET(LNET_NID_ANY));
1075
1076 list_for_each(t2, &matched_nets) {
1077 tb2 = list_entry(t2, struct lnet_text_buf,
1078 ltb_list);
1079 net2 = lnet_netspec2net(tb2->ltb_text);
1080 LASSERT(net2 != LNET_NIDNET(LNET_NID_ANY));
1081
1082 if (net1 == net2) {
1083 dup = 1;
1084 break;
1085 }
1086 }
1087
1088 if (dup)
1089 break;
1090 }
1091
1092 if (dup) {
1093 lnet_free_text_bufs(&current_nets);
1094 continue;
1095 }
1096
1097 list_for_each_safe(t, t2, &current_nets) {
1098 tb = list_entry(t, struct lnet_text_buf, ltb_list);
1099
1100 list_del(&tb->ltb_list);
1101 list_add_tail(&tb->ltb_list, &matched_nets);
1102
1103 len += snprintf(networks + len, sizeof(networks) - len,
1104 "%s%s", !len ? "" : ",",
1105 tb->ltb_text);
1106
1107 if (len >= sizeof(networks)) {
1108 CERROR("Too many matched networks\n");
1109 rc = -E2BIG;
1110 goto out;
1111 }
1112 }
1113
1114 count++;
1115 }
1116
1117 out:
1118 lnet_free_text_bufs(&raw_entries);
1119 lnet_free_text_bufs(&matched_nets);
1120 lnet_free_text_bufs(&current_nets);
1121 LASSERT(!lnet_tbnob);
1122
1123 if (rc < 0)
1124 return rc;
1125
1126 *networksp = networks;
1127 return count;
1128 }
1129
1130 static int
1131 lnet_ipaddr_enumerate(__u32 **ipaddrsp)
1132 {
1133 int up;
1134 __u32 netmask;
1135 __u32 *ipaddrs;
1136 __u32 *ipaddrs2;
1137 int nip;
1138 char **ifnames;
1139 int nif = lnet_ipif_enumerate(&ifnames);
1140 int i;
1141 int rc;
1142
1143 if (nif <= 0)
1144 return nif;
1145
1146 LIBCFS_ALLOC(ipaddrs, nif * sizeof(*ipaddrs));
1147 if (!ipaddrs) {
1148 CERROR("Can't allocate ipaddrs[%d]\n", nif);
1149 lnet_ipif_free_enumeration(ifnames, nif);
1150 return -ENOMEM;
1151 }
1152
1153 for (i = nip = 0; i < nif; i++) {
1154 if (!strcmp(ifnames[i], "lo"))
1155 continue;
1156
1157 rc = lnet_ipif_query(ifnames[i], &up, &ipaddrs[nip], &netmask);
1158 if (rc) {
1159 CWARN("Can't query interface %s: %d\n",
1160 ifnames[i], rc);
1161 continue;
1162 }
1163
1164 if (!up) {
1165 CWARN("Ignoring interface %s: it's down\n",
1166 ifnames[i]);
1167 continue;
1168 }
1169
1170 nip++;
1171 }
1172
1173 lnet_ipif_free_enumeration(ifnames, nif);
1174
1175 if (nip == nif) {
1176 *ipaddrsp = ipaddrs;
1177 } else {
1178 if (nip > 0) {
1179 LIBCFS_ALLOC(ipaddrs2, nip * sizeof(*ipaddrs2));
1180 if (!ipaddrs2) {
1181 CERROR("Can't allocate ipaddrs[%d]\n", nip);
1182 nip = -ENOMEM;
1183 } else {
1184 memcpy(ipaddrs2, ipaddrs,
1185 nip * sizeof(*ipaddrs));
1186 *ipaddrsp = ipaddrs2;
1187 rc = nip;
1188 }
1189 }
1190 LIBCFS_FREE(ipaddrs, nip * sizeof(*ipaddrs));
1191 }
1192 return nip;
1193 }
1194
1195 int
1196 lnet_parse_ip2nets(char **networksp, char *ip2nets)
1197 {
1198 __u32 *ipaddrs = NULL;
1199 int nip = lnet_ipaddr_enumerate(&ipaddrs);
1200 int rc;
1201
1202 if (nip < 0) {
1203 LCONSOLE_ERROR_MSG(0x117,
1204 "Error %d enumerating local IP interfaces for ip2nets to match\n",
1205 nip);
1206 return nip;
1207 }
1208
1209 if (!nip) {
1210 LCONSOLE_ERROR_MSG(0x118,
1211 "No local IP interfaces for ip2nets to match\n");
1212 return -ENOENT;
1213 }
1214
1215 rc = lnet_match_networks(networksp, ip2nets, ipaddrs, nip);
1216 LIBCFS_FREE(ipaddrs, nip * sizeof(*ipaddrs));
1217
1218 if (rc < 0) {
1219 LCONSOLE_ERROR_MSG(0x119, "Error %d parsing ip2nets\n", rc);
1220 return rc;
1221 }
1222
1223 if (!rc) {
1224 LCONSOLE_ERROR_MSG(0x11a,
1225 "ip2nets does not match any local IP interfaces\n");
1226 return -ENOENT;
1227 }
1228
1229 return 0;
1230 }
This page took 0.126135 seconds and 5 git commands to generate.