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