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