Whamcloud - gitweb
New release 2.15.64
[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("Error parsing '%s=\"%s\"'\n", name, str);
45         LCONSOLE_ERROR("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("%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("Can't parse networks: string too long\n");
566                 return -EINVAL;
567         }
568
569         tokensize = strlen(networks) + 1;
570
571         LIBCFS_ALLOC(tokens, tokensize);
572         if (tokens == NULL) {
573                 CERROR("Can't allocate net tokens\n");
574                 return -ENOMEM;
575         }
576
577         memcpy(tokens, networks, tokensize);
578         str = tokens;
579
580         /*
581          * Main parser loop.
582          *
583          * NB we don't check interface conflicts here; it's the LNDs
584          * responsibility (if it cares at all)
585          */
586         do {
587                 char *nistr;
588                 char *elstr;
589                 char *name;
590                 int rc;
591
592                 /*
593                  * Parse a network string into its components.
594                  *
595                  * <name>{"("...")"}{"["<el>"]"}
596                  */
597
598                 /* Network name (mandatory) */
599                 while (isspace(*str))
600                         *str++ = '\0';
601                 if (!*str)
602                         break;
603                 name = str;
604                 str += strcspn(str, SPACESTR ":()[],");
605                 while (isspace(*str))
606                         *str++ = '\0';
607
608                 /* Interface list (optional) */
609                 if (*str == '(') {
610                         *str++ = '\0';
611                         nistr = str;
612                         str += strcspn(str, ")");
613                         if (*str != ')') {
614                                 str = nistr;
615                                 goto failed_syntax;
616                         }
617                         do {
618                                 *str++ = '\0';
619                         } while (isspace(*str));
620                 } else {
621                         nistr = NULL;
622                 }
623
624                 /* CPT expression (optional) */
625                 if (*str == '[') {
626                         elstr = str;
627                         str += strcspn(str, "]");
628                         if (*str != ']') {
629                                 str = elstr;
630                                 goto failed_syntax;
631                         }
632                         rc = cfs_expr_list_parse(elstr, str - elstr + 1,
633                                                 0, LNET_CPT_NUMBER - 1,
634                                                 &net_el);
635                         if (rc != 0) {
636                                 str = elstr;
637                                 goto failed_syntax;
638                         }
639                         *elstr = '\0';
640                         do {
641                                 *str++ = '\0';
642                         } while (isspace(*str));
643                 }
644
645                 /* Bad delimiters */
646                 if (*str && (strchr(DELIMITERS, *str) != NULL))
647                         goto failed_syntax;
648
649                 /* go to the next net if it exits */
650                 str += strcspn(str, ",");
651                 if (*str == ',')
652                         *str++ = '\0';
653
654                 /*
655                  * At this point the name is properly terminated.
656                  */
657                 net_id = libcfs_str2net(name);
658                 if (net_id == LNET_NET_ANY) {
659                         LCONSOLE_ERROR("Unrecognised network type\n");
660                         str = name;
661                         goto failed_syntax;
662                 }
663
664                 if (LNET_NETTYP(net_id) == LOLND) {
665                         /* Loopback is implicit, and there can be only one. */
666                         if (net_el) {
667                                 cfs_expr_list_free(net_el);
668                                 net_el = NULL;
669                         }
670                         /* Should we error out instead? */
671                         continue;
672                 }
673
674                 /*
675                  * All network paramaters are now known.
676                  */
677                 nnets++;
678
679                 /* always allocate a net, since we will eventually add an
680                  * interface to it, or we will fail, in which case we'll
681                  * just delete it */
682                 net = lnet_net_alloc(net_id, netlist);
683                 if (IS_ERR_OR_NULL(net))
684                         goto failed;
685
686                 if (!nistr) {
687                         /*
688                          * No interface list was specified, allocate a
689                          * ni using the defaults.
690                          */
691                         ni = lnet_ni_alloc(net, net_el, NULL);
692                         if (IS_ERR_OR_NULL(ni))
693                                 goto failed;
694
695                         if (!nistr) {
696                                 if (net_el) {
697                                         cfs_expr_list_free(net_el);
698                                         net_el = NULL;
699                                 }
700                                 continue;
701                         }
702                 }
703
704                 do {
705                         elstr = NULL;
706
707                         /* Interface name (mandatory) */
708                         while (isspace(*nistr))
709                                 *nistr++ = '\0';
710                         name = nistr;
711                         nistr += strcspn(nistr, SPACESTR "[],");
712                         while (isspace(*nistr))
713                                 *nistr++ = '\0';
714
715                         /* CPT expression (optional) */
716                         if (*nistr == '[') {
717                                 elstr = nistr;
718                                 nistr += strcspn(nistr, "]");
719                                 if (*nistr != ']') {
720                                         str = elstr;
721                                         goto failed_syntax;
722                                 }
723                                 rc = cfs_expr_list_parse(elstr,
724                                                         nistr - elstr + 1,
725                                                         0, LNET_CPT_NUMBER - 1,
726                                                         &ni_el);
727                                 if (rc != 0) {
728                                         str = elstr;
729                                         goto failed_syntax;
730                                 }
731                                 *elstr = '\0';
732                                 do {
733                                         *nistr++ = '\0';
734                                 } while (isspace(*nistr));
735                         } else {
736                                 ni_el = net_el;
737                         }
738
739                         /*
740                          * End of single interface specificaton,
741                          * advance to the start of the next one, if
742                          * any.
743                          */
744                         if (*nistr == ',') {
745                                 do {
746                                         *nistr++ = '\0';
747                                 } while (isspace(*nistr));
748                                 if (!*nistr) {
749                                         str = nistr;
750                                         goto failed_syntax;
751                                 }
752                         } else if (*nistr) {
753                                 str = nistr;
754                                 goto failed_syntax;
755                         }
756
757                         /*
758                          * At this point the name is properly terminated.
759                          */
760                         if (!*name) {
761                                 str = name;
762                                 goto failed_syntax;
763                         }
764
765                         ni = lnet_ni_alloc(net, ni_el, name);
766                         if (IS_ERR_OR_NULL(ni))
767                                 goto failed;
768
769                         if (ni_el) {
770                                 if (ni_el != net_el) {
771                                         cfs_expr_list_free(ni_el);
772                                         ni_el = NULL;
773                                 }
774                         }
775                 } while (*nistr);
776
777                 if (net_el) {
778                         cfs_expr_list_free(net_el);
779                         net_el = NULL;
780                 }
781         } while (*str);
782
783         LIBCFS_FREE(tokens, tokensize);
784         return nnets;
785
786  failed_syntax:
787         lnet_syntax("networks", networks, (int)(str - tokens), strlen(str));
788  failed:
789         /* free the net list and all the nis on each net */
790         while ((net = list_first_entry_or_null(netlist,
791                                                struct lnet_net,
792                                                net_list)) != NULL) {
793                 list_del_init(&net->net_list);
794                 lnet_net_free(net);
795         }
796
797         if (ni_el && ni_el != net_el)
798                 cfs_expr_list_free(ni_el);
799         if (net_el)
800                 cfs_expr_list_free(net_el);
801
802         LIBCFS_FREE(tokens, tokensize);
803
804         return -EINVAL;
805 }
806
807 static struct lnet_text_buf *lnet_new_text_buf(int str_len)
808 {
809         struct lnet_text_buf *ltb;
810         int nob;
811
812         /* NB allocate space for the terminating 0 */
813         nob = offsetof(struct lnet_text_buf, ltb_text[str_len + 1]);
814         if (nob > LNET_SINGLE_TEXTBUF_NOB) {
815                 /* _way_ conservative for "route net gateway..." */
816                 CERROR("text buffer too big\n");
817                 return NULL;
818         }
819
820         if (lnet_tbnob + nob > LNET_MAX_TEXTBUF_NOB) {
821                 CERROR("Too many text buffers\n");
822                 return NULL;
823         }
824
825         LIBCFS_ALLOC(ltb, nob);
826         if (ltb == NULL)
827                 return NULL;
828
829         ltb->ltb_size = nob;
830         ltb->ltb_text[0] = 0;
831         lnet_tbnob += nob;
832         return ltb;
833 }
834
835 static void
836 lnet_free_text_buf(struct lnet_text_buf *ltb)
837 {
838         lnet_tbnob -= ltb->ltb_size;
839         LIBCFS_FREE(ltb, ltb->ltb_size);
840 }
841
842 static void
843 lnet_free_text_bufs(struct list_head *tbs)
844 {
845         struct lnet_text_buf  *ltb;
846
847         while ((ltb = list_first_entry_or_null(tbs, struct lnet_text_buf,
848                                                ltb_list)) != NULL) {
849                 list_del(&ltb->ltb_list);
850                 lnet_free_text_buf(ltb);
851         }
852 }
853
854 static int
855 lnet_str2tbs_sep(struct list_head *tbs, const char *str)
856 {
857         LIST_HEAD(pending);
858         const char *sep;
859         int nob;
860         int i;
861         struct lnet_text_buf *ltb;
862
863         /* Split 'str' into separate commands */
864         for (;;) {
865                 /* skip leading whitespace */
866                 while (isspace(*str))
867                         str++;
868
869                 /* scan for separator or comment */
870                 for (sep = str; *sep != 0; sep++)
871                         if (lnet_issep(*sep) || *sep == '#')
872                                 break;
873
874                 nob = (int)(sep - str);
875                 if (nob > 0) {
876                         ltb = lnet_new_text_buf(nob);
877                         if (ltb == NULL) {
878                                 lnet_free_text_bufs(&pending);
879                                 return -ENOMEM;
880                         }
881
882                         for (i = 0; i < nob; i++)
883                                 if (isspace(str[i]))
884                                         ltb->ltb_text[i] = ' ';
885                                 else
886                                         ltb->ltb_text[i] = str[i];
887
888                         ltb->ltb_text[nob] = 0;
889
890                         list_add_tail(&ltb->ltb_list, &pending);
891                 }
892
893                 if (*sep == '#') {
894                         /* scan for separator */
895                         do {
896                                 sep++;
897                         } while (*sep != 0 && !lnet_issep(*sep));
898                 }
899
900                 if (*sep == 0)
901                         break;
902
903                 str = sep + 1;
904         }
905
906         list_splice(&pending, tbs->prev);
907         return 0;
908 }
909
910 static int
911 lnet_expand1tb(struct list_head *list,
912                char *str, char *sep1, char *sep2,
913                char *item, int itemlen)
914 {
915         int              len1 = (int)(sep1 - str);
916         int              len2 = strlen(sep2 + 1);
917         struct lnet_text_buf *ltb;
918
919         LASSERT (*sep1 == '[');
920         LASSERT (*sep2 == ']');
921
922         ltb = lnet_new_text_buf(len1 + itemlen + len2);
923         if (ltb == NULL)
924                 return -ENOMEM;
925
926         memcpy(ltb->ltb_text, str, len1);
927         memcpy(&ltb->ltb_text[len1], item, itemlen);
928         memcpy(&ltb->ltb_text[len1+itemlen], sep2 + 1, len2);
929         ltb->ltb_text[len1 + itemlen + len2] = 0;
930
931         list_add_tail(&ltb->ltb_list, list);
932         return 0;
933 }
934
935 static int
936 lnet_str2tbs_expand(struct list_head *tbs, char *str)
937 {
938         char              num[16];
939         LIST_HEAD(pending);
940         char             *sep;
941         char             *sep2;
942         char             *parsed;
943         char             *enditem;
944         int               lo;
945         int               hi;
946         int               stride;
947         int               i;
948         int               nob;
949         int               scanned;
950
951         sep = strchr(str, '[');
952         if (sep == NULL)                        /* nothing to expand */
953                 return 0;
954
955         sep2 = strchr(sep, ']');
956         if (sep2 == NULL)
957                 goto failed;
958
959         for (parsed = sep; parsed < sep2; parsed = enditem) {
960
961                 enditem = ++parsed;
962                 while (enditem < sep2 && *enditem != ',')
963                         enditem++;
964
965                 if (enditem == parsed)          /* no empty items */
966                         goto failed;
967
968                 if (sscanf(parsed, "%d-%d/%d%n", &lo, &hi, &stride, &scanned) < 3) {
969
970                         if (sscanf(parsed, "%d-%d%n", &lo, &hi, &scanned) < 2) {
971
972                                 /* simple string enumeration */
973                                 if (lnet_expand1tb(&pending, str, sep, sep2,
974                                                    parsed, (int)(enditem - parsed)) != 0)
975                                         goto failed;
976
977                                 continue;
978                         }
979
980                         stride = 1;
981                 }
982
983                 /* range expansion */
984
985                 if (enditem != parsed + scanned) /* no trailing junk */
986                         goto failed;
987
988                 if (hi < 0 || lo < 0 || stride < 0 || hi < lo ||
989                     (hi - lo) % stride != 0)
990                         goto failed;
991
992                 for (i = lo; i <= hi; i += stride) {
993
994                         snprintf(num, sizeof(num), "%d", i);
995                         nob = strlen(num);
996                         if (nob + 1 == sizeof(num))
997                                 goto failed;
998
999                         if (lnet_expand1tb(&pending, str, sep, sep2,
1000                                            num, nob) != 0)
1001                                 goto failed;
1002                 }
1003         }
1004
1005         list_splice(&pending, tbs->prev);
1006         return 1;
1007
1008  failed:
1009         lnet_free_text_bufs(&pending);
1010         return -EINVAL;
1011 }
1012
1013 static int
1014 lnet_parse_hops (char *str, unsigned int *hops)
1015 {
1016         int     len = strlen(str);
1017         int     nob = len;
1018
1019         return (sscanf(str, "%u%n", hops, &nob) >= 1 &&
1020                 nob == len &&
1021                 *hops > 0 && *hops < 256);
1022 }
1023
1024 #define LNET_PRIORITY_SEPARATOR (':')
1025
1026 static int
1027 lnet_parse_priority(char *str, unsigned int *priority, char **token)
1028 {
1029         int   nob;
1030         char *sep;
1031         int   len;
1032
1033         sep = strchr(str, LNET_PRIORITY_SEPARATOR);
1034         if (sep == NULL) {
1035                 *priority = 0;
1036                 return 0;
1037         }
1038         len = strlen(sep + 1);
1039
1040         if ((sscanf((sep+1), "%u%n", priority, &nob) < 1) || (len != nob)) {
1041                 /* Update the caller's token pointer so it treats the found
1042                    priority as the token to report in the error message. */
1043                 *token += sep - str + 1;
1044                 return -EINVAL;
1045         }
1046
1047         CDEBUG(D_NET, "gateway %s, priority %d, nob %d\n", str, *priority, nob);
1048
1049         /*
1050          * Change priority separator to \0 to be able to parse NID
1051          */
1052         *sep = '\0';
1053         return 0;
1054 }
1055
1056 static int
1057 lnet_parse_route(char *str, int *im_a_router)
1058 {
1059         /* static scratch buffer OK (single threaded) */
1060         static char cmd[LNET_SINGLE_TEXTBUF_NOB];
1061
1062         LIST_HEAD(nets);
1063         LIST_HEAD(gateways);
1064         struct list_head *tmp1;
1065         struct list_head *tmp2;
1066         __u32 net;
1067         struct lnet_nid nid;
1068         struct lnet_text_buf *ltb = NULL;
1069         struct lnet_text_buf *ltb1, *ltb2;
1070         int rc;
1071         char *sep;
1072         char *token = str;
1073         int ntokens = 0;
1074         int myrc = -1;
1075         __u32 hops;
1076         int got_hops = 0;
1077         unsigned int priority = 0;
1078
1079         /* save a copy of the string for error messages */
1080         strncpy(cmd, str, sizeof(cmd));
1081         cmd[sizeof(cmd) - 1] = '\0';
1082
1083         sep = str;
1084         for (;;) {
1085                 /* scan for token start */
1086                 while (isspace(*sep))
1087                         sep++;
1088                 if (*sep == 0) {
1089                         if (ntokens < (got_hops ? 3 : 2))
1090                                 goto token_error;
1091                         break;
1092                 }
1093
1094                 ntokens++;
1095                 token = sep++;
1096
1097                 /* scan for token end */
1098                 while (*sep != 0 && !isspace(*sep))
1099                         sep++;
1100                 if (*sep != 0)
1101                         *sep++ = 0;
1102
1103                 if (ntokens == 1) {
1104                         tmp2 = &nets;           /* expanding nets */
1105                 } else if (ntokens == 2 &&
1106                            lnet_parse_hops(token, &hops)) {
1107                         got_hops = 1;           /* got a hop count */
1108                         continue;
1109                 } else {
1110                         tmp2 = &gateways;       /* expanding gateways */
1111                 }
1112
1113                 ltb = lnet_new_text_buf(strlen(token));
1114                 if (ltb == NULL)
1115                         goto out;
1116
1117                 strcpy(ltb->ltb_text, token);
1118                 tmp1 = &ltb->ltb_list;
1119                 list_add_tail(tmp1, tmp2);
1120
1121                 while (tmp1 != tmp2) {
1122                         ltb = list_entry(tmp1, struct lnet_text_buf, ltb_list);
1123
1124                         rc = lnet_str2tbs_expand(tmp1->next, ltb->ltb_text);
1125                         if (rc < 0)
1126                                 goto token_error;
1127
1128                         tmp1 = tmp1->next;
1129
1130                         if (rc > 0) {           /* expanded! */
1131                                 list_del(&ltb->ltb_list);
1132                                 lnet_free_text_buf(ltb);
1133                                 continue;
1134                         }
1135
1136                         if (ntokens == 1) {
1137                                 net = libcfs_str2net(ltb->ltb_text);
1138                                 if (net == LNET_NET_ANY ||
1139                                     LNET_NETTYP(net) == LOLND)
1140                                         goto token_error;
1141                         } else {
1142                                 rc = lnet_parse_priority(ltb->ltb_text,
1143                                                          &priority, &token);
1144                                 if (rc < 0)
1145                                         goto token_error;
1146
1147                                 if (libcfs_strnid(&nid, ltb->ltb_text) != 0 ||
1148                                     nid_is_lo0(&nid))
1149                                         goto token_error;
1150                         }
1151                 }
1152         }
1153
1154         /* if there are no hops set then we want to flag this value as
1155          * unset since hops is an optional parameter */
1156         if (!got_hops)
1157                 hops = LNET_UNDEFINED_HOPS;
1158
1159         LASSERT(!list_empty(&nets));
1160         LASSERT(!list_empty(&gateways));
1161
1162         list_for_each_entry(ltb1, &nets, ltb_list) {
1163                 net = libcfs_str2net(ltb1->ltb_text);
1164                 LASSERT(net != LNET_NET_ANY);
1165
1166                 list_for_each_entry(ltb2, &gateways, ltb_list) {
1167                         LASSERT(libcfs_strnid(&nid, ltb2->ltb_text) == 0);
1168
1169                         if (lnet_islocalnid(&nid)) {
1170                                 *im_a_router = 1;
1171                                 continue;
1172                         }
1173
1174                         rc = lnet_add_route(net, hops, &nid, priority, 1);
1175                         if (rc != 0 && rc != -EEXIST && rc != -EHOSTUNREACH) {
1176                                 CERROR("Can't create route "
1177                                        "to %s via %s\n",
1178                                        libcfs_net2str(net),
1179                                        libcfs_nidstr(&nid));
1180                                 goto out;
1181                         }
1182                 }
1183         }
1184
1185         myrc = 0;
1186         goto out;
1187
1188 token_error:
1189         lnet_syntax("routes", cmd, (int)(token - str), strlen(token));
1190 out:
1191         lnet_free_text_bufs(&nets);
1192         lnet_free_text_bufs(&gateways);
1193         return myrc;
1194 }
1195
1196 static int
1197 lnet_parse_route_tbs(struct list_head *tbs, int *im_a_router)
1198 {
1199         struct lnet_text_buf *ltb;
1200
1201         while ((ltb = list_first_entry_or_null(tbs, struct lnet_text_buf,
1202                                                ltb_list)) != NULL) {
1203                 if (lnet_parse_route(ltb->ltb_text, im_a_router) < 0) {
1204                         lnet_free_text_bufs(tbs);
1205                         return -EINVAL;
1206                 }
1207
1208                 list_del(&ltb->ltb_list);
1209                 lnet_free_text_buf(ltb);
1210         }
1211
1212         return 0;
1213 }
1214
1215 int
1216 lnet_parse_routes(const char *routes, int *im_a_router)
1217 {
1218         LIST_HEAD(tbs);
1219         int rc = 0;
1220
1221         *im_a_router = 0;
1222
1223         if (lnet_str2tbs_sep(&tbs, routes) < 0) {
1224                 CERROR("Error parsing routes\n");
1225                 rc = -EINVAL;
1226         } else {
1227                 rc = lnet_parse_route_tbs(&tbs, im_a_router);
1228         }
1229
1230         LASSERT (lnet_tbnob == 0);
1231         return rc;
1232 }
1233
1234 static int
1235 lnet_match_network_token(char *token, __u32 *ipaddrs, int nip)
1236 {
1237         LIST_HEAD(list);
1238         int             rc;
1239         int             i;
1240
1241         rc = cfs_ip_addr_parse(token, 0, &list);
1242         if (rc != 0)
1243                 return rc;
1244
1245         for (rc = i = 0; !rc && i < nip; i++)
1246                 rc = cfs_ip_addr_match(ipaddrs[i], &list);
1247
1248         cfs_expr_list_free_list(&list);
1249
1250         return rc;
1251 }
1252
1253 static int
1254 lnet_match_network_tokens(char *net_entry, __u32 *ipaddrs, int nip)
1255 {
1256         static char tokens[LNET_SINGLE_TEXTBUF_NOB];
1257
1258         int   matched = 0;
1259         int   ntokens = 0;
1260         char *net = NULL;
1261         char *sep;
1262         char *token;
1263         int   rc;
1264
1265         LASSERT(strlen(net_entry) < sizeof(tokens));
1266
1267         /* work on a copy of the string */
1268         strcpy(tokens, net_entry);
1269         sep = tokens;
1270         while (sep) {
1271                 /* scan for token start */
1272                 sep = skip_spaces(sep);
1273                 if (*sep == 0)
1274                         break;
1275
1276                 token = strsep(&sep, " \t\n\r\v\f");
1277
1278                 if (ntokens++ == 0) {
1279                         net = token;
1280                         continue;
1281                 }
1282
1283                 rc = lnet_match_network_token(token, ipaddrs, nip);
1284                 if (rc < 0) {
1285                         lnet_syntax("ip2nets", net_entry,
1286                                     (int)(token - tokens), strlen(token));
1287                         return rc;
1288                 }
1289
1290                 matched |= (rc != 0);
1291         }
1292
1293         if (!matched)
1294                 return 0;
1295
1296         strcpy(net_entry, net);                 /* replace with matched net */
1297         return 1;
1298 }
1299
1300 static __u32
1301 lnet_netspec2net(char *netspec)
1302 {
1303         char   *bracket = strchr(netspec, '(');
1304         __u32   net;
1305
1306         if (bracket != NULL)
1307                 *bracket = 0;
1308
1309         net = libcfs_str2net(netspec);
1310
1311         if (bracket != NULL)
1312                 *bracket = '(';
1313
1314         return net;
1315 }
1316
1317 static int
1318 lnet_splitnets(char *source, struct list_head *nets)
1319 {
1320         int               offset = 0;
1321         int               offset2;
1322         int               len;
1323         struct lnet_text_buf  *tb;
1324         struct lnet_text_buf  *tb2;
1325         char             *sep;
1326         char             *bracket;
1327         __u32             net;
1328
1329         LASSERT(!list_empty(nets));
1330         LASSERT(nets->next == nets->prev);      /* single entry */
1331
1332         tb = list_first_entry(nets, struct lnet_text_buf, ltb_list);
1333
1334         for (;;) {
1335                 sep = strchr(tb->ltb_text, ',');
1336                 bracket = strchr(tb->ltb_text, '(');
1337
1338                 if (sep != NULL &&
1339                     bracket != NULL &&
1340                     bracket < sep) {
1341                         /* netspec lists interfaces... */
1342
1343                         offset2 = offset + (int)(bracket - tb->ltb_text);
1344                         len = strlen(bracket);
1345
1346                         bracket = strchr(bracket + 1, ')');
1347
1348                         if (bracket == NULL ||
1349                             !(bracket[1] == ',' || bracket[1] == 0)) {
1350                                 lnet_syntax("ip2nets", source, offset2, len);
1351                                 return -EINVAL;
1352                         }
1353
1354                         sep = (bracket[1] == 0) ? NULL : bracket + 1;
1355                 }
1356
1357                 if (sep != NULL)
1358                         *sep++ = 0;
1359
1360                 net = lnet_netspec2net(tb->ltb_text);
1361                 if (net == LNET_NET_ANY) {
1362                         lnet_syntax("ip2nets", source, offset,
1363                                     strlen(tb->ltb_text));
1364                         return -EINVAL;
1365                 }
1366
1367                 list_for_each_entry(tb2, nets, ltb_list) {
1368                         if (tb2 == tb)
1369                                 continue;
1370
1371                         if (net == lnet_netspec2net(tb2->ltb_text)) {
1372                                 /* duplicate network */
1373                                 lnet_syntax("ip2nets", source, offset,
1374                                             strlen(tb->ltb_text));
1375                                 return -EINVAL;
1376                         }
1377                 }
1378
1379                 if (sep == NULL)
1380                         return 0;
1381
1382                 offset += (int)(sep - tb->ltb_text);
1383                 len = strlen(sep);
1384                 tb2 = lnet_new_text_buf(len);
1385                 if (tb2 == NULL)
1386                         return -ENOMEM;
1387
1388                 strncpy(tb2->ltb_text, sep, len);
1389                 tb2->ltb_text[len] = '\0';
1390                 list_add_tail(&tb2->ltb_list, nets);
1391
1392                 tb = tb2;
1393         }
1394 }
1395
1396 static int
1397 lnet_match_networks(const char **networksp, const char *ip2nets,
1398                     __u32 *ipaddrs, int nip)
1399 {
1400         static char       networks[LNET_SINGLE_TEXTBUF_NOB];
1401         static char       source[LNET_SINGLE_TEXTBUF_NOB];
1402
1403         LIST_HEAD(raw_entries);
1404         LIST_HEAD(matched_nets);
1405         LIST_HEAD(current_nets);
1406         struct list_head *t;
1407         struct list_head *t2;
1408         struct lnet_text_buf  *tb;
1409         int               len;
1410         int               count;
1411         int               rc;
1412
1413         if (lnet_str2tbs_sep(&raw_entries, ip2nets) < 0) {
1414                 CERROR("Error parsing ip2nets\n");
1415                 LASSERT(lnet_tbnob == 0);
1416                 return -EINVAL;
1417         }
1418
1419         networks[0] = 0;
1420         count = 0;
1421         len = 0;
1422         rc = 0;
1423
1424         while ((tb = list_first_entry_or_null(&raw_entries,
1425                                               struct lnet_text_buf,
1426                                               ltb_list)) != NULL) {
1427                 strncpy(source, tb->ltb_text, sizeof(source));
1428                 source[sizeof(source) - 1] = '\0';
1429
1430                 /* replace ltb_text with the network(s) add on match */
1431                 rc = lnet_match_network_tokens(tb->ltb_text, ipaddrs, nip);
1432                 if (rc < 0)
1433                         break;
1434
1435                 list_del(&tb->ltb_list);
1436
1437                 if (rc == 0) {                  /* no match */
1438                         lnet_free_text_buf(tb);
1439                         continue;
1440                 }
1441
1442                 /* split into separate networks */
1443                 INIT_LIST_HEAD(&current_nets);
1444                 list_add(&tb->ltb_list, &current_nets);
1445                 rc = lnet_splitnets(source, &current_nets);
1446                 if (rc < 0)
1447                         break;
1448
1449                 list_for_each_safe(t, t2, &current_nets) {
1450                         tb = list_entry(t, struct lnet_text_buf, ltb_list);
1451
1452                         list_move_tail(&tb->ltb_list, &matched_nets);
1453
1454                         len += scnprintf(networks + len, sizeof(networks) - len,
1455                                          "%s%s", (len == 0) ? "" : ",",
1456                                          tb->ltb_text);
1457
1458                         if (len >= sizeof(networks)) {
1459                                 CERROR("Too many matched networks\n");
1460                                 rc = -E2BIG;
1461                                 goto out;
1462                         }
1463                 }
1464
1465                 count++;
1466         }
1467
1468  out:
1469         lnet_free_text_bufs(&raw_entries);
1470         lnet_free_text_bufs(&matched_nets);
1471         lnet_free_text_bufs(&current_nets);
1472         LASSERT(lnet_tbnob == 0);
1473
1474         if (rc < 0)
1475                 return rc;
1476
1477         *networksp = networks;
1478         return count;
1479 }
1480
1481 __u32 lnet_set_link_fatal_state(struct lnet_ni *ni, unsigned int link_state)
1482 {
1483         CDEBUG(D_NET, "%s: set link fatal state to %u\n",
1484                libcfs_nidstr(&ni->ni_nid), link_state);
1485         return atomic_xchg(&ni->ni_fatal_error_on, link_state);
1486 }
1487 EXPORT_SYMBOL(lnet_set_link_fatal_state);
1488
1489 int lnet_get_link_status(struct net_device *dev)
1490 {
1491         int ret = -1;
1492
1493         if (!dev)
1494                 return -1;
1495
1496         if (!netif_running(dev)) {
1497                 ret = 0;
1498                 CDEBUG(D_NET, "device idx %d not running\n", dev->ifindex);
1499         }
1500         /* Some devices may not be providing link settings */
1501         else if (dev->ethtool_ops->get_link) {
1502                 ret = dev->ethtool_ops->get_link(dev);
1503                 CDEBUG(D_NET, "device idx %d get_link %u\n",
1504                        ret,
1505                        dev->ifindex);
1506         }
1507
1508         return ret;
1509 }
1510 EXPORT_SYMBOL(lnet_get_link_status);
1511
1512 int lnet_inet_select(struct lnet_ni *ni,
1513                      struct lnet_inetdev *ifaces,
1514                      int num_ifaces)
1515 {
1516         bool addr_set = nid_addr_is_set(&ni->ni_nid);
1517         int if_idx;
1518
1519         /* default to first interface if both interface and NID unspecified */
1520         if (!ni->ni_interface && !addr_set)
1521                 return 0;
1522
1523         for (if_idx = 0; if_idx < num_ifaces; if_idx++) {
1524                 if (ni->ni_interface && strlen(ni->ni_interface) &&
1525                         strcmp(ni->ni_interface, ifaces[if_idx].li_name) != 0)
1526                         /* not the specified interface */
1527                         continue;
1528
1529                 if (!addr_set)
1530                         /* IP unspecified, use IP of first matching interface */
1531                         break;
1532
1533                 if (ifaces[if_idx].li_size == NID_ADDR_BYTES(&ni->ni_nid)) {
1534                         char *addr = (char *)&ifaces[if_idx].li_ipaddr;
1535
1536                         if (ifaces[if_idx].li_size != 4)
1537                                 addr = (char *)ifaces[if_idx].li_ipv6addr;
1538
1539                         if (memcmp(ni->ni_nid.nid_addr, addr,
1540                                    ifaces[if_idx].li_size) == 0)
1541                                 break;
1542                 }
1543         }
1544
1545         if (if_idx < num_ifaces)
1546                 return if_idx;
1547
1548         if (addr_set)
1549                 CERROR("%s: failed to find IP address %s\n",
1550                        libcfs_lnd2modname(ni->ni_nid.nid_type),
1551                        libcfs_nidstr(&ni->ni_nid));
1552         else if (ni->ni_interface)
1553                 CERROR("%s: failed to find interface %s%s%s\n",
1554                        libcfs_lnd2modname(ni->ni_nid.nid_type),
1555                        ni->ni_interface, addr_set ? "@" : "",
1556                        addr_set ? libcfs_nidstr(&ni->ni_nid) : "");
1557
1558         return -EINVAL;
1559 }
1560 EXPORT_SYMBOL(lnet_inet_select);
1561
1562 int
1563 lnet_parse_ip2nets(const char **networksp, const char *ip2nets)
1564 {
1565         struct lnet_inetdev *ifaces = NULL;
1566         u32 *ipaddrs = NULL;
1567         int nip;
1568         int rc;
1569         int i;
1570
1571         if (current->nsproxy && current->nsproxy->net_ns)
1572                 nip = lnet_inet_enumerate(&ifaces, current->nsproxy->net_ns,
1573                                           the_lnet.ln_nis_use_large_nids);
1574         else
1575                 nip = lnet_inet_enumerate(&ifaces, &init_net,
1576                                           the_lnet.ln_nis_use_large_nids);
1577         if (nip < 0) {
1578                 if (nip != -ENOENT) {
1579                         LCONSOLE_ERROR("Error %d enumerating local IP interfaces for ip2nets to match\n",
1580                                            nip);
1581                 } else {
1582                         LCONSOLE_ERROR("No local IP interfaces for ip2nets to match\n");
1583                 }
1584                 return nip;
1585         }
1586
1587         CFS_ALLOC_PTR_ARRAY(ipaddrs, nip);
1588         if (!ipaddrs) {
1589                 rc = -ENOMEM;
1590                 CERROR("lnet: Can't allocate ipaddrs[%d], rc = %d\n",
1591                        nip, rc);
1592                 goto out_free_addrs;
1593         }
1594
1595         for (i = 0; i < nip; i++)
1596                 ipaddrs[i] = ntohl(ifaces[i].li_ipaddr);
1597
1598         rc = lnet_match_networks(networksp, ip2nets, ipaddrs, nip);
1599         if (rc < 0) {
1600                 LCONSOLE_ERROR("Error %d parsing ip2nets\n", rc);
1601         } else if (rc == 0) {
1602                 LCONSOLE_ERROR("ip2nets does not match any local IP interfaces\n");
1603                 rc = -ENOENT;
1604         }
1605         CFS_FREE_PTR_ARRAY(ipaddrs, nip);
1606 out_free_addrs:
1607         kfree(ifaces);
1608         return rc > 0 ? 0 : rc;
1609 }