Whamcloud - gitweb
LU-11424 lnet: copy the correct amount of cpts to lnet_cpts
[fs/lustre-release.git] / lnet / lnet / config.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  */
32
33 #define DEBUG_SUBSYSTEM S_LNET
34
35 #include <linux/ctype.h>
36 #include <linux/nsproxy.h>
37 #include <net/net_namespace.h>
38 #include <lnet/lib-lnet.h>
39
40 /* tmp struct for parsing routes */
41 struct lnet_text_buf {
42         struct list_head        ltb_list;       /* stash on lists */
43         int                     ltb_size;       /* allocated size */
44         char                    ltb_text[0];    /* text buffer */
45 };
46
47 static int lnet_tbnob = 0;                      /* track text buf allocation */
48 #define LNET_MAX_TEXTBUF_NOB     (64<<10)       /* bound allocation */
49 #define LNET_SINGLE_TEXTBUF_NOB  (4<<10)
50
51 #define SPACESTR " \t\v\r\n"
52 #define DELIMITERS ":()[]"
53
54 static void
55 lnet_syntax(const char *name, const char *str, int offset, int width)
56 {
57         static char dots[LNET_SINGLE_TEXTBUF_NOB];
58         static char dashes[LNET_SINGLE_TEXTBUF_NOB];
59
60         memset(dots, '.', sizeof(dots));
61         dots[sizeof(dots)-1] = 0;
62         memset(dashes, '-', sizeof(dashes));
63         dashes[sizeof(dashes)-1] = 0;
64
65         LCONSOLE_ERROR_MSG(0x10f, "Error parsing '%s=\"%s\"'\n", name, str);
66         LCONSOLE_ERROR_MSG(0x110, "here...........%.*s..%.*s|%.*s|\n",
67                            (int)strlen(name), dots, offset, dots,
68                             (width < 1) ? 0 : width - 1, dashes);
69 }
70
71 static int
72 lnet_issep (char c)
73 {
74         switch (c) {
75         case '\n':
76         case '\r':
77         case ';':
78                 return 1;
79         default:
80                 return 0;
81         }
82 }
83
84 bool
85 lnet_net_unique(__u32 net_id, struct list_head *netlist,
86                 struct lnet_net **net)
87 {
88         struct lnet_net  *net_l;
89
90         if (!netlist)
91                 return true;
92
93         list_for_each_entry(net_l, netlist, net_list) {
94                 if (net_l->net_id == net_id) {
95                         if (net != NULL)
96                                 *net = net_l;
97                         return false;
98                 }
99         }
100
101         return true;
102 }
103
104 /* check that the NI is unique within the list of NIs already added to
105  * a network */
106 bool
107 lnet_ni_unique_net(struct list_head *nilist, char *iface)
108 {
109         struct list_head *tmp;
110         struct lnet_ni *ni;
111
112         list_for_each(tmp, nilist) {
113                 ni = list_entry(tmp, struct lnet_ni, ni_netlist);
114
115                 if (ni->ni_interfaces[0] != NULL &&
116                     strncmp(ni->ni_interfaces[0], iface, strlen(iface)) == 0)
117                         return false;
118         }
119
120         return true;
121 }
122
123 /* check that the NI is unique to the interfaces with in the same NI.
124  * This is only a consideration if use_tcp_bonding is set */
125 static bool
126 lnet_ni_unique_ni(char *iface_list[LNET_INTERFACES_NUM], char *iface)
127 {
128         int i;
129         for (i = 0; i < LNET_INTERFACES_NUM; i++) {
130                 if (iface_list[i] != NULL &&
131                     strncmp(iface_list[i], iface, strlen(iface)) == 0)
132                         return false;
133         }
134
135         return true;
136 }
137
138 static bool
139 in_array(__u32 *array, __u32 size, __u32 value)
140 {
141         int i;
142
143         for (i = 0; i < size; i++) {
144                 if (array[i] == value)
145                         return false;
146         }
147
148         return true;
149 }
150
151 static int
152 lnet_net_append_cpts(__u32 *cpts, __u32 ncpts, struct lnet_net *net)
153 {
154         __u32 *added_cpts = NULL;
155         int i, j = 0, rc = 0;
156
157         /*
158          * no need to go futher since a subset of the NIs already exist on
159          * all CPTs
160          */
161         if (net->net_ncpts == LNET_CPT_NUMBER)
162                 return 0;
163
164         if (cpts == NULL) {
165                 /* there is an NI which will exist on all CPTs */
166                 if (net->net_cpts != NULL)
167                         LIBCFS_FREE(net->net_cpts, sizeof(*net->net_cpts) *
168                                     net->net_ncpts);
169                 net->net_cpts = NULL;
170                 net->net_ncpts = LNET_CPT_NUMBER;
171                 return 0;
172         }
173
174         if (net->net_cpts == NULL) {
175                 LIBCFS_ALLOC(net->net_cpts, sizeof(*net->net_cpts) * ncpts);
176                 if (net->net_cpts == NULL)
177                         return -ENOMEM;
178                 memcpy(net->net_cpts, cpts, ncpts * sizeof(*net->net_cpts));
179                 net->net_ncpts = ncpts;
180                 return 0;
181         }
182
183         LIBCFS_ALLOC(added_cpts, sizeof(*added_cpts) * LNET_CPT_NUMBER);
184         if (added_cpts == NULL)
185                 return -ENOMEM;
186
187         for (i = 0; i < ncpts; i++) {
188                 if (!in_array(net->net_cpts, net->net_ncpts, cpts[i])) {
189                         added_cpts[j] = cpts[i];
190                         j++;
191                 }
192         }
193
194         /* append the new cpts if any to the list of cpts in the net */
195         if (j > 0) {
196                 __u32 *array = NULL, *loc;
197                 __u32 total_entries = j + net->net_ncpts;
198
199                 LIBCFS_ALLOC(array, sizeof(*net->net_cpts) * total_entries);
200                 if (array == NULL) {
201                         rc = -ENOMEM;
202                         goto failed;
203                 }
204
205                 memcpy(array, net->net_cpts, net->net_ncpts);
206                 loc = array + net->net_ncpts;
207                 memcpy(loc, added_cpts, j);
208
209                 LIBCFS_FREE(net->net_cpts, sizeof(*net->net_cpts) *
210                             net->net_ncpts);
211                 net->net_ncpts = total_entries;
212                 net->net_cpts = array;
213         }
214
215 failed:
216         LIBCFS_FREE(added_cpts, sizeof(*added_cpts) * LNET_CPT_NUMBER);
217
218         return rc;
219 }
220
221 static void
222 lnet_net_remove_cpts(__u32 *cpts, __u32 ncpts, struct lnet_net *net)
223 {
224         struct lnet_ni *ni;
225         int rc;
226
227         /*
228          * Operation Assumption:
229          *      This function is called after an NI has been removed from
230          *      its parent net.
231          *
232          * if we're removing an NI which exists on all CPTs then
233          * we have to check if any of the other NIs on this net also
234          * exists on all CPTs. If none, then we need to build our Net CPT
235          * list based on the remaining NIs.
236          *
237          * If the NI being removed exist on a subset of the CPTs then we
238          * alo rebuild the Net CPT list based on the remaining NIs, which
239          * should resutl in the expected Net CPT list.
240          */
241
242         /*
243          * sometimes this function can be called due to some failure
244          * creating an NI, before any of the cpts are allocated, so check
245          * for that case and don't do anything
246          */
247         if (ncpts == 0)
248                 return;
249
250         if (ncpts == LNET_CPT_NUMBER) {
251                 /*
252                  * first iteration through the NI list in the net to see
253                  * if any of the NIs exist on all the CPTs. If one is
254                  * found then our job is done.
255                  */
256                 list_for_each_entry(ni, &net->net_ni_list, ni_netlist) {
257                         if (ni->ni_ncpts == LNET_CPT_NUMBER)
258                                 return;
259                 }
260         }
261
262         /*
263          * Rebuild the Net CPT list again, thereby only including only the
264          * CPTs which the remaining NIs are associated with.
265          */
266         if (net->net_cpts != NULL) {
267                 LIBCFS_FREE(net->net_cpts,
268                         sizeof(*net->net_cpts) * net->net_ncpts);
269                 net->net_cpts = NULL;
270         }
271
272         list_for_each_entry(ni, &net->net_ni_list, ni_netlist) {
273                 rc = lnet_net_append_cpts(ni->ni_cpts, ni->ni_ncpts,
274                                           net);
275                 if (rc != 0) {
276                         CERROR("Out of Memory\n");
277                         /*
278                          * do our best to keep on going. Delete
279                          * the net cpts and set it to NULL. This
280                          * way we can keep on going but less
281                          * efficiently, since memory accesses might be
282                          * accross CPT lines.
283                          */
284                         if (net->net_cpts != NULL) {
285                                 LIBCFS_FREE(net->net_cpts,
286                                                 sizeof(*net->net_cpts) *
287                                                 net->net_ncpts);
288                                 net->net_cpts = NULL;
289                                 net->net_ncpts = LNET_CPT_NUMBER;
290                         }
291                         return;
292                 }
293         }
294 }
295
296 void
297 lnet_ni_free(struct lnet_ni *ni)
298 {
299         int i;
300
301         lnet_net_remove_cpts(ni->ni_cpts, ni->ni_ncpts, ni->ni_net);
302
303         if (ni->ni_refs != NULL)
304                 cfs_percpt_free(ni->ni_refs);
305
306         if (ni->ni_tx_queues != NULL)
307                 cfs_percpt_free(ni->ni_tx_queues);
308
309         if (ni->ni_cpts != NULL)
310                 cfs_expr_list_values_free(ni->ni_cpts, ni->ni_ncpts);
311
312         for (i = 0; i < LNET_INTERFACES_NUM &&
313                     ni->ni_interfaces[i] != NULL; i++) {
314                 LIBCFS_FREE(ni->ni_interfaces[i],
315                             strlen(ni->ni_interfaces[i]) + 1);
316         }
317
318         /* release reference to net namespace */
319         if (ni->ni_net_ns != NULL)
320                 put_net(ni->ni_net_ns);
321
322         LIBCFS_FREE(ni, sizeof(*ni));
323 }
324
325 void
326 lnet_net_free(struct lnet_net *net)
327 {
328         struct list_head *tmp, *tmp2;
329         struct lnet_ni *ni;
330
331         LASSERT(list_empty(&net->net_ni_zombie));
332
333         /*
334          * delete any nis that haven't been added yet. This could happen
335          * if there is a failure on net startup
336          */
337         list_for_each_safe(tmp, tmp2, &net->net_ni_added) {
338                 ni = list_entry(tmp, struct lnet_ni, ni_netlist);
339                 list_del_init(&ni->ni_netlist);
340                 lnet_ni_free(ni);
341         }
342
343         /* delete any nis which have been started. */
344         list_for_each_safe(tmp, tmp2, &net->net_ni_list) {
345                 ni = list_entry(tmp, struct lnet_ni, ni_netlist);
346                 list_del_init(&ni->ni_netlist);
347                 lnet_ni_free(ni);
348         }
349
350         if (net->net_cpts != NULL)
351                 LIBCFS_FREE(net->net_cpts,
352                             sizeof(*net->net_cpts) * net->net_ncpts);
353
354         LIBCFS_FREE(net, sizeof(*net));
355 }
356
357 struct lnet_net *
358 lnet_net_alloc(__u32 net_id, struct list_head *net_list)
359 {
360         struct lnet_net         *net;
361
362         if (!lnet_net_unique(net_id, net_list, NULL)) {
363                 CERROR("Duplicate net %s. Ignore\n",
364                        libcfs_net2str(net_id));
365                 return NULL;
366         }
367
368         LIBCFS_ALLOC(net, sizeof(*net));
369         if (net == NULL) {
370                 CERROR("Out of memory creating network %s\n",
371                        libcfs_net2str(net_id));
372                 return NULL;
373         }
374
375         INIT_LIST_HEAD(&net->net_list);
376         INIT_LIST_HEAD(&net->net_ni_list);
377         INIT_LIST_HEAD(&net->net_ni_added);
378         INIT_LIST_HEAD(&net->net_ni_zombie);
379
380         net->net_id = net_id;
381         net->net_state = LNET_NET_STATE_INIT;
382
383         /* initialize global paramters to undefiend */
384         net->net_tunables.lct_peer_timeout = -1;
385         net->net_tunables.lct_max_tx_credits = -1;
386         net->net_tunables.lct_peer_tx_credits = -1;
387         net->net_tunables.lct_peer_rtr_credits = -1;
388
389         if (net_list)
390                 list_add_tail(&net->net_list, net_list);
391
392         return net;
393 }
394
395 static int
396 lnet_ni_add_interface(struct lnet_ni *ni, char *iface)
397 {
398         int niface = 0;
399
400         if (ni == NULL)
401                 return -ENOMEM;
402
403         if (!lnet_ni_unique_ni(ni->ni_interfaces, iface))
404                 return -EINVAL;
405
406         /* Allocate a separate piece of memory and copy
407          * into it the string, so we don't have
408          * a depencency on the tokens string.  This way we
409          * can free the tokens at the end of the function.
410          * The newly allocated ni_interfaces[] can be
411          * freed when freeing the NI */
412         while (niface < LNET_INTERFACES_NUM &&
413                ni->ni_interfaces[niface] != NULL)
414                 niface++;
415
416         if (niface >= LNET_INTERFACES_NUM) {
417                 LCONSOLE_ERROR_MSG(0x115, "Too many interfaces "
418                                    "for net %s\n",
419                                    libcfs_net2str(LNET_NIDNET(ni->ni_nid)));
420                 return -EINVAL;
421         }
422
423         LIBCFS_ALLOC(ni->ni_interfaces[niface],
424                      strlen(iface) + 1);
425
426         if (ni->ni_interfaces[niface] == NULL) {
427                 CERROR("Can't allocate net interface name\n");
428                 return -ENOMEM;
429         }
430
431         strncpy(ni->ni_interfaces[niface], iface,
432                 strlen(iface) + 1);
433
434         return 0;
435 }
436
437 static struct lnet_ni *
438 lnet_ni_alloc_common(struct lnet_net *net, char *iface)
439 {
440         struct lnet_tx_queue    *tq;
441         struct lnet_ni          *ni;
442         int                     i;
443
444         if (iface != NULL)
445                 /* make sure that this NI is unique in the net it's
446                  * being added to */
447                 if (!lnet_ni_unique_net(&net->net_ni_added, iface))
448                         return NULL;
449
450         LIBCFS_ALLOC(ni, sizeof(*ni));
451         if (ni == NULL) {
452                 CERROR("Out of memory creating network interface %s%s\n",
453                        libcfs_net2str(net->net_id),
454                        (iface != NULL) ? iface : "");
455                 return NULL;
456         }
457
458         spin_lock_init(&ni->ni_lock);
459         INIT_LIST_HEAD(&ni->ni_cptlist);
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         int        up;
1616         __u32      netmask;
1617         __u32     *ipaddrs;
1618         __u32     *ipaddrs2;
1619         int        nip;
1620         char     **ifnames;
1621         int        nif = lnet_ipif_enumerate(&ifnames);
1622         int        i;
1623         int        rc;
1624
1625         if (nif <= 0)
1626                 return nif;
1627
1628         LIBCFS_ALLOC(ipaddrs, nif * sizeof(*ipaddrs));
1629         if (ipaddrs == NULL) {
1630                 CERROR("Can't allocate ipaddrs[%d]\n", nif);
1631                 lnet_ipif_free_enumeration(ifnames, nif);
1632                 return -ENOMEM;
1633         }
1634
1635         for (i = nip = 0; i < nif; i++) {
1636                 if (!strcmp(ifnames[i], "lo"))
1637                         continue;
1638
1639                 rc = lnet_ipif_query(ifnames[i], &up,
1640                                        &ipaddrs[nip], &netmask);
1641                 if (rc != 0) {
1642                         CWARN("Can't query interface %s: %d\n",
1643                               ifnames[i], rc);
1644                         continue;
1645                 }
1646
1647                 if (!up) {
1648                         CWARN("Ignoring interface %s: it's down\n",
1649                               ifnames[i]);
1650                         continue;
1651                 }
1652
1653                 nip++;
1654         }
1655
1656         lnet_ipif_free_enumeration(ifnames, nif);
1657
1658         if (nip == nif) {
1659                 *ipaddrsp = ipaddrs;
1660         } else {
1661                 if (nip > 0) {
1662                         LIBCFS_ALLOC(ipaddrs2, nip * sizeof(*ipaddrs2));
1663                         if (ipaddrs2 == NULL) {
1664                                 CERROR("Can't allocate ipaddrs[%d]\n", nip);
1665                                 nip = -ENOMEM;
1666                         } else {
1667                                 memcpy(ipaddrs2, ipaddrs,
1668                                         nip * sizeof(*ipaddrs));
1669                                 *ipaddrsp = ipaddrs2;
1670                                 rc = nip;
1671                         }
1672                 }
1673                 lnet_ipaddr_free_enumeration(ipaddrs, nif);
1674         }
1675         return nip;
1676 }
1677
1678 int
1679 lnet_parse_ip2nets (char **networksp, char *ip2nets)
1680 {
1681         __u32     *ipaddrs = NULL;
1682         int        nip = lnet_ipaddr_enumerate(&ipaddrs);
1683         int        rc;
1684
1685         if (nip < 0) {
1686                 LCONSOLE_ERROR_MSG(0x117, "Error %d enumerating local IP "
1687                                    "interfaces for ip2nets to match\n", nip);
1688                 return nip;
1689         }
1690
1691         if (nip == 0) {
1692                 LCONSOLE_ERROR_MSG(0x118, "No local IP interfaces "
1693                                    "for ip2nets to match\n");
1694                 return -ENOENT;
1695         }
1696
1697         rc = lnet_match_networks(networksp, ip2nets, ipaddrs, nip);
1698         lnet_ipaddr_free_enumeration(ipaddrs, nip);
1699
1700         if (rc < 0) {
1701                 LCONSOLE_ERROR_MSG(0x119, "Error %d parsing ip2nets\n", rc);
1702                 return rc;
1703         }
1704
1705         if (rc == 0) {
1706                 LCONSOLE_ERROR_MSG(0x11a, "ip2nets does not match "
1707                                    "any local IP interfaces\n");
1708                 return -ENOENT;
1709         }
1710
1711         return 0;
1712 }