Whamcloud - gitweb
7b7d7754bebcdc76ad2c4a7e3834361d0bdb0926
[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,
207                        net->net_ncpts * sizeof(*net->net_cpts));
208                 loc = array + net->net_ncpts;
209                 memcpy(loc, added_cpts, j * sizeof(*net->net_cpts));
210
211                 LIBCFS_FREE(net->net_cpts, sizeof(*net->net_cpts) *
212                             net->net_ncpts);
213                 net->net_ncpts = total_entries;
214                 net->net_cpts = array;
215         }
216
217 failed:
218         LIBCFS_FREE(added_cpts, sizeof(*added_cpts) * LNET_CPT_NUMBER);
219
220         return rc;
221 }
222
223 static void
224 lnet_net_remove_cpts(__u32 *cpts, __u32 ncpts, struct lnet_net *net)
225 {
226         struct lnet_ni *ni;
227         int rc;
228
229         /*
230          * Operation Assumption:
231          *      This function is called after an NI has been removed from
232          *      its parent net.
233          *
234          * if we're removing an NI which exists on all CPTs then
235          * we have to check if any of the other NIs on this net also
236          * exists on all CPTs. If none, then we need to build our Net CPT
237          * list based on the remaining NIs.
238          *
239          * If the NI being removed exist on a subset of the CPTs then we
240          * alo rebuild the Net CPT list based on the remaining NIs, which
241          * should resutl in the expected Net CPT list.
242          */
243
244         /*
245          * sometimes this function can be called due to some failure
246          * creating an NI, before any of the cpts are allocated, so check
247          * for that case and don't do anything
248          */
249         if (ncpts == 0)
250                 return;
251
252         if (ncpts == LNET_CPT_NUMBER) {
253                 /*
254                  * first iteration through the NI list in the net to see
255                  * if any of the NIs exist on all the CPTs. If one is
256                  * found then our job is done.
257                  */
258                 list_for_each_entry(ni, &net->net_ni_list, ni_netlist) {
259                         if (ni->ni_ncpts == LNET_CPT_NUMBER)
260                                 return;
261                 }
262         }
263
264         /*
265          * Rebuild the Net CPT list again, thereby only including only the
266          * CPTs which the remaining NIs are associated with.
267          */
268         if (net->net_cpts != NULL) {
269                 LIBCFS_FREE(net->net_cpts,
270                         sizeof(*net->net_cpts) * net->net_ncpts);
271                 net->net_cpts = NULL;
272         }
273
274         list_for_each_entry(ni, &net->net_ni_list, ni_netlist) {
275                 rc = lnet_net_append_cpts(ni->ni_cpts, ni->ni_ncpts,
276                                           net);
277                 if (rc != 0) {
278                         CERROR("Out of Memory\n");
279                         /*
280                          * do our best to keep on going. Delete
281                          * the net cpts and set it to NULL. This
282                          * way we can keep on going but less
283                          * efficiently, since memory accesses might be
284                          * accross CPT lines.
285                          */
286                         if (net->net_cpts != NULL) {
287                                 LIBCFS_FREE(net->net_cpts,
288                                                 sizeof(*net->net_cpts) *
289                                                 net->net_ncpts);
290                                 net->net_cpts = NULL;
291                                 net->net_ncpts = LNET_CPT_NUMBER;
292                         }
293                         return;
294                 }
295         }
296 }
297
298 void
299 lnet_ni_free(struct lnet_ni *ni)
300 {
301         int i;
302
303         lnet_net_remove_cpts(ni->ni_cpts, ni->ni_ncpts, ni->ni_net);
304
305         if (ni->ni_refs != NULL)
306                 cfs_percpt_free(ni->ni_refs);
307
308         if (ni->ni_tx_queues != NULL)
309                 cfs_percpt_free(ni->ni_tx_queues);
310
311         if (ni->ni_cpts != NULL)
312                 cfs_expr_list_values_free(ni->ni_cpts, ni->ni_ncpts);
313
314         for (i = 0; i < LNET_INTERFACES_NUM &&
315                     ni->ni_interfaces[i] != NULL; i++) {
316                 LIBCFS_FREE(ni->ni_interfaces[i],
317                             strlen(ni->ni_interfaces[i]) + 1);
318         }
319
320         /* release reference to net namespace */
321         if (ni->ni_net_ns != NULL)
322                 put_net(ni->ni_net_ns);
323
324         LIBCFS_FREE(ni, sizeof(*ni));
325 }
326
327 void
328 lnet_net_free(struct lnet_net *net)
329 {
330         struct list_head *tmp, *tmp2;
331         struct lnet_ni *ni;
332
333         LASSERT(list_empty(&net->net_ni_zombie));
334
335         /*
336          * delete any nis that haven't been added yet. This could happen
337          * if there is a failure on net startup
338          */
339         list_for_each_safe(tmp, tmp2, &net->net_ni_added) {
340                 ni = list_entry(tmp, struct lnet_ni, ni_netlist);
341                 list_del_init(&ni->ni_netlist);
342                 lnet_ni_free(ni);
343         }
344
345         /* delete any nis which have been started. */
346         list_for_each_safe(tmp, tmp2, &net->net_ni_list) {
347                 ni = list_entry(tmp, struct lnet_ni, ni_netlist);
348                 list_del_init(&ni->ni_netlist);
349                 lnet_ni_free(ni);
350         }
351
352         if (net->net_cpts != NULL)
353                 LIBCFS_FREE(net->net_cpts,
354                             sizeof(*net->net_cpts) * net->net_ncpts);
355
356         LIBCFS_FREE(net, sizeof(*net));
357 }
358
359 struct lnet_net *
360 lnet_net_alloc(__u32 net_id, struct list_head *net_list)
361 {
362         struct lnet_net         *net;
363
364         if (!lnet_net_unique(net_id, net_list, NULL)) {
365                 CERROR("Duplicate net %s. Ignore\n",
366                        libcfs_net2str(net_id));
367                 return NULL;
368         }
369
370         LIBCFS_ALLOC(net, sizeof(*net));
371         if (net == NULL) {
372                 CERROR("Out of memory creating network %s\n",
373                        libcfs_net2str(net_id));
374                 return NULL;
375         }
376
377         INIT_LIST_HEAD(&net->net_list);
378         INIT_LIST_HEAD(&net->net_ni_list);
379         INIT_LIST_HEAD(&net->net_ni_added);
380         INIT_LIST_HEAD(&net->net_ni_zombie);
381         spin_lock_init(&net->net_lock);
382
383         net->net_id = net_id;
384         net->net_last_alive = ktime_get_real_seconds();
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 && current->nsproxy->net_ns)
484                 ni->ni_net_ns = get_net(current->nsproxy->net_ns);
485         else
486                 ni->ni_net_ns = get_net(&init_net);
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 static int
906 lnet_str2tbs_sep(struct list_head *tbs, char *str)
907 {
908         LIST_HEAD(pending);
909         char *sep;
910         int nob;
911         int i;
912         struct lnet_text_buf *ltb;
913
914         /* Split 'str' into separate commands */
915         for (;;) {
916                 /* skip leading whitespace */
917                 while (isspace(*str))
918                         str++;
919
920                 /* scan for separator or comment */
921                 for (sep = str; *sep != 0; sep++)
922                         if (lnet_issep(*sep) || *sep == '#')
923                                 break;
924
925                 nob = (int)(sep - str);
926                 if (nob > 0) {
927                         ltb = lnet_new_text_buf(nob);
928                         if (ltb == NULL) {
929                                 lnet_free_text_bufs(&pending);
930                                 return -ENOMEM;
931                         }
932
933                         for (i = 0; i < nob; i++)
934                                 if (isspace(str[i]))
935                                         ltb->ltb_text[i] = ' ';
936                                 else
937                                         ltb->ltb_text[i] = str[i];
938
939                         ltb->ltb_text[nob] = 0;
940
941                         list_add_tail(&ltb->ltb_list, &pending);
942                 }
943
944                 if (*sep == '#') {
945                         /* scan for separator */
946                         do {
947                                 sep++;
948                         } while (*sep != 0 && !lnet_issep(*sep));
949                 }
950
951                 if (*sep == 0)
952                         break;
953
954                 str = sep + 1;
955         }
956
957         list_splice(&pending, tbs->prev);
958         return 0;
959 }
960
961 static int
962 lnet_expand1tb(struct list_head *list,
963                char *str, char *sep1, char *sep2,
964                char *item, int itemlen)
965 {
966         int              len1 = (int)(sep1 - str);
967         int              len2 = strlen(sep2 + 1);
968         struct lnet_text_buf *ltb;
969
970         LASSERT (*sep1 == '[');
971         LASSERT (*sep2 == ']');
972
973         ltb = lnet_new_text_buf(len1 + itemlen + len2);
974         if (ltb == NULL)
975                 return -ENOMEM;
976
977         memcpy(ltb->ltb_text, str, len1);
978         memcpy(&ltb->ltb_text[len1], item, itemlen);
979         memcpy(&ltb->ltb_text[len1+itemlen], sep2 + 1, len2);
980         ltb->ltb_text[len1 + itemlen + len2] = 0;
981
982         list_add_tail(&ltb->ltb_list, list);
983         return 0;
984 }
985
986 static int
987 lnet_str2tbs_expand(struct list_head *tbs, char *str)
988 {
989         char              num[16];
990         LIST_HEAD(pending);
991         char             *sep;
992         char             *sep2;
993         char             *parsed;
994         char             *enditem;
995         int               lo;
996         int               hi;
997         int               stride;
998         int               i;
999         int               nob;
1000         int               scanned;
1001
1002         sep = strchr(str, '[');
1003         if (sep == NULL)                        /* nothing to expand */
1004                 return 0;
1005
1006         sep2 = strchr(sep, ']');
1007         if (sep2 == NULL)
1008                 goto failed;
1009
1010         for (parsed = sep; parsed < sep2; parsed = enditem) {
1011
1012                 enditem = ++parsed;
1013                 while (enditem < sep2 && *enditem != ',')
1014                         enditem++;
1015
1016                 if (enditem == parsed)          /* no empty items */
1017                         goto failed;
1018
1019                 if (sscanf(parsed, "%d-%d/%d%n", &lo, &hi, &stride, &scanned) < 3) {
1020
1021                         if (sscanf(parsed, "%d-%d%n", &lo, &hi, &scanned) < 2) {
1022
1023                                 /* simple string enumeration */
1024                                 if (lnet_expand1tb(&pending, str, sep, sep2,
1025                                                    parsed, (int)(enditem - parsed)) != 0)
1026                                         goto failed;
1027
1028                                 continue;
1029                         }
1030
1031                         stride = 1;
1032                 }
1033
1034                 /* range expansion */
1035
1036                 if (enditem != parsed + scanned) /* no trailing junk */
1037                         goto failed;
1038
1039                 if (hi < 0 || lo < 0 || stride < 0 || hi < lo ||
1040                     (hi - lo) % stride != 0)
1041                         goto failed;
1042
1043                 for (i = lo; i <= hi; i += stride) {
1044
1045                         snprintf(num, sizeof(num), "%d", i);
1046                         nob = strlen(num);
1047                         if (nob + 1 == sizeof(num))
1048                                 goto failed;
1049
1050                         if (lnet_expand1tb(&pending, str, sep, sep2,
1051                                            num, nob) != 0)
1052                                 goto failed;
1053                 }
1054         }
1055
1056         list_splice(&pending, tbs->prev);
1057         return 1;
1058
1059  failed:
1060         lnet_free_text_bufs(&pending);
1061         return -EINVAL;
1062 }
1063
1064 static int
1065 lnet_parse_hops (char *str, unsigned int *hops)
1066 {
1067         int     len = strlen(str);
1068         int     nob = len;
1069
1070         return (sscanf(str, "%u%n", hops, &nob) >= 1 &&
1071                 nob == len &&
1072                 *hops > 0 && *hops < 256);
1073 }
1074
1075 #define LNET_PRIORITY_SEPARATOR (':')
1076
1077 static int
1078 lnet_parse_priority(char *str, unsigned int *priority, char **token)
1079 {
1080         int   nob;
1081         char *sep;
1082         int   len;
1083
1084         sep = strchr(str, LNET_PRIORITY_SEPARATOR);
1085         if (sep == NULL) {
1086                 *priority = 0;
1087                 return 0;
1088         }
1089         len = strlen(sep + 1);
1090
1091         if ((sscanf((sep+1), "%u%n", priority, &nob) < 1) || (len != nob)) {
1092                 /* Update the caller's token pointer so it treats the found
1093                    priority as the token to report in the error message. */
1094                 *token += sep - str + 1;
1095                 return -EINVAL;
1096         }
1097
1098         CDEBUG(D_NET, "gateway %s, priority %d, nob %d\n", str, *priority, nob);
1099
1100         /*
1101          * Change priority separator to \0 to be able to parse NID
1102          */
1103         *sep = '\0';
1104         return 0;
1105 }
1106
1107 static int
1108 lnet_parse_route (char *str, int *im_a_router)
1109 {
1110         /* static scratch buffer OK (single threaded) */
1111         static char cmd[LNET_SINGLE_TEXTBUF_NOB];
1112
1113         LIST_HEAD(nets);
1114         LIST_HEAD(gateways);
1115         struct list_head *tmp1;
1116         struct list_head *tmp2;
1117         __u32             net;
1118         lnet_nid_t        nid;
1119         struct lnet_text_buf  *ltb;
1120         int               rc;
1121         char             *sep;
1122         char             *token = str;
1123         int               ntokens = 0;
1124         int               myrc = -1;
1125         __u32             hops;
1126         int               got_hops = 0;
1127         unsigned int      priority = 0;
1128
1129         /* save a copy of the string for error messages */
1130         strncpy(cmd, str, sizeof(cmd));
1131         cmd[sizeof(cmd) - 1] = '\0';
1132
1133         sep = str;
1134         for (;;) {
1135                 /* scan for token start */
1136                 while (isspace(*sep))
1137                         sep++;
1138                 if (*sep == 0) {
1139                         if (ntokens < (got_hops ? 3 : 2))
1140                                 goto token_error;
1141                         break;
1142                 }
1143
1144                 ntokens++;
1145                 token = sep++;
1146
1147                 /* scan for token end */
1148                 while (*sep != 0 && !isspace(*sep))
1149                         sep++;
1150                 if (*sep != 0)
1151                         *sep++ = 0;
1152
1153                 if (ntokens == 1) {
1154                         tmp2 = &nets;           /* expanding nets */
1155                 } else if (ntokens == 2 &&
1156                            lnet_parse_hops(token, &hops)) {
1157                         got_hops = 1;           /* got a hop count */
1158                         continue;
1159                 } else {
1160                         tmp2 = &gateways;       /* expanding gateways */
1161                 }
1162
1163                 ltb = lnet_new_text_buf(strlen(token));
1164                 if (ltb == NULL)
1165                         goto out;
1166
1167                 strcpy(ltb->ltb_text, token);
1168                 tmp1 = &ltb->ltb_list;
1169                 list_add_tail(tmp1, tmp2);
1170
1171                 while (tmp1 != tmp2) {
1172                         ltb = list_entry(tmp1, struct lnet_text_buf, ltb_list);
1173
1174                         rc = lnet_str2tbs_expand(tmp1->next, ltb->ltb_text);
1175                         if (rc < 0)
1176                                 goto token_error;
1177
1178                         tmp1 = tmp1->next;
1179
1180                         if (rc > 0) {           /* expanded! */
1181                                 list_del(&ltb->ltb_list);
1182                                 lnet_free_text_buf(ltb);
1183                                 continue;
1184                         }
1185
1186                         if (ntokens == 1) {
1187                                 net = libcfs_str2net(ltb->ltb_text);
1188                                 if (net == LNET_NIDNET(LNET_NID_ANY) ||
1189                                     LNET_NETTYP(net) == LOLND)
1190                                         goto token_error;
1191                         } else {
1192                                 rc = lnet_parse_priority(ltb->ltb_text,
1193                                                          &priority, &token);
1194                                 if (rc < 0)
1195                                         goto token_error;
1196
1197                                 nid = libcfs_str2nid(ltb->ltb_text);
1198                                 if (nid == LNET_NID_ANY ||
1199                                     LNET_NETTYP(LNET_NIDNET(nid)) == LOLND)
1200                                         goto token_error;
1201                         }
1202                 }
1203         }
1204
1205         /* if there are no hops set then we want to flag this value as
1206          * unset since hops is an optional parameter */
1207         if (!got_hops)
1208                 hops = LNET_UNDEFINED_HOPS;
1209
1210         LASSERT(!list_empty(&nets));
1211         LASSERT(!list_empty(&gateways));
1212
1213         list_for_each(tmp1, &nets) {
1214                 ltb = list_entry(tmp1, struct lnet_text_buf, ltb_list);
1215                 net = libcfs_str2net(ltb->ltb_text);
1216                 LASSERT (net != LNET_NIDNET(LNET_NID_ANY));
1217
1218                 list_for_each(tmp2, &gateways) {
1219                         ltb = list_entry(tmp2, struct lnet_text_buf, ltb_list);
1220                         nid = libcfs_str2nid(ltb->ltb_text);
1221                         LASSERT(nid != LNET_NID_ANY);
1222
1223                         if (lnet_islocalnid(nid)) {
1224                                 *im_a_router = 1;
1225                                 continue;
1226                         }
1227
1228                         rc = lnet_add_route(net, hops, nid, priority, 1);
1229                         if (rc != 0 && rc != -EEXIST && rc != -EHOSTUNREACH) {
1230                                 CERROR("Can't create route "
1231                                        "to %s via %s\n",
1232                                        libcfs_net2str(net),
1233                                        libcfs_nid2str(nid));
1234                                 goto out;
1235                         }
1236                 }
1237         }
1238
1239         myrc = 0;
1240         goto out;
1241
1242 token_error:
1243         lnet_syntax("routes", cmd, (int)(token - str), strlen(token));
1244 out:
1245         lnet_free_text_bufs(&nets);
1246         lnet_free_text_bufs(&gateways);
1247         return myrc;
1248 }
1249
1250 static int
1251 lnet_parse_route_tbs(struct list_head *tbs, int *im_a_router)
1252 {
1253         struct lnet_text_buf   *ltb;
1254
1255         while (!list_empty(tbs)) {
1256                 ltb = list_entry(tbs->next, struct lnet_text_buf, ltb_list);
1257
1258                 if (lnet_parse_route(ltb->ltb_text, im_a_router) < 0) {
1259                         lnet_free_text_bufs(tbs);
1260                         return -EINVAL;
1261                 }
1262
1263                 list_del(&ltb->ltb_list);
1264                 lnet_free_text_buf(ltb);
1265         }
1266
1267         return 0;
1268 }
1269
1270 int
1271 lnet_parse_routes (char *routes, int *im_a_router)
1272 {
1273         LIST_HEAD(tbs);
1274         int rc = 0;
1275
1276         *im_a_router = 0;
1277
1278         if (lnet_str2tbs_sep(&tbs, routes) < 0) {
1279                 CERROR("Error parsing routes\n");
1280                 rc = -EINVAL;
1281         } else {
1282                 rc = lnet_parse_route_tbs(&tbs, im_a_router);
1283         }
1284
1285         LASSERT (lnet_tbnob == 0);
1286         return rc;
1287 }
1288
1289 static int
1290 lnet_match_network_token(char *token, int len, __u32 *ipaddrs, int nip)
1291 {
1292         LIST_HEAD(list);
1293         int             rc;
1294         int             i;
1295
1296         rc = cfs_ip_addr_parse(token, len, &list);
1297         if (rc != 0)
1298                 return rc;
1299
1300         for (rc = i = 0; !rc && i < nip; i++)
1301                 rc = cfs_ip_addr_match(ipaddrs[i], &list);
1302
1303         cfs_expr_list_free_list(&list);
1304
1305         return rc;
1306 }
1307
1308 static int
1309 lnet_match_network_tokens(char *net_entry, __u32 *ipaddrs, int nip)
1310 {
1311         static char tokens[LNET_SINGLE_TEXTBUF_NOB];
1312
1313         int   matched = 0;
1314         int   ntokens = 0;
1315         int   len;
1316         char *net = NULL;
1317         char *sep;
1318         char *token;
1319         int   rc;
1320
1321         LASSERT(strlen(net_entry) < sizeof(tokens));
1322
1323         /* work on a copy of the string */
1324         strcpy(tokens, net_entry);
1325         sep = tokens;
1326         for (;;) {
1327                 /* scan for token start */
1328                 while (isspace(*sep))
1329                         sep++;
1330                 if (*sep == 0)
1331                         break;
1332
1333                 token = sep++;
1334
1335                 /* scan for token end */
1336                 while (*sep != 0 && !isspace(*sep))
1337                         sep++;
1338                 if (*sep != 0)
1339                         *sep++ = 0;
1340
1341                 if (ntokens++ == 0) {
1342                         net = token;
1343                         continue;
1344                 }
1345
1346                 len = strlen(token);
1347
1348                 rc = lnet_match_network_token(token, len, ipaddrs, nip);
1349                 if (rc < 0) {
1350                         lnet_syntax("ip2nets", net_entry,
1351                                     (int)(token - tokens), len);
1352                         return rc;
1353                 }
1354
1355                 matched |= (rc != 0);
1356         }
1357
1358         if (!matched)
1359                 return 0;
1360
1361         strcpy(net_entry, net);                 /* replace with matched net */
1362         return 1;
1363 }
1364
1365 static __u32
1366 lnet_netspec2net(char *netspec)
1367 {
1368         char   *bracket = strchr(netspec, '(');
1369         __u32   net;
1370
1371         if (bracket != NULL)
1372                 *bracket = 0;
1373
1374         net = libcfs_str2net(netspec);
1375
1376         if (bracket != NULL)
1377                 *bracket = '(';
1378
1379         return net;
1380 }
1381
1382 static int
1383 lnet_splitnets(char *source, struct list_head *nets)
1384 {
1385         int               offset = 0;
1386         int               offset2;
1387         int               len;
1388         struct lnet_text_buf  *tb;
1389         struct lnet_text_buf  *tb2;
1390         struct list_head *t;
1391         char             *sep;
1392         char             *bracket;
1393         __u32             net;
1394
1395         LASSERT(!list_empty(nets));
1396         LASSERT(nets->next == nets->prev);      /* single entry */
1397
1398         tb = list_entry(nets->next, struct lnet_text_buf, ltb_list);
1399
1400         for (;;) {
1401                 sep = strchr(tb->ltb_text, ',');
1402                 bracket = strchr(tb->ltb_text, '(');
1403
1404                 if (sep != NULL &&
1405                     bracket != NULL &&
1406                     bracket < sep) {
1407                         /* netspec lists interfaces... */
1408
1409                         offset2 = offset + (int)(bracket - tb->ltb_text);
1410                         len = strlen(bracket);
1411
1412                         bracket = strchr(bracket + 1, ')');
1413
1414                         if (bracket == NULL ||
1415                             !(bracket[1] == ',' || bracket[1] == 0)) {
1416                                 lnet_syntax("ip2nets", source, offset2, len);
1417                                 return -EINVAL;
1418                         }
1419
1420                         sep = (bracket[1] == 0) ? NULL : bracket + 1;
1421                 }
1422
1423                 if (sep != NULL)
1424                         *sep++ = 0;
1425
1426                 net = lnet_netspec2net(tb->ltb_text);
1427                 if (net == LNET_NIDNET(LNET_NID_ANY)) {
1428                         lnet_syntax("ip2nets", source, offset,
1429                                     strlen(tb->ltb_text));
1430                         return -EINVAL;
1431                 }
1432
1433                 list_for_each(t, nets) {
1434                         tb2 = list_entry(t, struct lnet_text_buf, ltb_list);
1435
1436                         if (tb2 == tb)
1437                                 continue;
1438
1439                         if (net == lnet_netspec2net(tb2->ltb_text)) {
1440                                 /* duplicate network */
1441                                 lnet_syntax("ip2nets", source, offset,
1442                                             strlen(tb->ltb_text));
1443                                 return -EINVAL;
1444                         }
1445                 }
1446
1447                 if (sep == NULL)
1448                         return 0;
1449
1450                 offset += (int)(sep - tb->ltb_text);
1451                 len = strlen(sep);
1452                 tb2 = lnet_new_text_buf(len);
1453                 if (tb2 == NULL)
1454                         return -ENOMEM;
1455
1456                 strncpy(tb2->ltb_text, sep, len);
1457                 tb2->ltb_text[len] = '\0';
1458                 list_add_tail(&tb2->ltb_list, nets);
1459
1460                 tb = tb2;
1461         }
1462 }
1463
1464 static int
1465 lnet_match_networks (char **networksp, char *ip2nets, __u32 *ipaddrs, int nip)
1466 {
1467         static char       networks[LNET_SINGLE_TEXTBUF_NOB];
1468         static char       source[LNET_SINGLE_TEXTBUF_NOB];
1469
1470         LIST_HEAD(raw_entries);
1471         LIST_HEAD(matched_nets);
1472         LIST_HEAD(current_nets);
1473         struct list_head *t;
1474         struct list_head *t2;
1475         struct lnet_text_buf  *tb;
1476         struct lnet_text_buf  *tb2;
1477         __u32             net1;
1478         __u32             net2;
1479         int               len;
1480         int               count;
1481         int               dup;
1482         int               rc;
1483
1484         if (lnet_str2tbs_sep(&raw_entries, ip2nets) < 0) {
1485                 CERROR("Error parsing ip2nets\n");
1486                 LASSERT(lnet_tbnob == 0);
1487                 return -EINVAL;
1488         }
1489
1490         networks[0] = 0;
1491         count = 0;
1492         len = 0;
1493         rc = 0;
1494
1495         while (!list_empty(&raw_entries)) {
1496                 tb = list_entry(raw_entries.next, struct lnet_text_buf,
1497                                 ltb_list);
1498
1499                 strncpy(source, tb->ltb_text, sizeof(source));
1500                 source[sizeof(source) - 1] = '\0';
1501
1502                 /* replace ltb_text with the network(s) add on match */
1503                 rc = lnet_match_network_tokens(tb->ltb_text, ipaddrs, nip);
1504                 if (rc < 0)
1505                         break;
1506
1507                 list_del(&tb->ltb_list);
1508
1509                 if (rc == 0) {                  /* no match */
1510                         lnet_free_text_buf(tb);
1511                         continue;
1512                 }
1513
1514                 /* split into separate networks */
1515                 INIT_LIST_HEAD(&current_nets);
1516                 list_add(&tb->ltb_list, &current_nets);
1517                 rc = lnet_splitnets(source, &current_nets);
1518                 if (rc < 0)
1519                         break;
1520
1521                 dup = 0;
1522                 list_for_each(t, &current_nets) {
1523                         tb = list_entry(t, struct lnet_text_buf, ltb_list);
1524                         net1 = lnet_netspec2net(tb->ltb_text);
1525                         LASSERT(net1 != LNET_NIDNET(LNET_NID_ANY));
1526
1527                         list_for_each(t2, &matched_nets) {
1528                                 tb2 = list_entry(t2, struct lnet_text_buf,
1529                                                  ltb_list);
1530                                 net2 = lnet_netspec2net(tb2->ltb_text);
1531                                 LASSERT(net2 != LNET_NIDNET(LNET_NID_ANY));
1532
1533                                 if (net1 == net2) {
1534                                         dup = 1;
1535                                         break;
1536                                 }
1537                         }
1538
1539                         if (dup)
1540                                 break;
1541                 }
1542
1543                 if (dup) {
1544                         lnet_free_text_bufs(&current_nets);
1545                         continue;
1546                 }
1547
1548                 list_for_each_safe(t, t2, &current_nets) {
1549                         tb = list_entry(t, struct lnet_text_buf, ltb_list);
1550
1551                         list_move_tail(&tb->ltb_list, &matched_nets);
1552
1553                         len += scnprintf(networks + len, sizeof(networks) - len,
1554                                          "%s%s", (len == 0) ? "" : ",",
1555                                          tb->ltb_text);
1556
1557                         if (len >= sizeof(networks)) {
1558                                 CERROR("Too many matched networks\n");
1559                                 rc = -E2BIG;
1560                                 goto out;
1561                         }
1562                 }
1563
1564                 count++;
1565         }
1566
1567  out:
1568         lnet_free_text_bufs(&raw_entries);
1569         lnet_free_text_bufs(&matched_nets);
1570         lnet_free_text_bufs(&current_nets);
1571         LASSERT(lnet_tbnob == 0);
1572
1573         if (rc < 0)
1574                 return rc;
1575
1576         *networksp = networks;
1577         return count;
1578 }
1579 /*
1580  * kernel 5.3: commit ef11db3310e272d3d8dbe8739e0770820dd20e52
1581  * added in_dev_for_each_ifa_rtnl and in_dev_for_each_ifa_rcu
1582  * and removed for_ifa and endfor_ifa.
1583  * Use the _rntl variant as the current locking is rtnl.
1584  */
1585 #ifdef in_dev_for_each_ifa_rtnl
1586 #define DECLARE_CONST_IN_IFADDR(ifa)            const struct in_ifaddr *ifa
1587 #define endfor_ifa(in_dev)
1588 #else
1589 #define DECLARE_CONST_IN_IFADDR(ifa)
1590 #define in_dev_for_each_ifa_rtnl(ifa, in_dev)   for_ifa((in_dev))
1591 #endif
1592
1593 int lnet_inet_enumerate(struct lnet_inetdev **dev_list, struct net *ns)
1594 {
1595         struct lnet_inetdev *ifaces = NULL;
1596         struct net_device *dev;
1597         int nalloc = 0;
1598         int nip = 0;
1599         DECLARE_CONST_IN_IFADDR(ifa);
1600
1601         rtnl_lock();
1602         for_each_netdev(ns, dev) {
1603                 int flags = dev_get_flags(dev);
1604                 struct in_device *in_dev;
1605                 int node_id;
1606                 int cpt;
1607
1608                 if (flags & IFF_LOOPBACK) /* skip the loopback IF */
1609                         continue;
1610
1611                 if (!(flags & IFF_UP)) {
1612                         CWARN("lnet: Ignoring interface %s: it's down\n",
1613                               dev->name);
1614                         continue;
1615                 }
1616
1617                 in_dev = __in_dev_get_rtnl(dev);
1618                 if (!in_dev) {
1619                         CWARN("lnet: Interface %s has no IPv4 status.\n",
1620                               dev->name);
1621                         continue;
1622                 }
1623
1624                 node_id = dev_to_node(&dev->dev);
1625                 cpt = cfs_cpt_of_node(lnet_cpt_table(), node_id);
1626
1627                 in_dev_for_each_ifa_rtnl(ifa, in_dev) {
1628                         if (nip >= nalloc) {
1629                                 struct lnet_inetdev *tmp;
1630
1631                                 nalloc += LNET_INTERFACES_NUM;
1632                                 tmp = krealloc(ifaces, nalloc * sizeof(*tmp),
1633                                                GFP_KERNEL);
1634                                 if (!tmp) {
1635                                         kfree(ifaces);
1636                                         ifaces = NULL;
1637                                         nip = -ENOMEM;
1638                                         goto unlock_rtnl;
1639                                 }
1640                                 ifaces = tmp;
1641                         }
1642
1643                         ifaces[nip].li_cpt = cpt;
1644                         ifaces[nip].li_flags = flags;
1645                         ifaces[nip].li_ipaddr = ntohl(ifa->ifa_local);
1646                         ifaces[nip].li_netmask = ntohl(ifa->ifa_mask);
1647                         strlcpy(ifaces[nip].li_name, ifa->ifa_label,
1648                                 sizeof(ifaces[nip].li_name));
1649                         nip++;
1650                 }
1651                 endfor_ifa(in_dev);
1652         }
1653 unlock_rtnl:
1654         rtnl_unlock();
1655
1656         if (nip == 0) {
1657                 CERROR("lnet: Can't find any usable interfaces, rc = -ENOENT\n");
1658                 nip = -ENOENT;
1659         }
1660
1661         *dev_list = ifaces;
1662         return nip;
1663 }
1664 EXPORT_SYMBOL(lnet_inet_enumerate);
1665
1666 int
1667 lnet_parse_ip2nets (char **networksp, char *ip2nets)
1668 {
1669         struct lnet_inetdev *ifaces = NULL;
1670         __u32     *ipaddrs = NULL;
1671         int nip;
1672         int        rc;
1673         int i;
1674
1675         if (current->nsproxy && current->nsproxy->net_ns)
1676                 nip = lnet_inet_enumerate(&ifaces, current->nsproxy->net_ns);
1677         else
1678                 nip = lnet_inet_enumerate(&ifaces, &init_net);
1679         if (nip < 0) {
1680                 if (nip != -ENOENT) {
1681                         LCONSOLE_ERROR_MSG(0x117,
1682                                            "Error %d enumerating local IP interfaces for ip2nets to match\n",
1683                                            nip);
1684                 } else {
1685                         LCONSOLE_ERROR_MSG(0x118,
1686                                            "No local IP interfaces for ip2nets to match\n");
1687                 }
1688                 return nip;
1689         }
1690
1691         LIBCFS_ALLOC(ipaddrs, nip * sizeof(*ipaddrs));
1692         if (!ipaddrs) {
1693                 rc = -ENOMEM;
1694                 CERROR("lnet: Can't allocate ipaddrs[%d], rc = %d\n",
1695                        nip, rc);
1696                 goto out_free_addrs;
1697         }
1698
1699         for (i = 0; i < nip; i++)
1700                 ipaddrs[i] = ifaces[i].li_ipaddr;
1701
1702         rc = lnet_match_networks(networksp, ip2nets, ipaddrs, nip);
1703         if (rc < 0) {
1704                 LCONSOLE_ERROR_MSG(0x119, "Error %d parsing ip2nets\n", rc);
1705         } else if (rc == 0) {
1706                 LCONSOLE_ERROR_MSG(0x11a, "ip2nets does not match "
1707                                    "any local IP interfaces\n");
1708                 rc = -ENOENT;
1709         }
1710         LIBCFS_FREE(ipaddrs, nip * sizeof(*ipaddrs));
1711 out_free_addrs:
1712         kfree(ifaces);
1713         return rc > 0 ? 0 : rc;
1714 }