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