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