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