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