Whamcloud - gitweb
LU-11370 lnet: cleanup ni_cptlist
[fs/lustre-release.git] / 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.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  */
32
33 #define DEBUG_SUBSYSTEM S_LNET
34
35 #include <linux/ctype.h>
36 #include <linux/nsproxy.h>
37 #include <net/net_namespace.h>
38 #include <lnet/lib-lnet.h>
39
40 /* tmp struct for parsing routes */
41 struct lnet_text_buf {
42         struct list_head        ltb_list;       /* stash on lists */
43         int                     ltb_size;       /* allocated size */
44         char                    ltb_text[0];    /* text buffer */
45 };
46
47 static int lnet_tbnob = 0;                      /* track text buf allocation */
48 #define LNET_MAX_TEXTBUF_NOB     (64<<10)       /* bound allocation */
49 #define LNET_SINGLE_TEXTBUF_NOB  (4<<10)
50
51 #define SPACESTR " \t\v\r\n"
52 #define DELIMITERS ":()[]"
53
54 static void
55 lnet_syntax(const char *name, const char *str, int offset, int width)
56 {
57         static char dots[LNET_SINGLE_TEXTBUF_NOB];
58         static char dashes[LNET_SINGLE_TEXTBUF_NOB];
59
60         memset(dots, '.', sizeof(dots));
61         dots[sizeof(dots)-1] = 0;
62         memset(dashes, '-', sizeof(dashes));
63         dashes[sizeof(dashes)-1] = 0;
64
65         LCONSOLE_ERROR_MSG(0x10f, "Error parsing '%s=\"%s\"'\n", name, str);
66         LCONSOLE_ERROR_MSG(0x110, "here...........%.*s..%.*s|%.*s|\n",
67                            (int)strlen(name), dots, offset, dots,
68                             (width < 1) ? 0 : width - 1, dashes);
69 }
70
71 static int
72 lnet_issep (char c)
73 {
74         switch (c) {
75         case '\n':
76         case '\r':
77         case ';':
78                 return 1;
79         default:
80                 return 0;
81         }
82 }
83
84 bool
85 lnet_net_unique(__u32 net_id, struct list_head *netlist,
86                 struct lnet_net **net)
87 {
88         struct lnet_net  *net_l;
89
90         if (!netlist)
91                 return true;
92
93         list_for_each_entry(net_l, netlist, net_list) {
94                 if (net_l->net_id == net_id) {
95                         if (net != NULL)
96                                 *net = net_l;
97                         return false;
98                 }
99         }
100
101         return true;
102 }
103
104 /* check that the NI is unique within the list of NIs already added to
105  * a network */
106 bool
107 lnet_ni_unique_net(struct list_head *nilist, char *iface)
108 {
109         struct list_head *tmp;
110         struct lnet_ni *ni;
111
112         list_for_each(tmp, nilist) {
113                 ni = list_entry(tmp, struct lnet_ni, ni_netlist);
114
115                 if (ni->ni_interfaces[0] != NULL &&
116                     strncmp(ni->ni_interfaces[0], iface, strlen(iface)) == 0)
117                         return false;
118         }
119
120         return true;
121 }
122
123 /* check that the NI is unique to the interfaces with in the same NI.
124  * This is only a consideration if use_tcp_bonding is set */
125 static bool
126 lnet_ni_unique_ni(char *iface_list[LNET_INTERFACES_NUM], char *iface)
127 {
128         int i;
129         for (i = 0; i < LNET_INTERFACES_NUM; i++) {
130                 if (iface_list[i] != NULL &&
131                     strncmp(iface_list[i], iface, strlen(iface)) == 0)
132                         return false;
133         }
134
135         return true;
136 }
137
138 static bool
139 in_array(__u32 *array, __u32 size, __u32 value)
140 {
141         int i;
142
143         for (i = 0; i < size; i++) {
144                 if (array[i] == value)
145                         return false;
146         }
147
148         return true;
149 }
150
151 static int
152 lnet_net_append_cpts(__u32 *cpts, __u32 ncpts, struct lnet_net *net)
153 {
154         __u32 *added_cpts = NULL;
155         int i, j = 0, rc = 0;
156
157         /*
158          * no need to go futher since a subset of the NIs already exist on
159          * all CPTs
160          */
161         if (net->net_ncpts == LNET_CPT_NUMBER)
162                 return 0;
163
164         if (cpts == NULL) {
165                 /* there is an NI which will exist on all CPTs */
166                 if (net->net_cpts != NULL)
167                         LIBCFS_FREE(net->net_cpts, sizeof(*net->net_cpts) *
168                                     net->net_ncpts);
169                 net->net_cpts = NULL;
170                 net->net_ncpts = LNET_CPT_NUMBER;
171                 return 0;
172         }
173
174         if (net->net_cpts == NULL) {
175                 LIBCFS_ALLOC(net->net_cpts, sizeof(*net->net_cpts) * ncpts);
176                 if (net->net_cpts == NULL)
177                         return -ENOMEM;
178                 memcpy(net->net_cpts, cpts, ncpts * sizeof(*net->net_cpts));
179                 net->net_ncpts = ncpts;
180                 return 0;
181         }
182
183         LIBCFS_ALLOC(added_cpts, sizeof(*added_cpts) * LNET_CPT_NUMBER);
184         if (added_cpts == NULL)
185                 return -ENOMEM;
186
187         for (i = 0; i < ncpts; i++) {
188                 if (!in_array(net->net_cpts, net->net_ncpts, cpts[i])) {
189                         added_cpts[j] = cpts[i];
190                         j++;
191                 }
192         }
193
194         /* append the new cpts if any to the list of cpts in the net */
195         if (j > 0) {
196                 __u32 *array = NULL, *loc;
197                 __u32 total_entries = j + net->net_ncpts;
198
199                 LIBCFS_ALLOC(array, sizeof(*net->net_cpts) * total_entries);
200                 if (array == NULL) {
201                         rc = -ENOMEM;
202                         goto failed;
203                 }
204
205                 memcpy(array, net->net_cpts, net->net_ncpts);
206                 loc = array + net->net_ncpts;
207                 memcpy(loc, added_cpts, j);
208
209                 LIBCFS_FREE(net->net_cpts, sizeof(*net->net_cpts) *
210                             net->net_ncpts);
211                 net->net_ncpts = total_entries;
212                 net->net_cpts = array;
213         }
214
215 failed:
216         LIBCFS_FREE(added_cpts, sizeof(*added_cpts) * LNET_CPT_NUMBER);
217
218         return rc;
219 }
220
221 static void
222 lnet_net_remove_cpts(__u32 *cpts, __u32 ncpts, struct lnet_net *net)
223 {
224         struct lnet_ni *ni;
225         int rc;
226
227         /*
228          * Operation Assumption:
229          *      This function is called after an NI has been removed from
230          *      its parent net.
231          *
232          * if we're removing an NI which exists on all CPTs then
233          * we have to check if any of the other NIs on this net also
234          * exists on all CPTs. If none, then we need to build our Net CPT
235          * list based on the remaining NIs.
236          *
237          * If the NI being removed exist on a subset of the CPTs then we
238          * alo rebuild the Net CPT list based on the remaining NIs, which
239          * should resutl in the expected Net CPT list.
240          */
241
242         /*
243          * sometimes this function can be called due to some failure
244          * creating an NI, before any of the cpts are allocated, so check
245          * for that case and don't do anything
246          */
247         if (ncpts == 0)
248                 return;
249
250         if (ncpts == LNET_CPT_NUMBER) {
251                 /*
252                  * first iteration through the NI list in the net to see
253                  * if any of the NIs exist on all the CPTs. If one is
254                  * found then our job is done.
255                  */
256                 list_for_each_entry(ni, &net->net_ni_list, ni_netlist) {
257                         if (ni->ni_ncpts == LNET_CPT_NUMBER)
258                                 return;
259                 }
260         }
261
262         /*
263          * Rebuild the Net CPT list again, thereby only including only the
264          * CPTs which the remaining NIs are associated with.
265          */
266         if (net->net_cpts != NULL) {
267                 LIBCFS_FREE(net->net_cpts,
268                         sizeof(*net->net_cpts) * net->net_ncpts);
269                 net->net_cpts = NULL;
270         }
271
272         list_for_each_entry(ni, &net->net_ni_list, ni_netlist) {
273                 rc = lnet_net_append_cpts(ni->ni_cpts, ni->ni_ncpts,
274                                           net);
275                 if (rc != 0) {
276                         CERROR("Out of Memory\n");
277                         /*
278                          * do our best to keep on going. Delete
279                          * the net cpts and set it to NULL. This
280                          * way we can keep on going but less
281                          * efficiently, since memory accesses might be
282                          * accross CPT lines.
283                          */
284                         if (net->net_cpts != NULL) {
285                                 LIBCFS_FREE(net->net_cpts,
286                                                 sizeof(*net->net_cpts) *
287                                                 net->net_ncpts);
288                                 net->net_cpts = NULL;
289                                 net->net_ncpts = LNET_CPT_NUMBER;
290                         }
291                         return;
292                 }
293         }
294 }
295
296 void
297 lnet_ni_free(struct lnet_ni *ni)
298 {
299         int i;
300
301         lnet_net_remove_cpts(ni->ni_cpts, ni->ni_ncpts, ni->ni_net);
302
303         if (ni->ni_refs != NULL)
304                 cfs_percpt_free(ni->ni_refs);
305
306         if (ni->ni_tx_queues != NULL)
307                 cfs_percpt_free(ni->ni_tx_queues);
308
309         if (ni->ni_cpts != NULL)
310                 cfs_expr_list_values_free(ni->ni_cpts, ni->ni_ncpts);
311
312         for (i = 0; i < LNET_INTERFACES_NUM &&
313                     ni->ni_interfaces[i] != NULL; i++) {
314                 LIBCFS_FREE(ni->ni_interfaces[i],
315                             strlen(ni->ni_interfaces[i]) + 1);
316         }
317
318         /* release reference to net namespace */
319         if (ni->ni_net_ns != NULL)
320                 put_net(ni->ni_net_ns);
321
322         LIBCFS_FREE(ni, sizeof(*ni));
323 }
324
325 void
326 lnet_net_free(struct lnet_net *net)
327 {
328         struct list_head *tmp, *tmp2;
329         struct lnet_ni *ni;
330
331         LASSERT(list_empty(&net->net_ni_zombie));
332
333         /*
334          * delete any nis that haven't been added yet. This could happen
335          * if there is a failure on net startup
336          */
337         list_for_each_safe(tmp, tmp2, &net->net_ni_added) {
338                 ni = list_entry(tmp, struct lnet_ni, ni_netlist);
339                 list_del_init(&ni->ni_netlist);
340                 lnet_ni_free(ni);
341         }
342
343         /* delete any nis which have been started. */
344         list_for_each_safe(tmp, tmp2, &net->net_ni_list) {
345                 ni = list_entry(tmp, struct lnet_ni, ni_netlist);
346                 list_del_init(&ni->ni_netlist);
347                 lnet_ni_free(ni);
348         }
349
350         if (net->net_cpts != NULL)
351                 LIBCFS_FREE(net->net_cpts,
352                             sizeof(*net->net_cpts) * net->net_ncpts);
353
354         LIBCFS_FREE(net, sizeof(*net));
355 }
356
357 struct lnet_net *
358 lnet_net_alloc(__u32 net_id, struct list_head *net_list)
359 {
360         struct lnet_net         *net;
361
362         if (!lnet_net_unique(net_id, net_list, NULL)) {
363                 CERROR("Duplicate net %s. Ignore\n",
364                        libcfs_net2str(net_id));
365                 return NULL;
366         }
367
368         LIBCFS_ALLOC(net, sizeof(*net));
369         if (net == NULL) {
370                 CERROR("Out of memory creating network %s\n",
371                        libcfs_net2str(net_id));
372                 return NULL;
373         }
374
375         INIT_LIST_HEAD(&net->net_list);
376         INIT_LIST_HEAD(&net->net_ni_list);
377         INIT_LIST_HEAD(&net->net_ni_added);
378         INIT_LIST_HEAD(&net->net_ni_zombie);
379
380         net->net_id = net_id;
381         net->net_state = LNET_NET_STATE_INIT;
382
383         /* initialize global paramters to undefiend */
384         net->net_tunables.lct_peer_timeout = -1;
385         net->net_tunables.lct_max_tx_credits = -1;
386         net->net_tunables.lct_peer_tx_credits = -1;
387         net->net_tunables.lct_peer_rtr_credits = -1;
388
389         if (net_list)
390                 list_add_tail(&net->net_list, net_list);
391
392         return net;
393 }
394
395 static int
396 lnet_ni_add_interface(struct lnet_ni *ni, char *iface)
397 {
398         int niface = 0;
399
400         if (ni == NULL)
401                 return -ENOMEM;
402
403         if (!lnet_ni_unique_ni(ni->ni_interfaces, iface))
404                 return -EINVAL;
405
406         /* Allocate a separate piece of memory and copy
407          * into it the string, so we don't have
408          * a depencency on the tokens string.  This way we
409          * can free the tokens at the end of the function.
410          * The newly allocated ni_interfaces[] can be
411          * freed when freeing the NI */
412         while (niface < LNET_INTERFACES_NUM &&
413                ni->ni_interfaces[niface] != NULL)
414                 niface++;
415
416         if (niface >= LNET_INTERFACES_NUM) {
417                 LCONSOLE_ERROR_MSG(0x115, "Too many interfaces "
418                                    "for net %s\n",
419                                    libcfs_net2str(LNET_NIDNET(ni->ni_nid)));
420                 return -EINVAL;
421         }
422
423         LIBCFS_ALLOC(ni->ni_interfaces[niface],
424                      strlen(iface) + 1);
425
426         if (ni->ni_interfaces[niface] == NULL) {
427                 CERROR("Can't allocate net interface name\n");
428                 return -ENOMEM;
429         }
430
431         strncpy(ni->ni_interfaces[niface], iface,
432                 strlen(iface) + 1);
433
434         return 0;
435 }
436
437 static struct lnet_ni *
438 lnet_ni_alloc_common(struct lnet_net *net, char *iface)
439 {
440         struct lnet_tx_queue    *tq;
441         struct lnet_ni          *ni;
442         int                     i;
443
444         if (iface != NULL)
445                 /* make sure that this NI is unique in the net it's
446                  * being added to */
447                 if (!lnet_ni_unique_net(&net->net_ni_added, iface))
448                         return NULL;
449
450         LIBCFS_ALLOC(ni, sizeof(*ni));
451         if (ni == NULL) {
452                 CERROR("Out of memory creating network interface %s%s\n",
453                        libcfs_net2str(net->net_id),
454                        (iface != NULL) ? iface : "");
455                 return NULL;
456         }
457
458         spin_lock_init(&ni->ni_lock);
459         INIT_LIST_HEAD(&ni->ni_netlist);
460         INIT_LIST_HEAD(&ni->ni_recovery);
461         ni->ni_refs = cfs_percpt_alloc(lnet_cpt_table(),
462                                        sizeof(*ni->ni_refs[0]));
463         if (ni->ni_refs == NULL)
464                 goto failed;
465
466         ni->ni_tx_queues = cfs_percpt_alloc(lnet_cpt_table(),
467                                             sizeof(*ni->ni_tx_queues[0]));
468         if (ni->ni_tx_queues == NULL)
469                 goto failed;
470
471         cfs_percpt_for_each(tq, i, ni->ni_tx_queues)
472                 INIT_LIST_HEAD(&tq->tq_delayed);
473
474         ni->ni_net = net;
475         /* LND will fill in the address part of the NID */
476         ni->ni_nid = LNET_MKNID(net->net_id, 0);
477
478         /* Store net namespace in which current ni is being created */
479         if (current->nsproxy->net_ns != NULL)
480                 ni->ni_net_ns = get_net(current->nsproxy->net_ns);
481         else
482                 ni->ni_net_ns = NULL;
483
484         ni->ni_last_alive = ktime_get_real_seconds();
485         ni->ni_state |= LNET_NI_STATE_INIT;
486         list_add_tail(&ni->ni_netlist, &net->net_ni_added);
487
488         /*
489          * if an interface name is provided then make sure to add in that
490          * interface name in NI
491          */
492         if (iface)
493                 if (lnet_ni_add_interface(ni, iface) != 0)
494                         goto failed;
495
496         return ni;
497 failed:
498         lnet_ni_free(ni);
499         return NULL;
500 }
501
502 /* allocate and add to the provided network */
503 struct lnet_ni *
504 lnet_ni_alloc(struct lnet_net *net, struct cfs_expr_list *el, char *iface)
505 {
506         struct lnet_ni          *ni;
507         int                     rc;
508
509         ni = lnet_ni_alloc_common(net, iface);
510         if (!ni)
511                 return NULL;
512
513         if (!el) {
514                 ni->ni_cpts  = NULL;
515                 ni->ni_ncpts = LNET_CPT_NUMBER;
516         } else {
517                 rc = cfs_expr_list_values(el, LNET_CPT_NUMBER, &ni->ni_cpts);
518                 if (rc <= 0) {
519                         CERROR("Failed to set CPTs for NI %s(%s): %d\n",
520                                libcfs_net2str(net->net_id),
521                                (iface != NULL) ? iface : "", rc);
522                         goto failed;
523                 }
524
525                 LASSERT(rc <= LNET_CPT_NUMBER);
526                 if (rc == LNET_CPT_NUMBER) {
527                         LIBCFS_FREE(ni->ni_cpts, rc * sizeof(ni->ni_cpts[0]));
528                         ni->ni_cpts = NULL;
529                 }
530
531                 ni->ni_ncpts = rc;
532         }
533
534         rc = lnet_net_append_cpts(ni->ni_cpts, ni->ni_ncpts, net);
535         if (rc != 0)
536                 goto failed;
537
538         return ni;
539 failed:
540         lnet_ni_free(ni);
541         return NULL;
542 }
543
544 struct lnet_ni *
545 lnet_ni_alloc_w_cpt_array(struct lnet_net *net, __u32 *cpts, __u32 ncpts,
546                           char *iface)
547 {
548         struct lnet_ni          *ni;
549         int                     rc;
550
551         ni = lnet_ni_alloc_common(net, iface);
552         if (!ni)
553                 return NULL;
554
555         if (ncpts == 0) {
556                 ni->ni_cpts  = NULL;
557                 ni->ni_ncpts = LNET_CPT_NUMBER;
558         } else {
559                 size_t array_size = ncpts * sizeof(ni->ni_cpts[0]);
560                 LIBCFS_ALLOC(ni->ni_cpts, array_size);
561                 if (ni->ni_cpts == NULL)
562                         goto failed;
563                 memcpy(ni->ni_cpts, cpts, array_size);
564                 ni->ni_ncpts = ncpts;
565         }
566
567         rc = lnet_net_append_cpts(ni->ni_cpts, ni->ni_ncpts, net);
568         if (rc != 0)
569                 goto failed;
570
571         return ni;
572 failed:
573         lnet_ni_free(ni);
574         return NULL;
575 }
576
577 /*
578  * Parse the networks string and create the matching set of NIs on the
579  * nilist.
580  */
581 int
582 lnet_parse_networks(struct list_head *netlist, char *networks,
583                     bool use_tcp_bonding)
584 {
585         struct cfs_expr_list *net_el = NULL;
586         struct cfs_expr_list *ni_el = NULL;
587         int             tokensize;
588         char            *tokens;
589         char            *str;
590         struct lnet_net *net;
591         struct lnet_ni  *ni = NULL;
592         __u32           net_id;
593         int             nnets = 0;
594
595         if (networks == NULL) {
596                 CERROR("networks string is undefined\n");
597                 return -EINVAL;
598         }
599
600         if (strlen(networks) > LNET_SINGLE_TEXTBUF_NOB) {
601                 /* _WAY_ conservative */
602                 LCONSOLE_ERROR_MSG(0x112, "Can't parse networks: string too "
603                                    "long\n");
604                 return -EINVAL;
605         }
606
607         tokensize = strlen(networks) + 1;
608
609         LIBCFS_ALLOC(tokens, tokensize);
610         if (tokens == NULL) {
611                 CERROR("Can't allocate net tokens\n");
612                 return -ENOMEM;
613         }
614
615         memcpy(tokens, networks, tokensize);
616         str = tokens;
617
618         /*
619          * Main parser loop.
620          *
621          * NB we don't check interface conflicts here; it's the LNDs
622          * responsibility (if it cares at all)
623          */
624         do {
625                 char *nistr;
626                 char *elstr;
627                 char *name;
628                 int rc;
629
630                 /*
631                  * Parse a network string into its components.
632                  *
633                  * <name>{"("...")"}{"["<el>"]"}
634                  */
635
636                 /* Network name (mandatory) */
637                 while (isspace(*str))
638                         *str++ = '\0';
639                 if (!*str)
640                         break;
641                 name = str;
642                 str += strcspn(str, SPACESTR ":()[],");
643                 while (isspace(*str))
644                         *str++ = '\0';
645
646                 /* Interface list (optional) */
647                 if (*str == '(') {
648                         *str++ = '\0';
649                         nistr = str;
650                         str += strcspn(str, ")");
651                         if (*str != ')') {
652                                 str = nistr;
653                                 goto failed_syntax;
654                         }
655                         do {
656                                 *str++ = '\0';
657                         } while (isspace(*str));
658                 } else {
659                         nistr = NULL;
660                 }
661
662                 /* CPT expression (optional) */
663                 if (*str == '[') {
664                         elstr = str;
665                         str += strcspn(str, "]");
666                         if (*str != ']') {
667                                 str = elstr;
668                                 goto failed_syntax;
669                         }
670                         rc = cfs_expr_list_parse(elstr, str - elstr + 1,
671                                                 0, LNET_CPT_NUMBER - 1,
672                                                 &net_el);
673                         if (rc != 0) {
674                                 str = elstr;
675                                 goto failed_syntax;
676                         }
677                         *elstr = '\0';
678                         do {
679                                 *str++ = '\0';
680                         } while (isspace(*str));
681                 }
682
683                 /* Bad delimiters */
684                 if (*str && (strchr(DELIMITERS, *str) != NULL))
685                         goto failed_syntax;
686
687                 /* go to the next net if it exits */
688                 str += strcspn(str, ",");
689                 if (*str == ',')
690                         *str++ = '\0';
691
692                 /*
693                  * At this point the name is properly terminated.
694                  */
695                 net_id = libcfs_str2net(name);
696                 if (net_id == LNET_NIDNET(LNET_NID_ANY)) {
697                         LCONSOLE_ERROR_MSG(0x113,
698                                         "Unrecognised network type\n");
699                         str = name;
700                         goto failed_syntax;
701                 }
702
703                 if (LNET_NETTYP(net_id) == LOLND) {
704                         /* Loopback is implicit, and there can be only one. */
705                         if (net_el) {
706                                 cfs_expr_list_free(net_el);
707                                 net_el = NULL;
708                         }
709                         /* Should we error out instead? */
710                         continue;
711                 }
712
713                 /*
714                  * All network paramaters are now known.
715                  */
716                 nnets++;
717
718                 /* always allocate a net, since we will eventually add an
719                  * interface to it, or we will fail, in which case we'll
720                  * just delete it */
721                 net = lnet_net_alloc(net_id, netlist);
722                 if (IS_ERR_OR_NULL(net))
723                         goto failed;
724
725                 if (!nistr ||
726                     (use_tcp_bonding && LNET_NETTYP(net_id) == SOCKLND)) {
727                         /*
728                          * No interface list was specified, allocate a
729                          * ni using the defaults.
730                          */
731                         ni = lnet_ni_alloc(net, net_el, NULL);
732                         if (IS_ERR_OR_NULL(ni))
733                                 goto failed;
734
735                         if (!nistr) {
736                                 if (net_el) {
737                                         cfs_expr_list_free(net_el);
738                                         net_el = NULL;
739                                 }
740                                 continue;
741                         }
742                 }
743
744                 do {
745                         elstr = NULL;
746
747                         /* Interface name (mandatory) */
748                         while (isspace(*nistr))
749                                 *nistr++ = '\0';
750                         name = nistr;
751                         nistr += strcspn(nistr, SPACESTR "[],");
752                         while (isspace(*nistr))
753                                 *nistr++ = '\0';
754
755                         /* CPT expression (optional) */
756                         if (*nistr == '[') {
757                                 elstr = nistr;
758                                 nistr += strcspn(nistr, "]");
759                                 if (*nistr != ']') {
760                                         str = elstr;
761                                         goto failed_syntax;
762                                 }
763                                 rc = cfs_expr_list_parse(elstr,
764                                                         nistr - elstr + 1,
765                                                         0, LNET_CPT_NUMBER - 1,
766                                                         &ni_el);
767                                 if (rc != 0) {
768                                         str = elstr;
769                                         goto failed_syntax;
770                                 }
771                                 *elstr = '\0';
772                                 do {
773                                         *nistr++ = '\0';
774                                 } while (isspace(*nistr));
775                         } else {
776                                 ni_el = net_el;
777                         }
778
779                         /*
780                          * End of single interface specificaton,
781                          * advance to the start of the next one, if
782                          * any.
783                          */
784                         if (*nistr == ',') {
785                                 do {
786                                         *nistr++ = '\0';
787                                 } while (isspace(*nistr));
788                                 if (!*nistr) {
789                                         str = nistr;
790                                         goto failed_syntax;
791                                 }
792                         } else if (*nistr) {
793                                 str = nistr;
794                                 goto failed_syntax;
795                         }
796
797                         /*
798                          * At this point the name is properly terminated.
799                          */
800                         if (!*name) {
801                                 str = name;
802                                 goto failed_syntax;
803                         }
804
805                         if (use_tcp_bonding &&
806                             LNET_NETTYP(net->net_id) == SOCKLND) {
807                                 rc = lnet_ni_add_interface(ni, name);
808                                 if (rc != 0)
809                                         goto failed;
810                         } else {
811                                 ni = lnet_ni_alloc(net, ni_el, name);
812                                 if (IS_ERR_OR_NULL(ni))
813                                         goto failed;
814                         }
815
816                         if (ni_el) {
817                                 if (ni_el != net_el) {
818                                         cfs_expr_list_free(ni_el);
819                                         ni_el = NULL;
820                                 }
821                         }
822                 } while (*nistr);
823
824                 if (net_el) {
825                         cfs_expr_list_free(net_el);
826                         net_el = NULL;
827                 }
828         } while (*str);
829
830         LIBCFS_FREE(tokens, tokensize);
831         return nnets;
832
833  failed_syntax:
834         lnet_syntax("networks", networks, (int)(str - tokens), strlen(str));
835  failed:
836         /* free the net list and all the nis on each net */
837         while (!list_empty(netlist)) {
838                 net = list_entry(netlist->next, struct lnet_net, net_list);
839
840                 list_del_init(&net->net_list);
841                 lnet_net_free(net);
842         }
843
844         if (ni_el && ni_el != net_el)
845                 cfs_expr_list_free(ni_el);
846         if (net_el)
847                 cfs_expr_list_free(net_el);
848
849         LIBCFS_FREE(tokens, tokensize);
850
851         return -EINVAL;
852 }
853
854 static struct lnet_text_buf *lnet_new_text_buf(int str_len)
855 {
856         struct lnet_text_buf *ltb;
857         int nob;
858
859         /* NB allocate space for the terminating 0 */
860         nob = offsetof(struct lnet_text_buf, ltb_text[str_len + 1]);
861         if (nob > LNET_SINGLE_TEXTBUF_NOB) {
862                 /* _way_ conservative for "route net gateway..." */
863                 CERROR("text buffer too big\n");
864                 return NULL;
865         }
866
867         if (lnet_tbnob + nob > LNET_MAX_TEXTBUF_NOB) {
868                 CERROR("Too many text buffers\n");
869                 return NULL;
870         }
871
872         LIBCFS_ALLOC(ltb, nob);
873         if (ltb == NULL)
874                 return NULL;
875
876         ltb->ltb_size = nob;
877         ltb->ltb_text[0] = 0;
878         lnet_tbnob += nob;
879         return ltb;
880 }
881
882 static void
883 lnet_free_text_buf(struct lnet_text_buf *ltb)
884 {
885         lnet_tbnob -= ltb->ltb_size;
886         LIBCFS_FREE(ltb, ltb->ltb_size);
887 }
888
889 static void
890 lnet_free_text_bufs(struct list_head *tbs)
891 {
892         struct lnet_text_buf  *ltb;
893
894         while (!list_empty(tbs)) {
895                 ltb = list_entry(tbs->next, struct lnet_text_buf, ltb_list);
896
897                 list_del(&ltb->ltb_list);
898                 lnet_free_text_buf(ltb);
899         }
900 }
901
902 void
903 lnet_print_text_bufs(struct list_head *tbs)
904 {
905         struct list_head *tmp;
906         struct lnet_text_buf  *ltb;
907
908         list_for_each(tmp, tbs) {
909                 ltb = list_entry(tmp, struct lnet_text_buf, ltb_list);
910
911                 CDEBUG(D_WARNING, "%s\n", ltb->ltb_text);
912         }
913
914         CDEBUG(D_WARNING, "%d allocated\n", lnet_tbnob);
915 }
916
917 static int
918 lnet_str2tbs_sep(struct list_head *tbs, char *str)
919 {
920         struct list_head  pending;
921         char             *sep;
922         int               nob;
923         int               i;
924         struct lnet_text_buf  *ltb;
925
926         INIT_LIST_HEAD(&pending);
927
928         /* Split 'str' into separate commands */
929         for (;;) {
930                 /* skip leading whitespace */
931                 while (isspace(*str))
932                         str++;
933
934                 /* scan for separator or comment */
935                 for (sep = str; *sep != 0; sep++)
936                         if (lnet_issep(*sep) || *sep == '#')
937                                 break;
938
939                 nob = (int)(sep - str);
940                 if (nob > 0) {
941                         ltb = lnet_new_text_buf(nob);
942                         if (ltb == NULL) {
943                                 lnet_free_text_bufs(&pending);
944                                 return -ENOMEM;
945                         }
946
947                         for (i = 0; i < nob; i++)
948                                 if (isspace(str[i]))
949                                         ltb->ltb_text[i] = ' ';
950                                 else
951                                         ltb->ltb_text[i] = str[i];
952
953                         ltb->ltb_text[nob] = 0;
954
955                         list_add_tail(&ltb->ltb_list, &pending);
956                 }
957
958                 if (*sep == '#') {
959                         /* scan for separator */
960                         do {
961                                 sep++;
962                         } while (*sep != 0 && !lnet_issep(*sep));
963                 }
964
965                 if (*sep == 0)
966                         break;
967
968                 str = sep + 1;
969         }
970
971         list_splice(&pending, tbs->prev);
972         return 0;
973 }
974
975 static int
976 lnet_expand1tb(struct list_head *list,
977                char *str, char *sep1, char *sep2,
978                char *item, int itemlen)
979 {
980         int              len1 = (int)(sep1 - str);
981         int              len2 = strlen(sep2 + 1);
982         struct lnet_text_buf *ltb;
983
984         LASSERT (*sep1 == '[');
985         LASSERT (*sep2 == ']');
986
987         ltb = lnet_new_text_buf(len1 + itemlen + len2);
988         if (ltb == NULL)
989                 return -ENOMEM;
990
991         memcpy(ltb->ltb_text, str, len1);
992         memcpy(&ltb->ltb_text[len1], item, itemlen);
993         memcpy(&ltb->ltb_text[len1+itemlen], sep2 + 1, len2);
994         ltb->ltb_text[len1 + itemlen + len2] = 0;
995
996         list_add_tail(&ltb->ltb_list, list);
997         return 0;
998 }
999
1000 static int
1001 lnet_str2tbs_expand(struct list_head *tbs, char *str)
1002 {
1003         char              num[16];
1004         struct list_head  pending;
1005         char             *sep;
1006         char             *sep2;
1007         char             *parsed;
1008         char             *enditem;
1009         int               lo;
1010         int               hi;
1011         int               stride;
1012         int               i;
1013         int               nob;
1014         int               scanned;
1015
1016         INIT_LIST_HEAD(&pending);
1017
1018         sep = strchr(str, '[');
1019         if (sep == NULL)                        /* nothing to expand */
1020                 return 0;
1021
1022         sep2 = strchr(sep, ']');
1023         if (sep2 == NULL)
1024                 goto failed;
1025
1026         for (parsed = sep; parsed < sep2; parsed = enditem) {
1027
1028                 enditem = ++parsed;
1029                 while (enditem < sep2 && *enditem != ',')
1030                         enditem++;
1031
1032                 if (enditem == parsed)          /* no empty items */
1033                         goto failed;
1034
1035                 if (sscanf(parsed, "%d-%d/%d%n", &lo, &hi, &stride, &scanned) < 3) {
1036
1037                         if (sscanf(parsed, "%d-%d%n", &lo, &hi, &scanned) < 2) {
1038
1039                                 /* simple string enumeration */
1040                                 if (lnet_expand1tb(&pending, str, sep, sep2,
1041                                                    parsed, (int)(enditem - parsed)) != 0)
1042                                         goto failed;
1043
1044                                 continue;
1045                         }
1046
1047                         stride = 1;
1048                 }
1049
1050                 /* range expansion */
1051
1052                 if (enditem != parsed + scanned) /* no trailing junk */
1053                         goto failed;
1054
1055                 if (hi < 0 || lo < 0 || stride < 0 || hi < lo ||
1056                     (hi - lo) % stride != 0)
1057                         goto failed;
1058
1059                 for (i = lo; i <= hi; i += stride) {
1060
1061                         snprintf(num, sizeof(num), "%d", i);
1062                         nob = strlen(num);
1063                         if (nob + 1 == sizeof(num))
1064                                 goto failed;
1065
1066                         if (lnet_expand1tb(&pending, str, sep, sep2,
1067                                            num, nob) != 0)
1068                                 goto failed;
1069                 }
1070         }
1071
1072         list_splice(&pending, tbs->prev);
1073         return 1;
1074
1075  failed:
1076         lnet_free_text_bufs(&pending);
1077         return -EINVAL;
1078 }
1079
1080 static int
1081 lnet_parse_hops (char *str, unsigned int *hops)
1082 {
1083         int     len = strlen(str);
1084         int     nob = len;
1085
1086         return (sscanf(str, "%u%n", hops, &nob) >= 1 &&
1087                 nob == len &&
1088                 *hops > 0 && *hops < 256);
1089 }
1090
1091 #define LNET_PRIORITY_SEPARATOR (':')
1092
1093 static int
1094 lnet_parse_priority(char *str, unsigned int *priority, char **token)
1095 {
1096         int   nob;
1097         char *sep;
1098         int   len;
1099
1100         sep = strchr(str, LNET_PRIORITY_SEPARATOR);
1101         if (sep == NULL) {
1102                 *priority = 0;
1103                 return 0;
1104         }
1105         len = strlen(sep + 1);
1106
1107         if ((sscanf((sep+1), "%u%n", priority, &nob) < 1) || (len != nob)) {
1108                 /* Update the caller's token pointer so it treats the found
1109                    priority as the token to report in the error message. */
1110                 *token += sep - str + 1;
1111                 return -EINVAL;
1112         }
1113
1114         CDEBUG(D_NET, "gateway %s, priority %d, nob %d\n", str, *priority, nob);
1115
1116         /*
1117          * Change priority separator to \0 to be able to parse NID
1118          */
1119         *sep = '\0';
1120         return 0;
1121 }
1122
1123 static int
1124 lnet_parse_route (char *str, int *im_a_router)
1125 {
1126         /* static scratch buffer OK (single threaded) */
1127         static char       cmd[LNET_SINGLE_TEXTBUF_NOB];
1128
1129         struct list_head  nets;
1130         struct list_head  gateways;
1131         struct list_head *tmp1;
1132         struct list_head *tmp2;
1133         __u32             net;
1134         lnet_nid_t        nid;
1135         struct lnet_text_buf  *ltb;
1136         int               rc;
1137         char             *sep;
1138         char             *token = str;
1139         int               ntokens = 0;
1140         int               myrc = -1;
1141         __u32             hops;
1142         int               got_hops = 0;
1143         unsigned int      priority = 0;
1144
1145         INIT_LIST_HEAD(&gateways);
1146         INIT_LIST_HEAD(&nets);
1147
1148         /* save a copy of the string for error messages */
1149         strncpy(cmd, str, sizeof(cmd));
1150         cmd[sizeof(cmd) - 1] = '\0';
1151
1152         sep = str;
1153         for (;;) {
1154                 /* scan for token start */
1155                 while (isspace(*sep))
1156                         sep++;
1157                 if (*sep == 0) {
1158                         if (ntokens < (got_hops ? 3 : 2))
1159                                 goto token_error;
1160                         break;
1161                 }
1162
1163                 ntokens++;
1164                 token = sep++;
1165
1166                 /* scan for token end */
1167                 while (*sep != 0 && !isspace(*sep))
1168                         sep++;
1169                 if (*sep != 0)
1170                         *sep++ = 0;
1171
1172                 if (ntokens == 1) {
1173                         tmp2 = &nets;           /* expanding nets */
1174                 } else if (ntokens == 2 &&
1175                            lnet_parse_hops(token, &hops)) {
1176                         got_hops = 1;           /* got a hop count */
1177                         continue;
1178                 } else {
1179                         tmp2 = &gateways;       /* expanding gateways */
1180                 }
1181
1182                 ltb = lnet_new_text_buf(strlen(token));
1183                 if (ltb == NULL)
1184                         goto out;
1185
1186                 strcpy(ltb->ltb_text, token);
1187                 tmp1 = &ltb->ltb_list;
1188                 list_add_tail(tmp1, tmp2);
1189
1190                 while (tmp1 != tmp2) {
1191                         ltb = list_entry(tmp1, struct lnet_text_buf, ltb_list);
1192
1193                         rc = lnet_str2tbs_expand(tmp1->next, ltb->ltb_text);
1194                         if (rc < 0)
1195                                 goto token_error;
1196
1197                         tmp1 = tmp1->next;
1198
1199                         if (rc > 0) {           /* expanded! */
1200                                 list_del(&ltb->ltb_list);
1201                                 lnet_free_text_buf(ltb);
1202                                 continue;
1203                         }
1204
1205                         if (ntokens == 1) {
1206                                 net = libcfs_str2net(ltb->ltb_text);
1207                                 if (net == LNET_NIDNET(LNET_NID_ANY) ||
1208                                     LNET_NETTYP(net) == LOLND)
1209                                         goto token_error;
1210                         } else {
1211                                 rc = lnet_parse_priority(ltb->ltb_text,
1212                                                          &priority, &token);
1213                                 if (rc < 0)
1214                                         goto token_error;
1215
1216                                 nid = libcfs_str2nid(ltb->ltb_text);
1217                                 if (nid == LNET_NID_ANY ||
1218                                     LNET_NETTYP(LNET_NIDNET(nid)) == LOLND)
1219                                         goto token_error;
1220                         }
1221                 }
1222         }
1223
1224         /* if there are no hops set then we want to flag this value as
1225          * unset since hops is an optional parameter */
1226         if (!got_hops)
1227                 hops = LNET_UNDEFINED_HOPS;
1228
1229         LASSERT(!list_empty(&nets));
1230         LASSERT(!list_empty(&gateways));
1231
1232         list_for_each(tmp1, &nets) {
1233                 ltb = list_entry(tmp1, struct lnet_text_buf, ltb_list);
1234                 net = libcfs_str2net(ltb->ltb_text);
1235                 LASSERT (net != LNET_NIDNET(LNET_NID_ANY));
1236
1237                 list_for_each(tmp2, &gateways) {
1238                         ltb = list_entry(tmp2, struct lnet_text_buf, ltb_list);
1239                         nid = libcfs_str2nid(ltb->ltb_text);
1240                         LASSERT(nid != LNET_NID_ANY);
1241
1242                         if (lnet_islocalnid(nid)) {
1243                                 *im_a_router = 1;
1244                                 continue;
1245                         }
1246
1247                         rc = lnet_add_route(net, hops, nid, priority);
1248                         if (rc != 0 && rc != -EEXIST && rc != -EHOSTUNREACH) {
1249                                 CERROR("Can't create route "
1250                                        "to %s via %s\n",
1251                                        libcfs_net2str(net),
1252                                        libcfs_nid2str(nid));
1253                                 goto out;
1254                         }
1255                 }
1256         }
1257
1258         myrc = 0;
1259         goto out;
1260
1261 token_error:
1262         lnet_syntax("routes", cmd, (int)(token - str), strlen(token));
1263 out:
1264         lnet_free_text_bufs(&nets);
1265         lnet_free_text_bufs(&gateways);
1266         return myrc;
1267 }
1268
1269 static int
1270 lnet_parse_route_tbs(struct list_head *tbs, int *im_a_router)
1271 {
1272         struct lnet_text_buf   *ltb;
1273
1274         while (!list_empty(tbs)) {
1275                 ltb = list_entry(tbs->next, struct lnet_text_buf, ltb_list);
1276
1277                 if (lnet_parse_route(ltb->ltb_text, im_a_router) < 0) {
1278                         lnet_free_text_bufs(tbs);
1279                         return -EINVAL;
1280                 }
1281
1282                 list_del(&ltb->ltb_list);
1283                 lnet_free_text_buf(ltb);
1284         }
1285
1286         return 0;
1287 }
1288
1289 int
1290 lnet_parse_routes (char *routes, int *im_a_router)
1291 {
1292         struct list_head tbs;
1293         int              rc = 0;
1294
1295         *im_a_router = 0;
1296
1297         INIT_LIST_HEAD(&tbs);
1298
1299         if (lnet_str2tbs_sep(&tbs, routes) < 0) {
1300                 CERROR("Error parsing routes\n");
1301                 rc = -EINVAL;
1302         } else {
1303                 rc = lnet_parse_route_tbs(&tbs, im_a_router);
1304         }
1305
1306         LASSERT (lnet_tbnob == 0);
1307         return rc;
1308 }
1309
1310 static int
1311 lnet_match_network_token(char *token, int len, __u32 *ipaddrs, int nip)
1312 {
1313         struct list_head list = LIST_HEAD_INIT(list);
1314         int             rc;
1315         int             i;
1316
1317         rc = cfs_ip_addr_parse(token, len, &list);
1318         if (rc != 0)
1319                 return rc;
1320
1321         for (rc = i = 0; !rc && i < nip; i++)
1322                 rc = cfs_ip_addr_match(ipaddrs[i], &list);
1323
1324         cfs_expr_list_free_list(&list);
1325
1326         return rc;
1327 }
1328
1329 static int
1330 lnet_match_network_tokens(char *net_entry, __u32 *ipaddrs, int nip)
1331 {
1332         static char tokens[LNET_SINGLE_TEXTBUF_NOB];
1333
1334         int   matched = 0;
1335         int   ntokens = 0;
1336         int   len;
1337         char *net = NULL;
1338         char *sep;
1339         char *token;
1340         int   rc;
1341
1342         LASSERT(strlen(net_entry) < sizeof(tokens));
1343
1344         /* work on a copy of the string */
1345         strcpy(tokens, net_entry);
1346         sep = tokens;
1347         for (;;) {
1348                 /* scan for token start */
1349                 while (isspace(*sep))
1350                         sep++;
1351                 if (*sep == 0)
1352                         break;
1353
1354                 token = sep++;
1355
1356                 /* scan for token end */
1357                 while (*sep != 0 && !isspace(*sep))
1358                         sep++;
1359                 if (*sep != 0)
1360                         *sep++ = 0;
1361
1362                 if (ntokens++ == 0) {
1363                         net = token;
1364                         continue;
1365                 }
1366
1367                 len = strlen(token);
1368
1369                 rc = lnet_match_network_token(token, len, ipaddrs, nip);
1370                 if (rc < 0) {
1371                         lnet_syntax("ip2nets", net_entry,
1372                                     (int)(token - tokens), len);
1373                         return rc;
1374                 }
1375
1376                 matched |= (rc != 0);
1377         }
1378
1379         if (!matched)
1380                 return 0;
1381
1382         strcpy(net_entry, net);                 /* replace with matched net */
1383         return 1;
1384 }
1385
1386 static __u32
1387 lnet_netspec2net(char *netspec)
1388 {
1389         char   *bracket = strchr(netspec, '(');
1390         __u32   net;
1391
1392         if (bracket != NULL)
1393                 *bracket = 0;
1394
1395         net = libcfs_str2net(netspec);
1396
1397         if (bracket != NULL)
1398                 *bracket = '(';
1399
1400         return net;
1401 }
1402
1403 static int
1404 lnet_splitnets(char *source, struct list_head *nets)
1405 {
1406         int               offset = 0;
1407         int               offset2;
1408         int               len;
1409         struct lnet_text_buf  *tb;
1410         struct lnet_text_buf  *tb2;
1411         struct list_head *t;
1412         char             *sep;
1413         char             *bracket;
1414         __u32             net;
1415
1416         LASSERT(!list_empty(nets));
1417         LASSERT(nets->next == nets->prev);      /* single entry */
1418
1419         tb = list_entry(nets->next, struct lnet_text_buf, ltb_list);
1420
1421         for (;;) {
1422                 sep = strchr(tb->ltb_text, ',');
1423                 bracket = strchr(tb->ltb_text, '(');
1424
1425                 if (sep != NULL &&
1426                     bracket != NULL &&
1427                     bracket < sep) {
1428                         /* netspec lists interfaces... */
1429
1430                         offset2 = offset + (int)(bracket - tb->ltb_text);
1431                         len = strlen(bracket);
1432
1433                         bracket = strchr(bracket + 1, ')');
1434
1435                         if (bracket == NULL ||
1436                             !(bracket[1] == ',' || bracket[1] == 0)) {
1437                                 lnet_syntax("ip2nets", source, offset2, len);
1438                                 return -EINVAL;
1439                         }
1440
1441                         sep = (bracket[1] == 0) ? NULL : bracket + 1;
1442                 }
1443
1444                 if (sep != NULL)
1445                         *sep++ = 0;
1446
1447                 net = lnet_netspec2net(tb->ltb_text);
1448                 if (net == LNET_NIDNET(LNET_NID_ANY)) {
1449                         lnet_syntax("ip2nets", source, offset,
1450                                     strlen(tb->ltb_text));
1451                         return -EINVAL;
1452                 }
1453
1454                 list_for_each(t, nets) {
1455                         tb2 = list_entry(t, struct lnet_text_buf, ltb_list);
1456
1457                         if (tb2 == tb)
1458                                 continue;
1459
1460                         if (net == lnet_netspec2net(tb2->ltb_text)) {
1461                                 /* duplicate network */
1462                                 lnet_syntax("ip2nets", source, offset,
1463                                             strlen(tb->ltb_text));
1464                                 return -EINVAL;
1465                         }
1466                 }
1467
1468                 if (sep == NULL)
1469                         return 0;
1470
1471                 offset += (int)(sep - tb->ltb_text);
1472                 len = strlen(sep);
1473                 tb2 = lnet_new_text_buf(len);
1474                 if (tb2 == NULL)
1475                         return -ENOMEM;
1476
1477                 strncpy(tb2->ltb_text, sep, len);
1478                 tb2->ltb_text[len] = '\0';
1479                 list_add_tail(&tb2->ltb_list, nets);
1480
1481                 tb = tb2;
1482         }
1483 }
1484
1485 static int
1486 lnet_match_networks (char **networksp, char *ip2nets, __u32 *ipaddrs, int nip)
1487 {
1488         static char       networks[LNET_SINGLE_TEXTBUF_NOB];
1489         static char       source[LNET_SINGLE_TEXTBUF_NOB];
1490
1491         struct list_head  raw_entries;
1492         struct list_head  matched_nets;
1493         struct list_head  current_nets;
1494         struct list_head *t;
1495         struct list_head *t2;
1496         struct lnet_text_buf  *tb;
1497         struct lnet_text_buf  *tb2;
1498         __u32             net1;
1499         __u32             net2;
1500         int               len;
1501         int               count;
1502         int               dup;
1503         int               rc;
1504
1505         INIT_LIST_HEAD(&raw_entries);
1506         if (lnet_str2tbs_sep(&raw_entries, ip2nets) < 0) {
1507                 CERROR("Error parsing ip2nets\n");
1508                 LASSERT(lnet_tbnob == 0);
1509                 return -EINVAL;
1510         }
1511
1512         INIT_LIST_HEAD(&matched_nets);
1513         INIT_LIST_HEAD(&current_nets);
1514         networks[0] = 0;
1515         count = 0;
1516         len = 0;
1517         rc = 0;
1518
1519         while (!list_empty(&raw_entries)) {
1520                 tb = list_entry(raw_entries.next, struct lnet_text_buf,
1521                                 ltb_list);
1522
1523                 strncpy(source, tb->ltb_text, sizeof(source));
1524                 source[sizeof(source) - 1] = '\0';
1525
1526                 /* replace ltb_text with the network(s) add on match */
1527                 rc = lnet_match_network_tokens(tb->ltb_text, ipaddrs, nip);
1528                 if (rc < 0)
1529                         break;
1530
1531                 list_del(&tb->ltb_list);
1532
1533                 if (rc == 0) {                  /* no match */
1534                         lnet_free_text_buf(tb);
1535                         continue;
1536                 }
1537
1538                 /* split into separate networks */
1539                 INIT_LIST_HEAD(&current_nets);
1540                 list_add(&tb->ltb_list, &current_nets);
1541                 rc = lnet_splitnets(source, &current_nets);
1542                 if (rc < 0)
1543                         break;
1544
1545                 dup = 0;
1546                 list_for_each(t, &current_nets) {
1547                         tb = list_entry(t, struct lnet_text_buf, ltb_list);
1548                         net1 = lnet_netspec2net(tb->ltb_text);
1549                         LASSERT(net1 != LNET_NIDNET(LNET_NID_ANY));
1550
1551                         list_for_each(t2, &matched_nets) {
1552                                 tb2 = list_entry(t2, struct lnet_text_buf,
1553                                                  ltb_list);
1554                                 net2 = lnet_netspec2net(tb2->ltb_text);
1555                                 LASSERT(net2 != LNET_NIDNET(LNET_NID_ANY));
1556
1557                                 if (net1 == net2) {
1558                                         dup = 1;
1559                                         break;
1560                                 }
1561                         }
1562
1563                         if (dup)
1564                                 break;
1565                 }
1566
1567                 if (dup) {
1568                         lnet_free_text_bufs(&current_nets);
1569                         continue;
1570                 }
1571
1572                 list_for_each_safe(t, t2, &current_nets) {
1573                         tb = list_entry(t, struct lnet_text_buf, ltb_list);
1574
1575                         list_del(&tb->ltb_list);
1576                         list_add_tail(&tb->ltb_list, &matched_nets);
1577
1578                         len += snprintf(networks + len, sizeof(networks) - len,
1579                                         "%s%s", (len == 0) ? "" : ",",
1580                                         tb->ltb_text);
1581
1582                         if (len >= sizeof(networks)) {
1583                                 CERROR("Too many matched networks\n");
1584                                 rc = -E2BIG;
1585                                 goto out;
1586                         }
1587                 }
1588
1589                 count++;
1590         }
1591
1592  out:
1593         lnet_free_text_bufs(&raw_entries);
1594         lnet_free_text_bufs(&matched_nets);
1595         lnet_free_text_bufs(&current_nets);
1596         LASSERT(lnet_tbnob == 0);
1597
1598         if (rc < 0)
1599                 return rc;
1600
1601         *networksp = networks;
1602         return count;
1603 }
1604
1605 static void
1606 lnet_ipaddr_free_enumeration(__u32 *ipaddrs, int nip)
1607 {
1608         LIBCFS_FREE(ipaddrs, nip * sizeof(*ipaddrs));
1609 }
1610
1611 static int
1612 lnet_ipaddr_enumerate (__u32 **ipaddrsp)
1613 {
1614         int        up;
1615         __u32      netmask;
1616         __u32     *ipaddrs;
1617         __u32     *ipaddrs2;
1618         int        nip;
1619         char     **ifnames;
1620         int        nif = lnet_ipif_enumerate(&ifnames);
1621         int        i;
1622         int        rc;
1623
1624         if (nif <= 0)
1625                 return nif;
1626
1627         LIBCFS_ALLOC(ipaddrs, nif * sizeof(*ipaddrs));
1628         if (ipaddrs == NULL) {
1629                 CERROR("Can't allocate ipaddrs[%d]\n", nif);
1630                 lnet_ipif_free_enumeration(ifnames, nif);
1631                 return -ENOMEM;
1632         }
1633
1634         for (i = nip = 0; i < nif; i++) {
1635                 if (!strcmp(ifnames[i], "lo"))
1636                         continue;
1637
1638                 rc = lnet_ipif_query(ifnames[i], &up,
1639                                        &ipaddrs[nip], &netmask);
1640                 if (rc != 0) {
1641                         CWARN("Can't query interface %s: %d\n",
1642                               ifnames[i], rc);
1643                         continue;
1644                 }
1645
1646                 if (!up) {
1647                         CWARN("Ignoring interface %s: it's down\n",
1648                               ifnames[i]);
1649                         continue;
1650                 }
1651
1652                 nip++;
1653         }
1654
1655         lnet_ipif_free_enumeration(ifnames, nif);
1656
1657         if (nip == nif) {
1658                 *ipaddrsp = ipaddrs;
1659         } else {
1660                 if (nip > 0) {
1661                         LIBCFS_ALLOC(ipaddrs2, nip * sizeof(*ipaddrs2));
1662                         if (ipaddrs2 == NULL) {
1663                                 CERROR("Can't allocate ipaddrs[%d]\n", nip);
1664                                 nip = -ENOMEM;
1665                         } else {
1666                                 memcpy(ipaddrs2, ipaddrs,
1667                                         nip * sizeof(*ipaddrs));
1668                                 *ipaddrsp = ipaddrs2;
1669                                 rc = nip;
1670                         }
1671                 }
1672                 lnet_ipaddr_free_enumeration(ipaddrs, nif);
1673         }
1674         return nip;
1675 }
1676
1677 int
1678 lnet_parse_ip2nets (char **networksp, char *ip2nets)
1679 {
1680         __u32     *ipaddrs = NULL;
1681         int        nip = lnet_ipaddr_enumerate(&ipaddrs);
1682         int        rc;
1683
1684         if (nip < 0) {
1685                 LCONSOLE_ERROR_MSG(0x117, "Error %d enumerating local IP "
1686                                    "interfaces for ip2nets to match\n", nip);
1687                 return nip;
1688         }
1689
1690         if (nip == 0) {
1691                 LCONSOLE_ERROR_MSG(0x118, "No local IP interfaces "
1692                                    "for ip2nets to match\n");
1693                 return -ENOENT;
1694         }
1695
1696         rc = lnet_match_networks(networksp, ip2nets, ipaddrs, nip);
1697         lnet_ipaddr_free_enumeration(ipaddrs, nip);
1698
1699         if (rc < 0) {
1700                 LCONSOLE_ERROR_MSG(0x119, "Error %d parsing ip2nets\n", rc);
1701                 return rc;
1702         }
1703
1704         if (rc == 0) {
1705                 LCONSOLE_ERROR_MSG(0x11a, "ip2nets does not match "
1706                                    "any local IP interfaces\n");
1707                 return -ENOENT;
1708         }
1709
1710         return 0;
1711 }