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