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