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