staging: lustre: Ignore hops if not explicitly set
[deliverable/linux.git] / drivers / staging / lustre / lnet / lnet / config.c
CommitLineData
d7e09d03
PT
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 *
1dc563a6 30 * Copyright (c) 2012, 2015, Intel Corporation.
d7e09d03
PT
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
9fdaf8c0 38#include "../../include/linux/lnet/lib-lnet.h"
d7e09d03 39
ddbc66a5 40struct lnet_text_buf { /* tmp struct for parsing routes */
7e7ab095
MS
41 struct list_head ltb_list; /* stash on lists */
42 int ltb_size; /* allocated size */
43 char ltb_text[0]; /* text buffer */
e416a893 44};
d7e09d03 45
ad0a75b4 46static int lnet_tbnob; /* track text buf allocation */
51078e25
JS
47#define LNET_MAX_TEXTBUF_NOB (64 << 10) /* bound allocation */
48#define LNET_SINGLE_TEXTBUF_NOB (4 << 10)
d7e09d03 49
714340db 50static void
d7e09d03
PT
51lnet_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));
51078e25 57 dots[sizeof(dots) - 1] = 0;
d7e09d03 58 memset(dashes, '-', sizeof(dashes));
51078e25 59 dashes[sizeof(dashes) - 1] = 0;
d7e09d03
PT
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
714340db 67static int
24edbe4f 68lnet_issep(char c)
d7e09d03
PT
69{
70 switch (c) {
71 case '\n':
72 case '\r':
73 case ';':
74 return 1;
75 default:
76 return 0;
77 }
78}
79
6c9e5a55 80int
d7e09d03
PT
81lnet_net_unique(__u32 net, struct list_head *nilist)
82{
7e7ab095
MS
83 struct list_head *tmp;
84 lnet_ni_t *ni;
d7e09d03 85
24edbe4f 86 list_for_each(tmp, nilist) {
d7e09d03
PT
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
96void
97lnet_ni_free(struct lnet_ni *ni)
98{
21602c7d
AS
99 int i;
100
06ace26e 101 if (ni->ni_refs)
d7e09d03
PT
102 cfs_percpt_free(ni->ni_refs);
103
06ace26e 104 if (ni->ni_tx_queues)
d7e09d03
PT
105 cfs_percpt_free(ni->ni_tx_queues);
106
06ace26e 107 if (ni->ni_cpts)
d7e09d03
PT
108 cfs_expr_list_values_free(ni->ni_cpts, ni->ni_ncpts);
109
21602c7d
AS
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 }
d7e09d03
PT
114 LIBCFS_FREE(ni, sizeof(*ni));
115}
116
9c26b89d 117lnet_ni_t *
d7e09d03
PT
118lnet_ni_alloc(__u32 net, struct cfs_expr_list *el, struct list_head *nilist)
119{
7e7ab095
MS
120 struct lnet_tx_queue *tq;
121 struct lnet_ni *ni;
122 int rc;
123 int i;
d7e09d03
PT
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));
06ace26e 132 if (!ni) {
d7e09d03
PT
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]));
06ace26e 142 if (!ni->ni_refs)
d7e09d03
PT
143 goto failed;
144
145 ni->ni_tx_queues = cfs_percpt_alloc(lnet_cpt_table(),
146 sizeof(*ni->ni_tx_queues[0]));
06ace26e 147 if (!ni->ni_tx_queues)
d7e09d03
PT
148 goto failed;
149
150 cfs_percpt_for_each(tq, i, ni->ni_tx_queues)
151 INIT_LIST_HEAD(&tq->tq_delayed);
152
06ace26e 153 if (!el) {
d7e09d03
PT
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);
ec0067d1 175 ni->ni_last_alive = ktime_get_real_seconds();
d7e09d03
PT
176 list_add_tail(&ni->ni_list, nilist);
177 return ni;
178 failed:
179 lnet_ni_free(ni);
180 return NULL;
181}
182
183int
184lnet_parse_networks(struct list_head *nilist, char *networks)
185{
186 struct cfs_expr_list *el = NULL;
8766cd12 187 int tokensize;
7e7ab095
MS
188 char *tokens;
189 char *str;
190 char *tmp;
191 struct lnet_ni *ni;
192 __u32 net;
193 int nnets = 0;
9c26b89d 194 struct list_head *temp_node;
d7e09d03 195
8766cd12
AS
196 if (!networks) {
197 CERROR("networks string is undefined\n");
198 return -EINVAL;
199 }
200
d7e09d03
PT
201 if (strlen(networks) > LNET_SINGLE_TEXTBUF_NOB) {
202 /* _WAY_ conservative */
e46b3a0b
RK
203 LCONSOLE_ERROR_MSG(0x112,
204 "Can't parse networks: string too long\n");
d7e09d03
PT
205 return -EINVAL;
206 }
207
8766cd12
AS
208 tokensize = strlen(networks) + 1;
209
d7e09d03 210 LIBCFS_ALLOC(tokens, tokensize);
06ace26e 211 if (!tokens) {
d7e09d03
PT
212 CERROR("Can't allocate net tokens\n");
213 return -ENOMEM;
214 }
215
24edbe4f 216 memcpy(tokens, networks, tokensize);
d3d3d37a
JS
217 tmp = tokens;
218 str = tokens;
d7e09d03 219
5fd88337 220 while (str && *str) {
7e7ab095
MS
221 char *comma = strchr(str, ',');
222 char *bracket = strchr(str, '(');
223 char *square = strchr(str, '[');
224 char *iface;
225 int niface;
226 int rc;
d7e09d03 227
587cb022
SS
228 /*
229 * NB we don't check interface conflicts here; it's the LNDs
230 * responsibility (if it cares at all)
231 */
06ace26e 232 if (square && (!comma || square < comma)) {
587cb022
SS
233 /*
234 * i.e: o2ib0(ib0)[1,2], number between square
235 * brackets are CPTs this NI needs to be bond
236 */
06ace26e 237 if (bracket && bracket > square) {
d7e09d03
PT
238 tmp = square;
239 goto failed_syntax;
240 }
241
242 tmp = strchr(square, ']');
06ace26e 243 if (!tmp) {
d7e09d03
PT
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);
5fd88337 250 if (rc) {
d7e09d03
PT
251 tmp = square;
252 goto failed_syntax;
253 }
254
255 while (square <= tmp)
256 *square++ = ' ';
257 }
258
06ace26e 259 if (!bracket || (comma && comma < bracket)) {
d7e09d03
PT
260 /* no interface list specified */
261
06ace26e 262 if (comma)
d7e09d03
PT
263 *comma++ = 0;
264 net = libcfs_str2net(cfs_trimwhite(str));
265
266 if (net == LNET_NIDNET(LNET_NID_ANY)) {
e46b3a0b
RK
267 LCONSOLE_ERROR_MSG(0x113,
268 "Unrecognised network type\n");
d7e09d03
PT
269 tmp = str;
270 goto failed_syntax;
271 }
272
273 if (LNET_NETTYP(net) != LOLND && /* LO is implicit */
06ace26e 274 !lnet_ni_alloc(net, el, nilist))
d7e09d03
PT
275 goto failed;
276
06ace26e 277 if (el) {
d7e09d03
PT
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
d7e09d03 293 ni = lnet_ni_alloc(net, el, nilist);
06ace26e 294 if (!ni)
d7e09d03
PT
295 goto failed;
296
06ace26e 297 if (el) {
d7e09d03
PT
298 cfs_expr_list_free(el);
299 el = NULL;
300 }
301
302 niface = 0;
303 iface = bracket + 1;
304
305 bracket = strchr(iface, ')');
06ace26e 306 if (!bracket) {
d7e09d03
PT
307 tmp = iface;
308 goto failed_syntax;
309 }
310
311 *bracket = 0;
312 do {
313 comma = strchr(iface, ',');
06ace26e 314 if (comma)
d7e09d03
PT
315 *comma++ = 0;
316
317 iface = cfs_trimwhite(iface);
5fd88337 318 if (!*iface) {
d7e09d03
PT
319 tmp = iface;
320 goto failed_syntax;
321 }
322
323 if (niface == LNET_MAX_INTERFACES) {
e46b3a0b
RK
324 LCONSOLE_ERROR_MSG(0x115,
325 "Too many interfaces for net %s\n",
d7e09d03
PT
326 libcfs_net2str(net));
327 goto failed;
328 }
329
21602c7d
AS
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++;
d7e09d03 347 iface = comma;
06ace26e 348 } while (iface);
d7e09d03
PT
349
350 str = bracket + 1;
351 comma = strchr(bracket + 1, ',');
06ace26e 352 if (comma) {
d7e09d03
PT
353 *comma = 0;
354 str = cfs_trimwhite(str);
5fd88337 355 if (*str) {
d7e09d03
PT
356 tmp = str;
357 goto failed_syntax;
358 }
359 str = comma + 1;
360 continue;
361 }
362
363 str = cfs_trimwhite(str);
5fd88337 364 if (*str) {
d7e09d03
PT
365 tmp = str;
366 goto failed_syntax;
367 }
368 }
369
9c26b89d
AS
370 list_for_each(temp_node, nilist)
371 nnets++;
21602c7d
AS
372
373 LIBCFS_FREE(tokens, tokensize);
9c26b89d 374 return nnets;
d7e09d03
PT
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
06ace26e 386 if (el)
d7e09d03
PT
387 cfs_expr_list_free(el);
388
389 LIBCFS_FREE(tokens, tokensize);
d7e09d03
PT
390
391 return -EINVAL;
392}
393
ddbc66a5 394static struct lnet_text_buf *
24edbe4f 395lnet_new_text_buf(int str_len)
d7e09d03 396{
ddbc66a5 397 struct lnet_text_buf *ltb;
7e7ab095 398 int nob;
d7e09d03
PT
399
400 /* NB allocate space for the terminating 0 */
ddbc66a5 401 nob = offsetof(struct lnet_text_buf, ltb_text[str_len + 1]);
d7e09d03
PT
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);
06ace26e 414 if (!ltb)
d7e09d03
PT
415 return NULL;
416
417 ltb->ltb_size = nob;
418 ltb->ltb_text[0] = 0;
419 lnet_tbnob += nob;
420 return ltb;
421}
422
714340db 423static void
ddbc66a5 424lnet_free_text_buf(struct lnet_text_buf *ltb)
d7e09d03
PT
425{
426 lnet_tbnob -= ltb->ltb_size;
427 LIBCFS_FREE(ltb, ltb->ltb_size);
428}
429
714340db 430static void
d7e09d03
PT
431lnet_free_text_bufs(struct list_head *tbs)
432{
ddbc66a5 433 struct lnet_text_buf *ltb;
d7e09d03
PT
434
435 while (!list_empty(tbs)) {
ddbc66a5 436 ltb = list_entry(tbs->next, struct lnet_text_buf, ltb_list);
d7e09d03
PT
437
438 list_del(&ltb->ltb_list);
439 lnet_free_text_buf(ltb);
440 }
441}
442
714340db 443static int
24edbe4f 444lnet_str2tbs_sep(struct list_head *tbs, char *str)
d7e09d03 445{
7e7ab095
MS
446 struct list_head pending;
447 char *sep;
448 int nob;
449 int i;
ddbc66a5 450 struct lnet_text_buf *ltb;
d7e09d03
PT
451
452 INIT_LIST_HEAD(&pending);
453
454 /* Split 'str' into separate commands */
455 for (;;) {
456 /* skip leading whitespace */
e525a681 457 while (isspace(*str))
d7e09d03
PT
458 str++;
459
460 /* scan for separator or comment */
5fd88337 461 for (sep = str; *sep; sep++)
d7e09d03
PT
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);
06ace26e 468 if (!ltb) {
d7e09d03
PT
469 lnet_free_text_bufs(&pending);
470 return -1;
471 }
472
473 for (i = 0; i < nob; i++)
e525a681 474 if (isspace(str[i]))
d7e09d03
PT
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++;
5fd88337 488 } while (*sep && !lnet_issep(*sep));
d7e09d03
PT
489 }
490
5fd88337 491 if (!*sep)
d7e09d03
PT
492 break;
493
494 str = sep + 1;
495 }
496
497 list_splice(&pending, tbs->prev);
498 return 0;
499}
500
714340db 501static int
24edbe4f 502lnet_expand1tb(struct list_head *list,
d7e09d03
PT
503 char *str, char *sep1, char *sep2,
504 char *item, int itemlen)
505{
7e7ab095
MS
506 int len1 = (int)(sep1 - str);
507 int len2 = strlen(sep2 + 1);
ddbc66a5 508 struct lnet_text_buf *ltb;
d7e09d03 509
24edbe4f
RK
510 LASSERT(*sep1 == '[');
511 LASSERT(*sep2 == ']');
d7e09d03
PT
512
513 ltb = lnet_new_text_buf(len1 + itemlen + len2);
06ace26e 514 if (!ltb)
d7e09d03
PT
515 return -ENOMEM;
516
517 memcpy(ltb->ltb_text, str, len1);
518 memcpy(&ltb->ltb_text[len1], item, itemlen);
51078e25 519 memcpy(&ltb->ltb_text[len1 + itemlen], sep2 + 1, len2);
d7e09d03
PT
520 ltb->ltb_text[len1 + itemlen + len2] = 0;
521
522 list_add_tail(&ltb->ltb_list, list);
523 return 0;
524}
525
714340db 526static int
24edbe4f 527lnet_str2tbs_expand(struct list_head *tbs, char *str)
d7e09d03 528{
7e7ab095
MS
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;
d7e09d03
PT
541
542 INIT_LIST_HEAD(&pending);
543
544 sep = strchr(str, '[');
06ace26e 545 if (!sep) /* nothing to expand */
d7e09d03
PT
546 return 0;
547
548 sep2 = strchr(sep, ']');
06ace26e 549 if (!sep2)
d7e09d03
PT
550 goto failed;
551
552 for (parsed = sep; parsed < sep2; parsed = enditem) {
d7e09d03
PT
553 enditem = ++parsed;
554 while (enditem < sep2 && *enditem != ',')
555 enditem++;
556
557 if (enditem == parsed) /* no empty items */
558 goto failed;
559
3a338e20
RB
560 if (sscanf(parsed, "%d-%d/%d%n", &lo, &hi,
561 &stride, &scanned) < 3) {
d7e09d03 562 if (sscanf(parsed, "%d-%d%n", &lo, &hi, &scanned) < 2) {
d7e09d03 563 /* simple string enumeration */
c314c319
JS
564 if (lnet_expand1tb(&pending, str, sep, sep2,
565 parsed,
5fd88337 566 (int)(enditem - parsed))) {
d7e09d03 567 goto failed;
3a338e20 568 }
d7e09d03
PT
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 ||
5fd88337 581 (hi - lo) % stride)
d7e09d03
PT
582 goto failed;
583
584 for (i = lo; i <= hi; i += stride) {
d7e09d03
PT
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,
5fd88337 591 num, nob))
d7e09d03
PT
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
714340db 604static int
24edbe4f 605lnet_parse_hops(char *str, unsigned int *hops)
d7e09d03 606{
7e7ab095
MS
607 int len = strlen(str);
608 int nob = len;
d7e09d03
PT
609
610 return (sscanf(str, "%u%n", hops, &nob) >= 1 &&
611 nob == len &&
612 *hops > 0 && *hops < 256);
613}
614
e75fb87f
DO
615#define LNET_PRIORITY_SEPARATOR (':')
616
714340db 617static int
e75fb87f
DO
618lnet_parse_priority(char *str, unsigned int *priority, char **token)
619{
7e7ab095 620 int nob;
e75fb87f 621 char *sep;
7e7ab095 622 int len;
e75fb87f
DO
623
624 sep = strchr(str, LNET_PRIORITY_SEPARATOR);
06ace26e 625 if (!sep) {
e75fb87f
DO
626 *priority = 0;
627 return 0;
628 }
629 len = strlen(sep + 1);
630
51078e25 631 if ((sscanf((sep + 1), "%u%n", priority, &nob) < 1) || (len != nob)) {
587cb022
SS
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 */
e75fb87f
DO
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}
d7e09d03 648
714340db 649static int
24edbe4f 650lnet_parse_route(char *str, int *im_a_router)
d7e09d03
PT
651{
652 /* static scratch buffer OK (single threaded) */
7e7ab095
MS
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;
ddbc66a5 661 struct lnet_text_buf *ltb;
7e7ab095
MS
662 int rc;
663 char *sep;
664 char *token = str;
665 int ntokens = 0;
666 int myrc = -1;
b9bbb61c 667 __u32 hops;
7e7ab095
MS
668 int got_hops = 0;
669 unsigned int priority = 0;
d7e09d03
PT
670
671 INIT_LIST_HEAD(&gateways);
672 INIT_LIST_HEAD(&nets);
673
674 /* save a copy of the string for error messages */
9563fe8a
DE
675 strncpy(cmd, str, sizeof(cmd));
676 cmd[sizeof(cmd) - 1] = '\0';
d7e09d03
PT
677
678 sep = str;
679 for (;;) {
680 /* scan for token start */
e525a681 681 while (isspace(*sep))
d7e09d03 682 sep++;
5fd88337 683 if (!*sep) {
d7e09d03
PT
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 */
5fd88337 693 while (*sep && !isspace(*sep))
d7e09d03 694 sep++;
5fd88337 695 if (*sep)
d7e09d03
PT
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));
06ace26e 709 if (!ltb)
d7e09d03
PT
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) {
ddbc66a5 717 ltb = list_entry(tmp1, struct lnet_text_buf, ltb_list);
d7e09d03
PT
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 {
e75fb87f
DO
737 rc = lnet_parse_priority(ltb->ltb_text,
738 &priority, &token);
739 if (rc < 0)
740 goto token_error;
741
d7e09d03
PT
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
b9bbb61c
AS
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 */
d7e09d03 754 if (!got_hops)
b9bbb61c 755 hops = LNET_UNDEFINED_HOPS;
d7e09d03 756
24edbe4f
RK
757 LASSERT(!list_empty(&nets));
758 LASSERT(!list_empty(&gateways));
d7e09d03 759
24edbe4f 760 list_for_each(tmp1, &nets) {
ddbc66a5 761 ltb = list_entry(tmp1, struct lnet_text_buf, ltb_list);
d7e09d03 762 net = libcfs_str2net(ltb->ltb_text);
24edbe4f 763 LASSERT(net != LNET_NIDNET(LNET_NID_ANY));
d7e09d03 764
24edbe4f 765 list_for_each(tmp2, &gateways) {
ddbc66a5 766 ltb = list_entry(tmp2, struct lnet_text_buf, ltb_list);
d7e09d03 767 nid = libcfs_str2nid(ltb->ltb_text);
24edbe4f 768 LASSERT(nid != LNET_NID_ANY);
d7e09d03
PT
769
770 if (lnet_islocalnid(nid)) {
771 *im_a_router = 1;
772 continue;
773 }
774
e75fb87f 775 rc = lnet_add_route(net, hops, nid, priority);
be8240ac 776 if (rc && rc != -EEXIST && rc != -EHOSTUNREACH) {
e46b3a0b 777 CERROR("Can't create route to %s via %s\n",
d7e09d03
PT
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
714340db 796static int
d7e09d03
PT
797lnet_parse_route_tbs(struct list_head *tbs, int *im_a_router)
798{
ddbc66a5 799 struct lnet_text_buf *ltb;
d7e09d03
PT
800
801 while (!list_empty(tbs)) {
ddbc66a5 802 ltb = list_entry(tbs->next, struct lnet_text_buf, ltb_list);
d7e09d03
PT
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
816int
24edbe4f 817lnet_parse_routes(char *routes, int *im_a_router)
d7e09d03 818{
7e7ab095
MS
819 struct list_head tbs;
820 int rc = 0;
d7e09d03
PT
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
5fd88337 833 LASSERT(!lnet_tbnob);
d7e09d03
PT
834 return rc;
835}
836
714340db 837static int
d7e09d03
PT
838lnet_match_network_token(char *token, int len, __u32 *ipaddrs, int nip)
839{
24edbe4f 840 LIST_HEAD(list);
7e7ab095
MS
841 int rc;
842 int i;
d7e09d03
PT
843
844 rc = cfs_ip_addr_parse(token, len, &list);
5fd88337 845 if (rc)
d7e09d03
PT
846 return rc;
847
848 for (rc = i = 0; !rc && i < nip; i++)
849 rc = cfs_ip_addr_match(ipaddrs[i], &list);
850
a620ec63 851 cfs_expr_list_free_list(&list);
d7e09d03
PT
852
853 return rc;
854}
855
714340db 856static int
d7e09d03
PT
857lnet_match_network_tokens(char *net_entry, __u32 *ipaddrs, int nip)
858{
859 static char tokens[LNET_SINGLE_TEXTBUF_NOB];
860
7e7ab095
MS
861 int matched = 0;
862 int ntokens = 0;
863 int len;
d7e09d03
PT
864 char *net = NULL;
865 char *sep;
866 char *token;
7e7ab095 867 int rc;
d7e09d03 868
24edbe4f 869 LASSERT(strlen(net_entry) < sizeof(tokens));
d7e09d03
PT
870
871 /* work on a copy of the string */
872 strcpy(tokens, net_entry);
873 sep = tokens;
874 for (;;) {
875 /* scan for token start */
e525a681 876 while (isspace(*sep))
d7e09d03 877 sep++;
5fd88337 878 if (!*sep)
d7e09d03
PT
879 break;
880
881 token = sep++;
882
883 /* scan for token end */
5fd88337 884 while (*sep && !isspace(*sep))
d7e09d03 885 sep++;
5fd88337 886 if (*sep)
d7e09d03
PT
887 *sep++ = 0;
888
5fd88337 889 if (!ntokens++) {
d7e09d03
PT
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
5fd88337
JS
903 if (rc)
904 matched |= 1;
d7e09d03
PT
905 }
906
907 if (!matched)
908 return 0;
909
910 strcpy(net_entry, net); /* replace with matched net */
911 return 1;
912}
913
714340db 914static __u32
d7e09d03
PT
915lnet_netspec2net(char *netspec)
916{
7e7ab095
MS
917 char *bracket = strchr(netspec, '(');
918 __u32 net;
d7e09d03 919
06ace26e 920 if (bracket)
d7e09d03
PT
921 *bracket = 0;
922
923 net = libcfs_str2net(netspec);
924
06ace26e 925 if (bracket)
d7e09d03
PT
926 *bracket = '(';
927
928 return net;
929}
930
714340db 931static int
d7e09d03
PT
932lnet_splitnets(char *source, struct list_head *nets)
933{
7e7ab095
MS
934 int offset = 0;
935 int offset2;
936 int len;
ddbc66a5
JS
937 struct lnet_text_buf *tb;
938 struct lnet_text_buf *tb2;
7e7ab095
MS
939 struct list_head *t;
940 char *sep;
941 char *bracket;
942 __u32 net;
d7e09d03 943
24edbe4f
RK
944 LASSERT(!list_empty(nets));
945 LASSERT(nets->next == nets->prev); /* single entry */
d7e09d03 946
ddbc66a5 947 tb = list_entry(nets->next, struct lnet_text_buf, ltb_list);
d7e09d03
PT
948
949 for (;;) {
950 sep = strchr(tb->ltb_text, ',');
951 bracket = strchr(tb->ltb_text, '(');
952
06ace26e 953 if (sep && bracket && bracket < sep) {
d7e09d03
PT
954 /* netspec lists interfaces... */
955
956 offset2 = offset + (int)(bracket - tb->ltb_text);
957 len = strlen(bracket);
958
959 bracket = strchr(bracket + 1, ')');
960
06ace26e 961 if (!bracket ||
5fd88337 962 !(bracket[1] == ',' || !bracket[1])) {
d7e09d03
PT
963 lnet_syntax("ip2nets", source, offset2, len);
964 return -EINVAL;
965 }
966
5fd88337 967 sep = !bracket[1] ? NULL : bracket + 1;
d7e09d03
PT
968 }
969
06ace26e 970 if (sep)
d7e09d03
PT
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) {
ddbc66a5 981 tb2 = list_entry(t, struct lnet_text_buf, ltb_list);
d7e09d03
PT
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
06ace26e 994 if (!sep)
d7e09d03
PT
995 return 0;
996
997 offset += (int)(sep - tb->ltb_text);
9563fe8a
DE
998 len = strlen(sep);
999 tb2 = lnet_new_text_buf(len);
06ace26e 1000 if (!tb2)
d7e09d03
PT
1001 return -ENOMEM;
1002
9563fe8a
DE
1003 strncpy(tb2->ltb_text, sep, len);
1004 tb2->ltb_text[len] = '\0';
d7e09d03
PT
1005 list_add_tail(&tb2->ltb_list, nets);
1006
1007 tb = tb2;
1008 }
1009}
1010
714340db 1011static int
24edbe4f 1012lnet_match_networks(char **networksp, char *ip2nets, __u32 *ipaddrs, int nip)
d7e09d03 1013{
7e7ab095
MS
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;
ddbc66a5
JS
1022 struct lnet_text_buf *tb;
1023 struct lnet_text_buf *tb2;
7e7ab095
MS
1024 __u32 net1;
1025 __u32 net2;
1026 int len;
1027 int count;
1028 int dup;
1029 int rc;
d7e09d03
PT
1030
1031 INIT_LIST_HEAD(&raw_entries);
1032 if (lnet_str2tbs_sep(&raw_entries, ip2nets) < 0) {
1033 CERROR("Error parsing ip2nets\n");
5fd88337 1034 LASSERT(!lnet_tbnob);
d7e09d03
PT
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)) {
ddbc66a5
JS
1046 tb = list_entry(raw_entries.next, struct lnet_text_buf,
1047 ltb_list);
9563fe8a 1048 strncpy(source, tb->ltb_text, sizeof(source));
51078e25 1049 source[sizeof(source) - 1] = '\0';
d7e09d03
PT
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
5fd88337 1058 if (!rc) { /* no match */
d7e09d03
PT
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;
24edbe4f 1071 list_for_each(t, &current_nets) {
ddbc66a5 1072 tb = list_entry(t, struct lnet_text_buf, ltb_list);
d7e09d03 1073 net1 = lnet_netspec2net(tb->ltb_text);
24edbe4f 1074 LASSERT(net1 != LNET_NIDNET(LNET_NID_ANY));
d7e09d03
PT
1075
1076 list_for_each(t2, &matched_nets) {
ddbc66a5
JS
1077 tb2 = list_entry(t2, struct lnet_text_buf,
1078 ltb_list);
d7e09d03 1079 net2 = lnet_netspec2net(tb2->ltb_text);
24edbe4f 1080 LASSERT(net2 != LNET_NIDNET(LNET_NID_ANY));
d7e09d03
PT
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) {
ddbc66a5 1098 tb = list_entry(t, struct lnet_text_buf, ltb_list);
d7e09d03
PT
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,
5fd88337 1104 "%s%s", !len ? "" : ",",
d7e09d03
PT
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);
5fd88337 1121 LASSERT(!lnet_tbnob);
d7e09d03
PT
1122
1123 if (rc < 0)
1124 return rc;
1125
1126 *networksp = networks;
1127 return count;
1128}
1129
714340db 1130static int
24edbe4f 1131lnet_ipaddr_enumerate(__u32 **ipaddrsp)
d7e09d03 1132{
7e7ab095
MS
1133 int up;
1134 __u32 netmask;
1135 __u32 *ipaddrs;
1136 __u32 *ipaddrs2;
1137 int nip;
1138 char **ifnames;
1ad6a73e 1139 int nif = lnet_ipif_enumerate(&ifnames);
7e7ab095
MS
1140 int i;
1141 int rc;
d7e09d03
PT
1142
1143 if (nif <= 0)
1144 return nif;
1145
1146 LIBCFS_ALLOC(ipaddrs, nif * sizeof(*ipaddrs));
06ace26e 1147 if (!ipaddrs) {
d7e09d03 1148 CERROR("Can't allocate ipaddrs[%d]\n", nif);
1ad6a73e 1149 lnet_ipif_free_enumeration(ifnames, nif);
d7e09d03
PT
1150 return -ENOMEM;
1151 }
1152
1153 for (i = nip = 0; i < nif; i++) {
1154 if (!strcmp(ifnames[i], "lo"))
1155 continue;
1156
1ad6a73e 1157 rc = lnet_ipif_query(ifnames[i], &up, &ipaddrs[nip], &netmask);
5fd88337 1158 if (rc) {
d7e09d03
PT
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
1ad6a73e 1173 lnet_ipif_free_enumeration(ifnames, nif);
d7e09d03
PT
1174
1175 if (nip == nif) {
1176 *ipaddrsp = ipaddrs;
1177 } else {
1178 if (nip > 0) {
1179 LIBCFS_ALLOC(ipaddrs2, nip * sizeof(*ipaddrs2));
06ace26e 1180 if (!ipaddrs2) {
d7e09d03
PT
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 }
cfa38118 1190 LIBCFS_FREE(ipaddrs, nip * sizeof(*ipaddrs));
d7e09d03
PT
1191 }
1192 return nip;
1193}
1194
1195int
24edbe4f 1196lnet_parse_ip2nets(char **networksp, char *ip2nets)
d7e09d03 1197{
7e7ab095
MS
1198 __u32 *ipaddrs = NULL;
1199 int nip = lnet_ipaddr_enumerate(&ipaddrs);
1200 int rc;
d7e09d03
PT
1201
1202 if (nip < 0) {
e46b3a0b
RK
1203 LCONSOLE_ERROR_MSG(0x117,
1204 "Error %d enumerating local IP interfaces for ip2nets to match\n",
1205 nip);
d7e09d03
PT
1206 return nip;
1207 }
1208
5fd88337 1209 if (!nip) {
e46b3a0b
RK
1210 LCONSOLE_ERROR_MSG(0x118,
1211 "No local IP interfaces for ip2nets to match\n");
d7e09d03
PT
1212 return -ENOENT;
1213 }
1214
1215 rc = lnet_match_networks(networksp, ip2nets, ipaddrs, nip);
cfa38118 1216 LIBCFS_FREE(ipaddrs, nip * sizeof(*ipaddrs));
d7e09d03
PT
1217
1218 if (rc < 0) {
1219 LCONSOLE_ERROR_MSG(0x119, "Error %d parsing ip2nets\n", rc);
1220 return rc;
1221 }
1222
5fd88337 1223 if (!rc) {
e46b3a0b
RK
1224 LCONSOLE_ERROR_MSG(0x11a,
1225 "ip2nets does not match any local IP interfaces\n");
d7e09d03
PT
1226 return -ENOENT;
1227 }
1228
1229 return 0;
1230}
This page took 0.561574 seconds and 5 git commands to generate.