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