Whamcloud - gitweb
LU-10214 lnet: allow expressions for route config
[fs/lustre-release.git] / lnet / utils / lnetconfig / liblnetconfig.c
1 /*
2  * LGPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of the
9  * License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  * LGPL HEADER END
20  *
21  * Copyright (c) 2014, 2016, Intel Corporation.
22  *
23  * Author:
24  *   Amir Shehata <amir.shehata@intel.com>
25  */
26
27 /*
28  * There are two APIs:
29  *  1. APIs that take the actual parameters expanded.  This is for other
30  *  entities that would like to link against the library and call the APIs
31  *  directly without having to form an intermediate representation.
32  *  2. APIs that take a YAML file and parses out the information there and
33  *  calls the APIs mentioned in 1
34  */
35
36 #include <errno.h>
37 #include <limits.h>
38 #include <byteswap.h>
39 #include <netdb.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <sys/ioctl.h>
45 #include <net/if.h>
46 #include <libcfs/util/ioctl.h>
47 #include <lnet/lnetctl.h>
48 #include <lnet/socklnd.h>
49 #include "liblnd.h"
50 #include <lnet/lnet.h>
51 #include <sys/types.h>
52 #include <ifaddrs.h>
53 #include "liblnetconfig.h"
54 #include "cyaml.h"
55
56 #define CONFIG_CMD              "configure"
57 #define UNCONFIG_CMD            "unconfigure"
58 #define ADD_CMD                 "add"
59 #define DEL_CMD                 "del"
60 #define SHOW_CMD                "show"
61 #define DBG_CMD                 "dbg"
62 #define MAX_NUM_IPS             128
63
64 /*
65  * lustre_lnet_ip_range_descr
66  *      Describes an IP range.
67  *      Each octect is an expression
68  */
69 struct lustre_lnet_ip_range_descr {
70         struct list_head ipr_entry;
71         struct list_head ipr_expr;
72 };
73
74 /*
75  * lustre_lnet_ip2nets
76  *      Describes an ip2nets rule. This can be on a list of rules.
77  */
78 struct lustre_lnet_ip2nets {
79         struct lnet_dlc_network_descr ip2nets_net;
80         struct list_head ip2nets_ip_ranges;
81 };
82
83 /*
84  * free_intf_descr
85  *      frees the memory allocated for an intf descriptor.
86  */
87 void free_intf_descr(struct lnet_dlc_intf_descr *intf_descr)
88 {
89         if (!intf_descr)
90                 return;
91
92         if (intf_descr->cpt_expr != NULL)
93                 cfs_expr_list_free(intf_descr->cpt_expr);
94         free(intf_descr);
95 }
96
97 /*
98  * lustre_lnet_add_ip_range
99  * Formatting:
100  *      given a string of the format:
101  *      <expr.expr.expr.expr> parse each expr into
102  *      a lustre_lnet_ip_range_descr structure and insert on the list.
103  *
104  *      This function is called from
105  *              YAML on each ip-range.
106  *              As a result of lnetctl command
107  *              When building a NID or P2P selection rules
108  */
109 int lustre_lnet_add_ip_range(struct list_head *list, char *str_ip_range)
110 {
111         struct lustre_lnet_ip_range_descr *ip_range;
112         int rc;
113
114         ip_range = calloc(1, sizeof(*ip_range));
115         if (ip_range == NULL)
116                 return LUSTRE_CFG_RC_OUT_OF_MEM;
117
118         INIT_LIST_HEAD(&ip_range->ipr_entry);
119         INIT_LIST_HEAD(&ip_range->ipr_expr);
120
121         rc = cfs_ip_addr_parse(str_ip_range, strlen(str_ip_range),
122                                &ip_range->ipr_expr);
123         if (rc != 0)
124                 return LUSTRE_CFG_RC_BAD_PARAM;
125
126         list_add_tail(&ip_range->ipr_entry, list);
127
128         return LUSTRE_CFG_RC_NO_ERR;
129 }
130
131 int lustre_lnet_add_intf_descr(struct list_head *list, char *intf, int len)
132 {
133         char *open_sq_bracket = NULL, *close_sq_bracket = NULL,
134              *intf_name;
135         struct lnet_dlc_intf_descr *intf_descr = NULL;
136         int rc;
137         char intf_string[LNET_MAX_STR_LEN];
138
139         if (len >= LNET_MAX_STR_LEN)
140                 return LUSTRE_CFG_RC_BAD_PARAM;
141
142         strncpy(intf_string, intf, len);
143         intf_string[len] = '\0';
144
145         intf_descr = calloc(1, sizeof(*intf_descr));
146         if (intf_descr == NULL)
147                 return LUSTRE_CFG_RC_OUT_OF_MEM;
148
149         INIT_LIST_HEAD(&intf_descr->intf_on_network);
150
151         intf_name = intf_string;
152         open_sq_bracket = strchr(intf_string, '[');
153         if (open_sq_bracket != NULL) {
154                 close_sq_bracket = strchr(intf_string, ']');
155                 if (close_sq_bracket == NULL) {
156                         free(intf_descr);
157                         return LUSTRE_CFG_RC_BAD_PARAM;
158                 }
159                 rc = cfs_expr_list_parse(open_sq_bracket,
160                                          strlen(open_sq_bracket), 0, UINT_MAX,
161                                          &intf_descr->cpt_expr);
162                 if (rc < 0) {
163                         free(intf_descr);
164                         return LUSTRE_CFG_RC_BAD_PARAM;
165                 }
166                 strncpy(intf_descr->intf_name, intf_name,
167                         open_sq_bracket - intf_name);
168                 intf_descr->intf_name[open_sq_bracket - intf_name] = '\0';
169         } else {
170                 strcpy(intf_descr->intf_name, intf_name);
171                 intf_descr->cpt_expr = NULL;
172         }
173
174         list_add_tail(&intf_descr->intf_on_network, list);
175
176         return LUSTRE_CFG_RC_NO_ERR;
177 }
178
179 void lustre_lnet_init_nw_descr(struct lnet_dlc_network_descr *nw_descr)
180 {
181         if (nw_descr != NULL) {
182                 INIT_LIST_HEAD(&nw_descr->network_on_rule);
183                 INIT_LIST_HEAD(&nw_descr->nw_intflist);
184         }
185 }
186
187 static char *get_next_delimiter_in_nid(char *str, char sep)
188 {
189         char *at, *comma;
190
191         /* first find the '@' */
192         at = strchr(str, '@');
193         if (!at)
194                 return str;
195
196         /* now that you found the at find the sep after */
197         comma = strchr(at, sep);
198         return comma;
199 }
200
201 int lustre_lnet_parse_nids(char *nids, char **array, int size,
202                            char ***out_array)
203 {
204         int num_nids = 0;
205         char *comma = nids, *cur, *entry;
206         char **new_array;
207         int i, len, start = 0, finish = 0;
208
209         if (nids == NULL || strlen(nids) == 0)
210                 return size;
211
212         /* count the number or new nids, by counting the number of comma*/
213         while (comma) {
214                 comma = get_next_delimiter_in_nid(comma, ',');
215                 if (comma) {
216                         comma++;
217                         num_nids++;
218                 } else {
219                         num_nids++;
220                 }
221         }
222
223         /*
224          * if the array is not NULL allocate a large enough array to house
225          * the old and new entries
226          */
227         new_array = calloc(sizeof(char*),
228                            (size > 0) ? size + num_nids : num_nids);
229
230         if (!new_array)
231                 goto failed;
232
233         /* parse our the new nids and add them to the tail of the array */
234         comma = nids;
235         cur = nids;
236         start = (size > 0) ? size: 0;
237         finish = (size > 0) ? size + num_nids : num_nids;
238         for (i = start; i < finish; i++) {
239                 comma = get_next_delimiter_in_nid(comma, ',');
240                 if (!comma)
241                         /*
242                          * the length of the string to be parsed out is
243                          * from cur to end of string. So it's good enough
244                          * to strlen(cur)
245                          */
246                         len = strlen(cur) + 1;
247                 else
248                         /* length of the string is comma - cur */
249                         len = (comma - cur) + 1;
250
251                 entry = calloc(1, len);
252                 if (!entry) {
253                         finish = i > 0 ? i - 1: 0;
254                         goto failed;
255                 }
256                 strncpy(entry, cur, len - 1);
257                 entry[len] = '\0';
258                 new_array[i] = entry;
259                 if (comma) {
260                         comma++;
261                         cur = comma;
262                 }
263         }
264
265         /* add the old entries in the array and delete the old array*/
266         for (i = 0; i < size; i++)
267                 new_array[i] = array[i];
268
269         if (array)
270                 free(array);
271
272         *out_array = new_array;
273
274         return finish;
275
276 failed:
277         for (i = start; i < finish; i++)
278                 free(new_array[i]);
279         if (new_array)
280                 free(new_array);
281
282         return size;
283 }
284
285 /*
286  * format expected:
287  *      <intf>[<expr>], <intf>[<expr>],..
288  */
289 int lustre_lnet_parse_interfaces(char *intf_str,
290                                  struct lnet_dlc_network_descr *nw_descr)
291 {
292         char *open_square;
293         char *close_square;
294         char *comma;
295         char *cur = intf_str, *next = NULL;
296         char *end = intf_str + strlen(intf_str);
297         int rc, len;
298         struct lnet_dlc_intf_descr *intf_descr, *tmp;
299
300         if (nw_descr == NULL)
301                 return LUSTRE_CFG_RC_BAD_PARAM;
302
303         while (cur < end) {
304                 open_square = strchr(cur, '[');
305                 if (open_square != NULL) {
306                         close_square = strchr(cur, ']');
307                         if (close_square == NULL) {
308                                 rc = LUSTRE_CFG_RC_BAD_PARAM;
309                                 goto failed;
310                         }
311
312                         comma = strchr(cur, ',');
313                         if (comma != NULL && comma > close_square) {
314                                 next = comma + 1;
315                                 len = next - close_square;
316                         } else {
317                                 len = strlen(cur);
318                                 next = cur + len;
319                         }
320                 } else {
321                         comma = strchr(cur, ',');
322                         if (comma != NULL) {
323                                 next = comma + 1;
324                                 len = comma - cur;
325                         } else {
326                                 len = strlen(cur);
327                                 next = cur + len;
328                         }
329                 }
330
331                 rc = lustre_lnet_add_intf_descr(&nw_descr->nw_intflist, cur, len);
332                 if (rc != LUSTRE_CFG_RC_NO_ERR)
333                         goto failed;
334
335                 cur = next;
336         }
337
338         return LUSTRE_CFG_RC_NO_ERR;
339
340 failed:
341         list_for_each_entry_safe(intf_descr, tmp, &nw_descr->nw_intflist,
342                                  intf_on_network) {
343                 list_del(&intf_descr->intf_on_network);
344                 free_intf_descr(intf_descr);
345         }
346
347         return rc;
348 }
349
350 int lustre_lnet_config_lib_init(void)
351 {
352         return register_ioc_dev(LNET_DEV_ID, LNET_DEV_PATH);
353 }
354
355 void lustre_lnet_config_lib_uninit(void)
356 {
357         unregister_ioc_dev(LNET_DEV_ID);
358 }
359
360 int lustre_lnet_config_ni_system(bool up, bool load_ni_from_mod,
361                                  int seq_no, struct cYAML **err_rc)
362 {
363         struct libcfs_ioctl_data data;
364         unsigned int opc;
365         int rc;
366         char err_str[LNET_MAX_STR_LEN];
367
368         snprintf(err_str, sizeof(err_str), "\"Success\"");
369
370         LIBCFS_IOC_INIT(data);
371
372         /* Reverse logic is used here in order not to change
373          * the lctl utility */
374         data.ioc_flags = load_ni_from_mod ? 0 : 1;
375
376         opc = up ? IOC_LIBCFS_CONFIGURE : IOC_LIBCFS_UNCONFIGURE;
377
378         rc = l_ioctl(LNET_DEV_ID, opc, &data);
379         if (rc != 0) {
380                 snprintf(err_str,
381                         sizeof(err_str),
382                         "\"LNet %s error: %s\"", (up) ? "configure" :
383                         "unconfigure", strerror(errno));
384                 rc = -errno;
385         }
386
387         cYAML_build_error(rc, seq_no, (up) ? CONFIG_CMD : UNCONFIG_CMD,
388                           "lnet", err_str, err_rc);
389
390         return rc;
391 }
392
393 static int dispatch_peer_ni_cmd(lnet_nid_t pnid, lnet_nid_t nid, __u32 cmd,
394                                 struct lnet_ioctl_peer_cfg *data,
395                                 char *err_str, char *cmd_str)
396 {
397         int rc;
398
399         data->prcfg_prim_nid = pnid;
400         data->prcfg_cfg_nid = nid;
401
402         rc = l_ioctl(LNET_DEV_ID, cmd, data);
403         if (rc != 0) {
404                 rc = -errno;
405                 snprintf(err_str,
406                         LNET_MAX_STR_LEN,
407                         "\"cannot %s peer ni: %s\"",
408                         (cmd_str) ? cmd_str : "add", strerror(errno));
409                 err_str[LNET_MAX_STR_LEN - 1] = '\0';
410         }
411
412         return rc;
413 }
414
415 static void lustre_lnet_clean_ip2nets(struct lustre_lnet_ip2nets *ip2nets)
416 {
417         struct lustre_lnet_ip_range_descr *ipr, *tmp;
418         struct cfs_expr_list *el, *el_tmp;
419
420         list_for_each_entry_safe(ipr, tmp,
421                                  &ip2nets->ip2nets_ip_ranges,
422                                  ipr_entry) {
423                 list_del(&ipr->ipr_entry);
424                 list_for_each_entry_safe(el, el_tmp, &ipr->ipr_expr,
425                                          el_link) {
426                         list_del(&el->el_link);
427                         cfs_expr_list_free(el);
428                 }
429                 free(ipr);
430         }
431 }
432
433 /*
434  * returns an rc < 0 if there is an error
435  * otherwise it returns the number IPs generated
436  *  it also has out params: net - network name
437  */
438 static int lnet_expr2ips(char *nidstr, __u32 *ip_list,
439                          struct lustre_lnet_ip2nets *ip2nets,
440                          __u32 *net, char *err_str)
441 {
442         struct lustre_lnet_ip_range_descr *ipr;
443         char *comp1, *comp2;
444         int ip_idx = MAX_NUM_IPS - 1;
445         int ip_range_len, rc = LUSTRE_CFG_RC_NO_ERR;
446         __u32 net_type;
447         char ip_range[LNET_MAX_STR_LEN];
448
449         /* separate the two components of the NID */
450         comp1 = nidstr;
451         comp2 = strchr(nidstr, '@');
452         if (comp2 == NULL) {
453                 snprintf(err_str,
454                         LNET_MAX_STR_LEN,
455                         "\"cannot parse NID %s\"", nidstr);
456                 err_str[LNET_MAX_STR_LEN - 1] = '\0';
457                 rc = LUSTRE_CFG_RC_BAD_PARAM;
458                 goto out;
459         }
460
461         /* length of the expected ip-range */
462         ip_range_len = comp2 - comp1;
463         if (ip_range_len >= LNET_MAX_STR_LEN) {
464                 snprintf(err_str,
465                         LNET_MAX_STR_LEN,
466                         "\"cannot parse ip_range '%s'\"", ip_range);
467                 err_str[LNET_MAX_STR_LEN - 1] = '\0';
468                 rc = LUSTRE_CFG_RC_BAD_PARAM;
469                 goto out;
470         }
471
472         /* move beyond '@' */
473         comp2++;
474
475         /*
476          * if the net component is either o2ib or tcp then we expect
477          * an IP range which could only be a single IP address.
478          * Parse that.
479          */
480         *net = libcfs_str2net(comp2);
481         net_type = LNET_NETTYP(*net);
482         /* expression support is for o2iblnd and socklnd only */
483         if (net_type != O2IBLND && net_type != SOCKLND)
484                 return LUSTRE_CFG_RC_SKIP;
485
486         strncpy(ip_range, comp1, ip_range_len);
487         ip_range[ip_range_len] = '\0';
488         ip2nets->ip2nets_net.nw_id = *net;
489
490         rc = lustre_lnet_add_ip_range(&ip2nets->ip2nets_ip_ranges, ip_range);
491         if (rc != LUSTRE_CFG_RC_NO_ERR) {
492                 snprintf(err_str,
493                         LNET_MAX_STR_LEN,
494                         "\"cannot parse ip_range '%s'\"", ip_range);
495                 err_str[LNET_MAX_STR_LEN - 1] = '\0';
496                 rc = LUSTRE_CFG_RC_BAD_PARAM;
497                 goto out;
498         }
499
500         /*
501         * Generate all the IP Addresses from the parsed range. For sanity
502         * we allow only a max of MAX_NUM_IPS nids to be configured for
503         * a single peer.
504         */
505         list_for_each_entry(ipr, &ip2nets->ip2nets_ip_ranges, ipr_entry)
506                 ip_idx = cfs_ip_addr_range_gen(ip_list, MAX_NUM_IPS,
507                                                 &ipr->ipr_expr);
508
509         if (ip_idx == MAX_NUM_IPS - 1) {
510                 snprintf(err_str, LNET_MAX_STR_LEN,
511                                 "no NIDs provided for configuration");
512                 err_str[LNET_MAX_STR_LEN - 1] = '\0';
513                 rc = LUSTRE_CFG_RC_NO_MATCH;
514                 goto out;
515         } else if (ip_idx == -1) {
516                 rc = LUSTRE_CFG_RC_LAST_ELEM;
517         } else {
518                 rc = ip_idx;
519         }
520
521 out:
522         return rc;
523 }
524
525 static int lustre_lnet_handle_peer_ip2nets(char **nid, int num_nids, bool mr,
526                                            bool range, __u32 cmd,
527                                            char *cmd_type, char *err_str)
528 {
529         __u32 net = LNET_NIDNET(LNET_NID_ANY);
530         int ip_idx;
531         int i, j, rc = LUSTRE_CFG_RC_NO_ERR;
532         __u32 ip_list[MAX_NUM_IPS];
533         struct lustre_lnet_ip2nets ip2nets;
534         struct lnet_ioctl_peer_cfg data;
535         lnet_nid_t peer_nid;
536         lnet_nid_t prim_nid = LNET_NID_ANY;
537
538         /* initialize all lists */
539         INIT_LIST_HEAD(&ip2nets.ip2nets_ip_ranges);
540         INIT_LIST_HEAD(&ip2nets.ip2nets_net.network_on_rule);
541         INIT_LIST_HEAD(&ip2nets.ip2nets_net.nw_intflist);
542
543         /* each nid entry is an expression */
544         for (i = 0; i < num_nids; i++) {
545                 if (!range && i == 0)
546                         prim_nid = libcfs_str2nid(nid[0]);
547                 else if (range)
548                         prim_nid = LNET_NID_ANY;
549
550                 rc = lnet_expr2ips(nid[i], ip_list, &ip2nets, &net, err_str);
551                 if (rc == LUSTRE_CFG_RC_SKIP)
552                         continue;
553                 else if (rc == LUSTRE_CFG_RC_LAST_ELEM)
554                         rc = -1;
555                 else if (rc < LUSTRE_CFG_RC_NO_ERR)
556                         goto out;
557
558                 ip_idx = rc;
559
560                 for (j = MAX_NUM_IPS - 1; j > ip_idx; j--) {
561                         peer_nid = LNET_MKNID(net, ip_list[j]);
562                         if (peer_nid == LNET_NID_ANY) {
563                                 snprintf(err_str,
564                                         LNET_MAX_STR_LEN,
565                                         "\"cannot parse NID\"");
566                                 err_str[LNET_MAX_STR_LEN - 1] = '\0';
567                                 rc = LUSTRE_CFG_RC_BAD_PARAM;
568                                 goto out;
569                         }
570
571                         LIBCFS_IOC_INIT_V2(data, prcfg_hdr);
572                         data.prcfg_mr = mr;
573
574                         if (prim_nid == LNET_NID_ANY && j == MAX_NUM_IPS - 1) {
575                                 prim_nid = peer_nid;
576                                 peer_nid = LNET_NID_ANY;
577                         }
578
579                         if (!range && num_nids > 1 && i == 0 &&
580                             cmd == IOC_LIBCFS_DEL_PEER_NI)
581                                 continue;
582                         else if (!range && i == 0)
583                                 peer_nid = LNET_NID_ANY;
584
585                         /*
586                         * If prim_nid is not provided then the first nid in the
587                         * list becomes the prim_nid. First time round the loop
588                         * use LNET_NID_ANY for the first parameter, then use
589                         * nid[0] as the key nid after wards
590                         */
591                         rc = dispatch_peer_ni_cmd(prim_nid, peer_nid, cmd,
592                                                   &data, err_str, cmd_type);
593                         if (rc != 0)
594                                 goto out;
595
596                         /*
597                          * we just deleted the entire peer using the
598                          * primary_nid. So don't bother iterating through
599                          * the rest of the nids
600                          */
601                         if (prim_nid != LNET_NID_ANY &&
602                             peer_nid == LNET_NID_ANY &&
603                             cmd == IOC_LIBCFS_DEL_PEER_NI)
604                                 goto next_nid;
605                 }
606 next_nid:
607                 lustre_lnet_clean_ip2nets(&ip2nets);
608         }
609
610 out:
611         lustre_lnet_clean_ip2nets(&ip2nets);
612         return rc;
613 }
614
615 int lustre_lnet_config_peer_nid(char *pnid, char **nid, int num_nids,
616                                 bool mr, bool ip2nets, int seq_no,
617                                 struct cYAML **err_rc)
618 {
619         int rc = LUSTRE_CFG_RC_NO_ERR;
620         char err_str[LNET_MAX_STR_LEN] = {0};
621         char **nid_array = NULL;
622
623         snprintf(err_str, sizeof(err_str), "\"Success\"");
624
625         if (ip2nets) {
626                 rc = lustre_lnet_handle_peer_ip2nets(nid, num_nids, mr,
627                                                 ip2nets, IOC_LIBCFS_ADD_PEER_NI,
628                                                 ADD_CMD, err_str);
629                 goto out;
630         }
631
632         if (pnid) {
633                 if (libcfs_str2nid(pnid) == LNET_NID_ANY) {
634                         snprintf(err_str, sizeof(err_str),
635                                  "bad primary NID: '%s'",
636                                  pnid);
637                         rc = LUSTRE_CFG_RC_MISSING_PARAM;
638                         goto out;
639                 }
640
641                 num_nids++;
642
643                 nid_array = calloc(sizeof(*nid_array), num_nids);
644                 if (!nid_array) {
645                         snprintf(err_str, sizeof(err_str),
646                                         "out of memory");
647                         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
648                         goto out;
649                 }
650                 nid_array[0] = pnid;
651                 memcpy(&nid_array[1], nid, sizeof(*nid) * (num_nids - 1));
652         }
653
654         rc = lustre_lnet_handle_peer_ip2nets((pnid) ? nid_array : nid,
655                                              num_nids, mr, ip2nets,
656                                              IOC_LIBCFS_ADD_PEER_NI, ADD_CMD,
657                                              err_str);
658         if (rc)
659                 goto out;
660
661 out:
662         if (nid_array)
663                 free(nid_array);
664
665         cYAML_build_error(rc, seq_no, ADD_CMD, "peer_ni", err_str, err_rc);
666         return rc;
667 }
668
669 int lustre_lnet_del_peer_nid(char *pnid, char **nid, int num_nids,
670                              bool ip2nets, int seq_no, struct cYAML **err_rc)
671 {
672         int rc = LUSTRE_CFG_RC_NO_ERR;
673         char err_str[LNET_MAX_STR_LEN] = {0};
674         char **nid_array = NULL;
675
676         snprintf(err_str, sizeof(err_str), "\"Success\"");
677
678         if (ip2nets) {
679                 rc = lustre_lnet_handle_peer_ip2nets(nid, num_nids, false,
680                                                 ip2nets, IOC_LIBCFS_DEL_PEER_NI,
681                                                 DEL_CMD, err_str);
682                 goto out;
683         }
684
685         if (pnid == NULL) {
686                 snprintf(err_str, sizeof(err_str),
687                          "\"Primary nid is not provided\"");
688                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
689                 goto out;
690         } else if (!ip2nets) {
691                 if (libcfs_str2nid(pnid) == LNET_NID_ANY) {
692                         rc = LUSTRE_CFG_RC_BAD_PARAM;
693                         snprintf(err_str, sizeof(err_str),
694                                  "bad key NID: '%s'",
695                                  pnid);
696                         goto out;
697                 }
698         }
699
700         num_nids++;
701         nid_array = calloc(sizeof(*nid_array), num_nids);
702         if (!nid_array) {
703                 snprintf(err_str, sizeof(err_str),
704                                 "out of memory");
705                 rc = LUSTRE_CFG_RC_OUT_OF_MEM;
706                 goto out;
707         }
708         nid_array[0] = pnid;
709         memcpy(&nid_array[1], nid, sizeof(*nid) * (num_nids - 1));
710
711         rc = lustre_lnet_handle_peer_ip2nets(nid_array, num_nids, false,
712                                              ip2nets, IOC_LIBCFS_DEL_PEER_NI,
713                                              DEL_CMD, err_str);
714         if (rc)
715                 goto out;
716
717 out:
718         if (nid_array)
719                 free(nid_array);
720
721         cYAML_build_error(rc, seq_no, DEL_CMD, "peer_ni", err_str, err_rc);
722         return rc;
723 }
724
725 int lustre_lnet_config_route(char *nw, char *gw, int hops, int prio,
726                              int seq_no, struct cYAML **err_rc)
727 {
728         struct lnet_ioctl_config_data data;
729         lnet_nid_t gateway_nid;
730         int rc = LUSTRE_CFG_RC_NO_ERR;
731         int ip_idx, i;
732         __u32 rnet = LNET_NIDNET(LNET_NID_ANY);
733         __u32 net = LNET_NIDNET(LNET_NID_ANY);
734         char err_str[LNET_MAX_STR_LEN];
735         __u32 ip_list[MAX_NUM_IPS];
736         struct lustre_lnet_ip2nets ip2nets;
737
738         /* initialize all lists */
739         INIT_LIST_HEAD(&ip2nets.ip2nets_ip_ranges);
740         INIT_LIST_HEAD(&ip2nets.ip2nets_net.network_on_rule);
741         INIT_LIST_HEAD(&ip2nets.ip2nets_net.nw_intflist);
742
743         snprintf(err_str, sizeof(err_str), "\"Success\"");
744
745         if (nw == NULL || gw == NULL) {
746                 snprintf(err_str,
747                          sizeof(err_str),
748                          "\"missing mandatory parameter(s): '%s'\"",
749                          (nw == NULL && gw == NULL) ? "network, gateway" :
750                          (nw == NULL) ? "network" : "gateway");
751                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
752                 goto out;
753         }
754
755         rnet = libcfs_str2net(nw);
756         if (rnet == LNET_NIDNET(LNET_NID_ANY)) {
757                 snprintf(err_str,
758                          sizeof(err_str),
759                          "\"cannot parse remote net %s\"", nw);
760                 rc = LUSTRE_CFG_RC_BAD_PARAM;
761                 goto out;
762         }
763
764         if (hops == -1) {
765                 /* hops is undefined */
766                 hops = LNET_UNDEFINED_HOPS;
767         } else if (hops < 1 || hops > 255) {
768                 snprintf(err_str,
769                         sizeof(err_str),
770                         "\"invalid hop count %d, must be between 1 and 255\"",
771                         hops);
772                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
773                 goto out;
774         }
775
776         if (prio == -1) {
777                 prio = 0;
778         } else if (prio < 0) {
779                 snprintf(err_str,
780                          sizeof(err_str),
781                         "\"invalid priority %d, must be greater than 0\"",
782                         prio);
783                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
784                 goto out;
785         }
786
787         rc = lnet_expr2ips(gw, ip_list,
788                            &ip2nets, &net, err_str);
789         if (rc == LUSTRE_CFG_RC_LAST_ELEM)
790                 rc = -1;
791         else if (rc < LUSTRE_CFG_RC_NO_ERR)
792                 goto out;
793
794         ip_idx = rc;
795
796         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
797         data.cfg_net = rnet;
798         data.cfg_config_u.cfg_route.rtr_hop = hops;
799         data.cfg_config_u.cfg_route.rtr_priority = prio;
800
801         for (i = MAX_NUM_IPS - 1; i > ip_idx; i--) {
802                 gateway_nid = LNET_MKNID(net, ip_list[i]);
803                 if (gateway_nid == LNET_NID_ANY) {
804                         snprintf(err_str,
805                                 LNET_MAX_STR_LEN,
806                                 "\"cannot form gateway NID: %u\"",
807                                 ip_list[i]);
808                         err_str[LNET_MAX_STR_LEN - 1] = '\0';
809                         rc = LUSTRE_CFG_RC_BAD_PARAM;
810                         goto out;
811                 }
812                 data.cfg_nid = gateway_nid;
813
814                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_ROUTE, &data);
815                 if (rc != 0) {
816                         rc = -errno;
817                         snprintf(err_str,
818                                 sizeof(err_str),
819                                 "\"cannot add route: %s\"", strerror(errno));
820                         goto out;
821                 }
822         }
823 out:
824         cYAML_build_error(rc, seq_no, ADD_CMD, "route", err_str, err_rc);
825
826         return rc;
827 }
828
829 int lustre_lnet_del_route(char *nw, char *gw,
830                           int seq_no, struct cYAML **err_rc)
831 {
832         struct lnet_ioctl_config_data data;
833         lnet_nid_t gateway_nid;
834         int rc = LUSTRE_CFG_RC_NO_ERR;
835         __u32 rnet = LNET_NIDNET(LNET_NID_ANY);
836         __u32 net = LNET_NIDNET(LNET_NID_ANY);
837         char err_str[LNET_MAX_STR_LEN];
838         int ip_idx, i;
839         __u32 ip_list[MAX_NUM_IPS];
840         struct lustre_lnet_ip2nets ip2nets;
841
842         /* initialize all lists */
843         INIT_LIST_HEAD(&ip2nets.ip2nets_ip_ranges);
844         INIT_LIST_HEAD(&ip2nets.ip2nets_net.network_on_rule);
845         INIT_LIST_HEAD(&ip2nets.ip2nets_net.nw_intflist);
846
847         snprintf(err_str, sizeof(err_str), "\"Success\"");
848
849         if (nw == NULL || gw == NULL) {
850                 snprintf(err_str,
851                          sizeof(err_str),
852                          "\"missing mandatory parameter(s): '%s'\"",
853                          (nw == NULL && gw == NULL) ? "network, gateway" :
854                          (nw == NULL) ? "network" : "gateway");
855                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
856                 goto out;
857         }
858
859         rnet = libcfs_str2net(nw);
860         if (rnet == LNET_NIDNET(LNET_NID_ANY)) {
861                 snprintf(err_str,
862                          sizeof(err_str),
863                          "\"cannot parse remote net '%s'\"", nw);
864                 rc = LUSTRE_CFG_RC_BAD_PARAM;
865                 goto out;
866         }
867
868         rc = lnet_expr2ips(gw, ip_list,
869                            &ip2nets, &net, err_str);
870         if (rc == LUSTRE_CFG_RC_LAST_ELEM)
871                 rc = -1;
872         else if (rc < LUSTRE_CFG_RC_NO_ERR)
873                 goto out;
874
875         ip_idx = rc;
876
877         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
878         data.cfg_net = rnet;
879
880         for (i = MAX_NUM_IPS - 1; i > ip_idx; i--) {
881                 gateway_nid = LNET_MKNID(net, ip_list[i]);
882                 if (gateway_nid == LNET_NID_ANY) {
883                         snprintf(err_str,
884                                 LNET_MAX_STR_LEN,
885                                 "\"cannot form gateway NID: %u\"",
886                                 ip_list[i]);
887                         err_str[LNET_MAX_STR_LEN - 1] = '\0';
888                         rc = LUSTRE_CFG_RC_BAD_PARAM;
889                         goto out;
890                 }
891                 data.cfg_nid = gateway_nid;
892
893                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DEL_ROUTE, &data);
894                 if (rc != 0) {
895                         rc = -errno;
896                         snprintf(err_str,
897                                 sizeof(err_str),
898                                 "\"cannot delete route: %s\"", strerror(errno));
899                         goto out;
900                 }
901         }
902 out:
903         cYAML_build_error(rc, seq_no, DEL_CMD, "route", err_str, err_rc);
904
905         return rc;
906 }
907
908 int lustre_lnet_show_route(char *nw, char *gw, int hops, int prio, int detail,
909                            int seq_no, struct cYAML **show_rc,
910                            struct cYAML **err_rc)
911 {
912         struct lnet_ioctl_config_data data;
913         lnet_nid_t gateway_nid;
914         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
915         int l_errno = 0;
916         __u32 net = LNET_NIDNET(LNET_NID_ANY);
917         int i;
918         struct cYAML *root = NULL, *route = NULL, *item = NULL;
919         struct cYAML *first_seq = NULL;
920         char err_str[LNET_MAX_STR_LEN];
921         bool exist = false;
922
923         snprintf(err_str, sizeof(err_str),
924                  "\"out of memory\"");
925
926         if (nw != NULL) {
927                 net = libcfs_str2net(nw);
928                 if (net == LNET_NIDNET(LNET_NID_ANY)) {
929                         snprintf(err_str,
930                                  sizeof(err_str),
931                                  "\"cannot parse net '%s'\"", nw);
932                         rc = LUSTRE_CFG_RC_BAD_PARAM;
933                         goto out;
934                 }
935
936         } else {
937                 /* show all routes without filtering on net */
938                 net = LNET_NIDNET(LNET_NID_ANY);
939         }
940
941         if (gw != NULL) {
942                 gateway_nid = libcfs_str2nid(gw);
943                 if (gateway_nid == LNET_NID_ANY) {
944                         snprintf(err_str,
945                                  sizeof(err_str),
946                                  "\"cannot parse gateway NID '%s'\"", gw);
947                         rc = LUSTRE_CFG_RC_BAD_PARAM;
948                         goto out;
949                 }
950         } else
951                 /* show all routes with out filtering on gateway */
952                 gateway_nid = LNET_NID_ANY;
953
954         if ((hops < 1 && hops != -1) || hops > 255) {
955                 snprintf(err_str,
956                          sizeof(err_str),
957                          "\"invalid hop count %d, must be between 0 and 256\"",
958                          hops);
959                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
960                 goto out;
961         }
962
963         /* create struct cYAML root object */
964         root = cYAML_create_object(NULL, NULL);
965         if (root == NULL)
966                 goto out;
967
968         route = cYAML_create_seq(root, "route");
969         if (route == NULL)
970                 goto out;
971
972         for (i = 0;; i++) {
973                 LIBCFS_IOC_INIT_V2(data, cfg_hdr);
974                 data.cfg_count = i;
975
976                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_ROUTE, &data);
977                 if (rc != 0) {
978                         l_errno = errno;
979                         break;
980                 }
981
982                 /* filter on provided data */
983                 if (net != LNET_NIDNET(LNET_NID_ANY) &&
984                     net != data.cfg_net)
985                         continue;
986
987                 if (gateway_nid != LNET_NID_ANY &&
988                     gateway_nid != data.cfg_nid)
989                         continue;
990
991                 if (hops != -1 &&
992                     hops != data.cfg_config_u.cfg_route.rtr_hop)
993                         continue;
994
995                 if (prio != -1 &&
996                     prio != data.cfg_config_u.cfg_route.rtr_priority)
997                         continue;
998
999                 /* default rc to -1 incase we hit the goto */
1000                 rc = -1;
1001                 exist = true;
1002
1003                 item = cYAML_create_seq_item(route);
1004                 if (item == NULL)
1005                         goto out;
1006
1007                 if (first_seq == NULL)
1008                         first_seq = item;
1009
1010                 if (cYAML_create_string(item, "net",
1011                                         libcfs_net2str(data.cfg_net)) == NULL)
1012                         goto out;
1013
1014                 if (cYAML_create_string(item, "gateway",
1015                                         libcfs_nid2str(data.cfg_nid)) == NULL)
1016                         goto out;
1017
1018                 if (detail) {
1019                         if (cYAML_create_number(item, "hop",
1020                                                 (int) data.cfg_config_u.
1021                                                 cfg_route.rtr_hop) ==
1022                             NULL)
1023                                 goto out;
1024
1025                         if (cYAML_create_number(item, "priority",
1026                                                 data.cfg_config_u.
1027                                                 cfg_route.rtr_priority) == NULL)
1028                                 goto out;
1029
1030                         if (cYAML_create_string(item, "state",
1031                                                 data.cfg_config_u.cfg_route.
1032                                                         rtr_flags ?
1033                                                 "up" : "down") == NULL)
1034                                 goto out;
1035                 }
1036         }
1037
1038         /* print output iff show_rc is not provided */
1039         if (show_rc == NULL)
1040                 cYAML_print_tree(root);
1041
1042         if (l_errno != ENOENT) {
1043                 snprintf(err_str,
1044                          sizeof(err_str),
1045                          "\"cannot get routes: %s\"",
1046                          strerror(l_errno));
1047                 rc = -l_errno;
1048                 goto out;
1049         } else
1050                 rc = LUSTRE_CFG_RC_NO_ERR;
1051
1052         snprintf(err_str, sizeof(err_str), "\"success\"");
1053 out:
1054         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR || !exist) {
1055                 cYAML_free_tree(root);
1056         } else if (show_rc != NULL && *show_rc != NULL) {
1057                 struct cYAML *show_node;
1058                 /* find the route node, if one doesn't exist then
1059                  * insert one.  Otherwise add to the one there
1060                  */
1061                 show_node = cYAML_get_object_item(*show_rc, "route");
1062                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
1063                         cYAML_insert_child(show_node, first_seq);
1064                         free(route);
1065                         free(root);
1066                 } else if (show_node == NULL) {
1067                         cYAML_insert_sibling((*show_rc)->cy_child,
1068                                                 route);
1069                         free(root);
1070                 } else {
1071                         cYAML_free_tree(root);
1072                 }
1073         } else {
1074                 *show_rc = root;
1075         }
1076
1077         cYAML_build_error(rc, seq_no, SHOW_CMD, "route", err_str, err_rc);
1078
1079         return rc;
1080 }
1081
1082 static int socket_intf_query(int request, char *intf,
1083                              struct ifreq *ifr)
1084 {
1085         int rc = 0;
1086         int sockfd;
1087
1088         if (strlen(intf) >= IFNAMSIZ || ifr == NULL)
1089                 return LUSTRE_CFG_RC_BAD_PARAM;
1090
1091         sockfd = socket(AF_INET, SOCK_DGRAM, 0);
1092         if (sockfd < 0)
1093                 return LUSTRE_CFG_RC_BAD_PARAM;
1094
1095         strcpy(ifr->ifr_name, intf);
1096         rc = ioctl(sockfd, request, ifr);
1097         if (rc != 0)
1098                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1099
1100         close(sockfd);
1101
1102         return rc;
1103 }
1104
1105 /*
1106  * for each interface in the array of interfaces find the IP address of
1107  * that interface, create its nid and add it to an array of NIDs.
1108  * Stop if any of the interfaces is down
1109  */
1110 static int lustre_lnet_intf2nids(struct lnet_dlc_network_descr *nw,
1111                                  lnet_nid_t **nids, __u32 *nnids)
1112 {
1113         int i = 0, count = 0, rc;
1114         struct ifreq ifr;
1115         __u32 ip;
1116         struct lnet_dlc_intf_descr *intf;
1117
1118         if (nw == NULL || nids == NULL)
1119                 return LUSTRE_CFG_RC_BAD_PARAM;
1120
1121         list_for_each_entry(intf, &nw->nw_intflist, intf_on_network)
1122                 count++;
1123
1124         *nids = calloc(count, sizeof(lnet_nid_t));
1125         if (*nids == NULL)
1126                 return LUSTRE_CFG_RC_OUT_OF_MEM;
1127
1128         list_for_each_entry(intf, &nw->nw_intflist, intf_on_network) {
1129                 memset(&ifr, 0, sizeof(ifr));
1130                 rc = socket_intf_query(SIOCGIFFLAGS, intf->intf_name, &ifr);
1131                 if (rc != 0)
1132                         goto failed;
1133
1134                 if ((ifr.ifr_flags & IFF_UP) == 0) {
1135                         rc = LUSTRE_CFG_RC_BAD_PARAM;
1136                         goto failed;
1137                 }
1138
1139                 memset(&ifr, 0, sizeof(ifr));
1140                 rc = socket_intf_query(SIOCGIFADDR, intf->intf_name, &ifr);
1141                 if (rc != 0)
1142                         goto failed;
1143
1144                 ip = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
1145                 ip = bswap_32(ip);
1146                 (*nids)[i] = LNET_MKNID(nw->nw_id, ip);
1147                 i++;
1148         }
1149
1150         *nnids = count;
1151
1152         return 0;
1153
1154 failed:
1155         free(*nids);
1156         *nids = NULL;
1157         return rc;
1158 }
1159
1160 /*
1161  * called repeatedly until a match or no more ip range
1162  * What do you have?
1163  *      ip_range expression
1164  *      interface list with all the interface names.
1165  *      all the interfaces in the system.
1166  *
1167  *      try to match the ip_range expr to one of the interfaces' IPs in
1168  *      the system. If we hit a patch for an interface. Check if that
1169  *      interface name is in the list.
1170  *
1171  *      If there are more than one interface in the list, then make sure
1172  *      that the IPs for all of these interfaces match the ip ranges
1173  *      given.
1174  *
1175  *      for each interface in intf_list
1176  *              look up the intf name in ifa
1177  *              if not there then no match
1178  *              check ip obtained from ifa against a match to any of the
1179  *              ip_ranges given.
1180  *              If no match, then fail
1181  *
1182  *      The result is that all the interfaces have to match.
1183  */
1184 int lustre_lnet_match_ip_to_intf(struct ifaddrs *ifa,
1185                                  struct list_head *intf_list,
1186                                  struct list_head *ip_ranges)
1187 {
1188         int rc;
1189         __u32 ip;
1190         struct lnet_dlc_intf_descr *intf_descr, *tmp;
1191         struct ifaddrs *ifaddr = ifa;
1192         struct lustre_lnet_ip_range_descr *ip_range;
1193         int family;
1194
1195         /*
1196          * if there are no explicit interfaces, and no ip ranges, then
1197          * configure the first tcp interface we encounter.
1198          */
1199         if (list_empty(intf_list) && list_empty(ip_ranges)) {
1200                 for (ifaddr = ifa; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {
1201                         if (ifaddr->ifa_addr == NULL)
1202                                 continue;
1203
1204                         if ((ifaddr->ifa_flags & IFF_UP) == 0)
1205                                 continue;
1206
1207                         family = ifaddr->ifa_addr->sa_family;
1208                         if (family == AF_INET &&
1209                             strcmp(ifaddr->ifa_name, "lo") != 0) {
1210                                 rc = lustre_lnet_add_intf_descr
1211                                         (intf_list, ifaddr->ifa_name,
1212                                         strlen(ifaddr->ifa_name));
1213
1214                                 if (rc != LUSTRE_CFG_RC_NO_ERR)
1215                                         return rc;
1216
1217                                 return LUSTRE_CFG_RC_MATCH;
1218                         }
1219                 }
1220                 return LUSTRE_CFG_RC_NO_MATCH;
1221         }
1222
1223         /*
1224          * First interface which matches an IP pattern will be used
1225          */
1226         if (list_empty(intf_list)) {
1227                 /*
1228                  * no interfaces provided in the rule, but an ip range is
1229                  * provided, so try and match an interface to the ip
1230                  * range.
1231                  */
1232                 for (ifaddr = ifa; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {
1233                         if (ifaddr->ifa_addr == NULL)
1234                                 continue;
1235
1236                         if ((ifaddr->ifa_flags & IFF_UP) == 0)
1237                                 continue;
1238
1239                         family = ifaddr->ifa_addr->sa_family;
1240                         if (family == AF_INET) {
1241                                 ip = ((struct sockaddr_in *)ifaddr->ifa_addr)->
1242                                         sin_addr.s_addr;
1243
1244                                 list_for_each_entry(ip_range, ip_ranges,
1245                                                     ipr_entry) {
1246                                         rc = cfs_ip_addr_match(bswap_32(ip),
1247                                                         &ip_range->ipr_expr);
1248                                         if (!rc)
1249                                                 continue;
1250
1251                                         rc = lustre_lnet_add_intf_descr
1252                                           (intf_list, ifaddr->ifa_name,
1253                                            strlen(ifaddr->ifa_name));
1254
1255                                         if (rc != LUSTRE_CFG_RC_NO_ERR)
1256                                                 return rc;
1257                                 }
1258                         }
1259                 }
1260
1261                 if (!list_empty(intf_list))
1262                         return LUSTRE_CFG_RC_MATCH;
1263
1264                 return LUSTRE_CFG_RC_NO_MATCH;
1265         }
1266
1267         /*
1268          * If an interface is explicitly specified the ip-range might or
1269          * might not be specified. if specified the interface needs to match the
1270          * ip-range. If no ip-range then the interfaces are
1271          * automatically matched if they are all up.
1272          * If > 1 interfaces all the interfaces must match for the NI to
1273          * be configured.
1274          */
1275         list_for_each_entry_safe(intf_descr, tmp, intf_list, intf_on_network) {
1276                 for (ifaddr = ifa; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {
1277                         if (ifaddr->ifa_addr == NULL)
1278                                 continue;
1279
1280                         family = ifaddr->ifa_addr->sa_family;
1281                         if (family == AF_INET &&
1282                             strcmp(intf_descr->intf_name,
1283                                    ifaddr->ifa_name) == 0)
1284                                 break;
1285                 }
1286
1287                 if (ifaddr == NULL) {
1288                         list_del(&intf_descr->intf_on_network);
1289                         free_intf_descr(intf_descr);
1290                         continue;
1291                 }
1292
1293                 if ((ifaddr->ifa_flags & IFF_UP) == 0) {
1294                         list_del(&intf_descr->intf_on_network);
1295                         free_intf_descr(intf_descr);
1296                         continue;
1297                 }
1298
1299                 ip = ((struct sockaddr_in *)ifaddr->ifa_addr)->sin_addr.s_addr;
1300
1301                 rc = 1;
1302                 list_for_each_entry(ip_range, ip_ranges, ipr_entry) {
1303                         rc = cfs_ip_addr_match(bswap_32(ip), &ip_range->ipr_expr);
1304                         if (rc)
1305                                 break;
1306                 }
1307
1308                 if (!rc) {
1309                         /* no match for this interface */
1310                         list_del(&intf_descr->intf_on_network);
1311                         free_intf_descr(intf_descr);
1312                 }
1313         }
1314
1315         return LUSTRE_CFG_RC_MATCH;
1316 }
1317
1318 int lustre_lnet_resolve_ip2nets_rule(struct lustre_lnet_ip2nets *ip2nets,
1319                                      lnet_nid_t **nids, __u32 *nnids)
1320 {
1321         struct ifaddrs *ifa;
1322         int rc = LUSTRE_CFG_RC_NO_ERR;
1323
1324         rc = getifaddrs(&ifa);
1325         if (rc < 0)
1326                 return -errno;
1327
1328         rc = lustre_lnet_match_ip_to_intf(ifa,
1329                                           &ip2nets->ip2nets_net.nw_intflist,
1330                                           &ip2nets->ip2nets_ip_ranges);
1331         if (rc != LUSTRE_CFG_RC_MATCH) {
1332                 freeifaddrs(ifa);
1333                 return rc;
1334         }
1335
1336         rc = lustre_lnet_intf2nids(&ip2nets->ip2nets_net, nids, nnids);
1337         if (rc != LUSTRE_CFG_RC_NO_ERR) {
1338                 *nids = NULL;
1339                 *nnids = 0;
1340         }
1341
1342         freeifaddrs(ifa);
1343
1344         return rc;
1345 }
1346
1347 static int
1348 lustre_lnet_ioctl_config_ni(struct list_head *intf_list,
1349                             struct lnet_ioctl_config_lnd_tunables *tunables,
1350                             struct cfs_expr_list *global_cpts,
1351                             lnet_nid_t *nids, char *err_str)
1352 {
1353         char *data;
1354         struct lnet_ioctl_config_ni *conf;
1355         struct lnet_ioctl_config_lnd_tunables *tun = NULL;
1356         int rc = LUSTRE_CFG_RC_NO_ERR, i = 0;
1357         size_t len;
1358         int count;
1359         struct lnet_dlc_intf_descr *intf_descr;
1360         __u32 *cpt_array;
1361         struct cfs_expr_list *cpt_expr;
1362
1363         list_for_each_entry(intf_descr, intf_list,
1364                             intf_on_network) {
1365                 if (tunables != NULL)
1366                         len = sizeof(struct lnet_ioctl_config_ni) +
1367                               sizeof(struct lnet_ioctl_config_lnd_tunables);
1368                 else
1369                         len = sizeof(struct lnet_ioctl_config_ni);
1370
1371                 data = calloc(1, len);
1372                 if (!data)
1373                         return LUSTRE_CFG_RC_OUT_OF_MEM;
1374                 conf = (struct lnet_ioctl_config_ni*) data;
1375                 if (tunables != NULL)
1376                         tun = (struct lnet_ioctl_config_lnd_tunables*)
1377                                 conf->lic_bulk;
1378
1379                 LIBCFS_IOC_INIT_V2(*conf, lic_cfg_hdr);
1380                 conf->lic_cfg_hdr.ioc_len = len;
1381                 conf->lic_nid = nids[i];
1382                 strncpy(conf->lic_ni_intf[0], intf_descr->intf_name,
1383                         LNET_MAX_STR_LEN);
1384
1385                 if (intf_descr->cpt_expr != NULL)
1386                         cpt_expr = intf_descr->cpt_expr;
1387                 else if (global_cpts != NULL)
1388                         cpt_expr = global_cpts;
1389                 else
1390                         cpt_expr = NULL;
1391
1392                 if (cpt_expr != NULL) {
1393                         count = cfs_expr_list_values(cpt_expr,
1394                                                      LNET_MAX_SHOW_NUM_CPT,
1395                                                      &cpt_array);
1396                         if (count > 0) {
1397                                 memcpy(conf->lic_cpts, cpt_array,
1398                                        sizeof(cpt_array[0]) * LNET_MAX_STR_LEN);
1399                                 free(cpt_array);
1400                         } else {
1401                                 count = 0;
1402                         }
1403                 } else {
1404                         count = 0;
1405                 }
1406
1407                 conf->lic_ncpts = count;
1408
1409                 if (tunables != NULL)
1410                         memcpy(tun, tunables, sizeof(*tunables));
1411
1412                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_LOCAL_NI, data);
1413                 if (rc < 0) {
1414                         rc = -errno;
1415                         snprintf(err_str,
1416                                  LNET_MAX_STR_LEN,
1417                                  "\"cannot add network: %s\"", strerror(errno));
1418                         free(data);
1419                         return rc;
1420                 }
1421                 free(data);
1422                 i++;
1423         }
1424
1425         return LUSTRE_CFG_RC_NO_ERR;
1426 }
1427
1428 int
1429 lustre_lnet_config_ip2nets(struct lustre_lnet_ip2nets *ip2nets,
1430                            struct lnet_ioctl_config_lnd_tunables *tunables,
1431                            struct cfs_expr_list *global_cpts,
1432                            int seq_no, struct cYAML **err_rc)
1433 {
1434         lnet_nid_t *nids = NULL;
1435         __u32 nnids = 0;
1436         int rc;
1437         char err_str[LNET_MAX_STR_LEN];
1438
1439         snprintf(err_str, sizeof(err_str), "\"success\"");
1440
1441         if (!ip2nets) {
1442                 snprintf(err_str,
1443                          sizeof(err_str),
1444                          "\"incomplete ip2nets information\"");
1445                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1446                 goto out;
1447         }
1448
1449         /*
1450          * call below function to resolve the rules into a list of nids.
1451          * The memory is allocated in that function then freed here when
1452          * it's no longer needed.
1453          */
1454         rc = lustre_lnet_resolve_ip2nets_rule(ip2nets, &nids, &nnids);
1455         if (rc != LUSTRE_CFG_RC_NO_ERR && rc != LUSTRE_CFG_RC_MATCH) {
1456                 snprintf(err_str,
1457                          sizeof(err_str),
1458                          "\"cannot resolve ip2nets rule\"");
1459                 goto out;
1460         }
1461
1462         if (list_empty(&ip2nets->ip2nets_net.nw_intflist)) {
1463                 snprintf(err_str, sizeof(err_str),
1464                          "\"no interfaces match ip2nets rules\"");
1465                 goto free_nids_out;
1466         }
1467
1468         rc = lustre_lnet_ioctl_config_ni(&ip2nets->ip2nets_net.nw_intflist,
1469                                          tunables, global_cpts, nids,
1470                                          err_str);
1471
1472 free_nids_out:
1473         free(nids);
1474
1475 out:
1476         cYAML_build_error(rc, seq_no, ADD_CMD, "ip2nets", err_str, err_rc);
1477         return rc;
1478 }
1479
1480 int lustre_lnet_config_ni(struct lnet_dlc_network_descr *nw_descr,
1481                           struct cfs_expr_list *global_cpts,
1482                           char *ip2net,
1483                           struct lnet_ioctl_config_lnd_tunables *tunables,
1484                           int seq_no, struct cYAML **err_rc)
1485 {
1486         char *data = NULL;
1487         struct lnet_ioctl_config_ni *conf;
1488         struct lnet_ioctl_config_lnd_tunables *tun = NULL;
1489         char buf[LNET_MAX_STR_LEN];
1490         int rc = LUSTRE_CFG_RC_NO_ERR;
1491         char err_str[LNET_MAX_STR_LEN];
1492         lnet_nid_t *nids = NULL;
1493         __u32 nnids = 0;
1494         size_t len;
1495         int count;
1496         struct lnet_dlc_intf_descr *intf_descr, *tmp;
1497         __u32 *cpt_array;
1498
1499         snprintf(err_str, sizeof(err_str), "\"success\"");
1500
1501         if (ip2net == NULL && nw_descr == NULL) {
1502                 snprintf(err_str,
1503                          sizeof(err_str),
1504                          "\"mandatory parameters not specified.\"");
1505                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
1506                 goto out;
1507         }
1508
1509         if (ip2net != NULL && strlen(ip2net) >= sizeof(buf)) {
1510                 snprintf(err_str,
1511                          sizeof(err_str),
1512                          "\"ip2net string too long %d\"",
1513                                 (int)strlen(ip2net));
1514                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
1515                 goto out;
1516         }
1517
1518         if (ip2net != NULL) {
1519                 if (tunables != NULL)
1520                         len = sizeof(struct lnet_ioctl_config_ni) +
1521                               sizeof(struct lnet_ioctl_config_lnd_tunables);
1522                 else
1523                         len = sizeof(struct lnet_ioctl_config_ni);
1524                 data = calloc(1, len);
1525                 if (!data) {
1526                         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
1527                         goto out;
1528                 }
1529                 conf = (struct lnet_ioctl_config_ni*) data;
1530                 if (tunables != NULL)
1531                         tun = (struct lnet_ioctl_config_lnd_tunables*)
1532                                 (data + sizeof(*conf));
1533
1534                 LIBCFS_IOC_INIT_V2(*conf, lic_cfg_hdr);
1535                 conf->lic_cfg_hdr.ioc_len = len;
1536                 strncpy(conf->lic_legacy_ip2nets, ip2net,
1537                         LNET_MAX_STR_LEN);
1538
1539                 if (global_cpts != NULL) {
1540                         count = cfs_expr_list_values(global_cpts,
1541                                                      LNET_MAX_SHOW_NUM_CPT,
1542                                                      &cpt_array);
1543                         if (count > 0) {
1544                                 memcpy(conf->lic_cpts, cpt_array,
1545                                        sizeof(cpt_array[0]) * LNET_MAX_STR_LEN);
1546                                 free(cpt_array);
1547                         } else {
1548                                 count = 0;
1549                         }
1550                 } else {
1551                         count = 0;
1552                 }
1553
1554                 conf->lic_ncpts = count;
1555
1556                 if (tunables != NULL)
1557                         memcpy(tun, tunables, sizeof(*tunables));
1558
1559                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_LOCAL_NI, data);
1560                 if (rc < 0) {
1561                         rc = -errno;
1562                         snprintf(err_str,
1563                                 sizeof(err_str),
1564                                 "\"cannot add network: %s\"", strerror(errno));
1565                         goto out;
1566                 }
1567
1568                 goto out;
1569         }
1570
1571         if (LNET_NETTYP(nw_descr->nw_id) == LOLND) {
1572                 rc = LUSTRE_CFG_RC_NO_ERR;
1573                 goto out;
1574         }
1575
1576         if (nw_descr->nw_id == LNET_NIDNET(LNET_NID_ANY)) {
1577                 snprintf(err_str,
1578                         sizeof(err_str),
1579                         "\"cannot parse net '%s'\"",
1580                         libcfs_net2str(nw_descr->nw_id));
1581                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1582                 goto out;
1583         }
1584
1585         if (list_empty(&nw_descr->nw_intflist)) {
1586                 snprintf(err_str,
1587                         sizeof(err_str),
1588                         "\"no interface name provided\"");
1589                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1590                 goto out;
1591         }
1592
1593         rc = lustre_lnet_intf2nids(nw_descr, &nids, &nnids);
1594         if (rc != 0) {
1595                 snprintf(err_str, sizeof(err_str),
1596                          "\"bad parameter\"");
1597                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1598                 goto out;
1599         }
1600
1601         rc = lustre_lnet_ioctl_config_ni(&nw_descr->nw_intflist,
1602                                          tunables, global_cpts, nids,
1603                                          err_str);
1604
1605 out:
1606         if (nw_descr != NULL) {
1607                 list_for_each_entry_safe(intf_descr, tmp,
1608                                          &nw_descr->nw_intflist,
1609                                          intf_on_network) {
1610                         list_del(&intf_descr->intf_on_network);
1611                         free_intf_descr(intf_descr);
1612                 }
1613         }
1614
1615         cYAML_build_error(rc, seq_no, ADD_CMD, "net", err_str, err_rc);
1616
1617         if (nids)
1618                 free(nids);
1619
1620         if (data)
1621                 free(data);
1622
1623         return rc;
1624 }
1625
1626 int lustre_lnet_del_ni(struct lnet_dlc_network_descr *nw_descr,
1627                        int seq_no, struct cYAML **err_rc)
1628 {
1629         struct lnet_ioctl_config_ni data;
1630         int rc = LUSTRE_CFG_RC_NO_ERR, i;
1631         char err_str[LNET_MAX_STR_LEN];
1632         lnet_nid_t *nids = NULL;
1633         __u32 nnids = 0;
1634         struct lnet_dlc_intf_descr *intf_descr, *tmp;
1635
1636         snprintf(err_str, sizeof(err_str), "\"success\"");
1637
1638         if (nw_descr == NULL) {
1639                 snprintf(err_str,
1640                          sizeof(err_str),
1641                          "\"missing mandatory parameter\"");
1642                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
1643                 goto out;
1644         }
1645
1646         if (LNET_NETTYP(nw_descr->nw_id) == LOLND)
1647                 return LUSTRE_CFG_RC_NO_ERR;
1648
1649         if (nw_descr->nw_id == LNET_NIDNET(LNET_NID_ANY)) {
1650                 snprintf(err_str,
1651                          sizeof(err_str),
1652                          "\"cannot parse net '%s'\"",
1653                          libcfs_net2str(nw_descr->nw_id));
1654                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1655                 goto out;
1656         }
1657
1658         rc = lustre_lnet_intf2nids(nw_descr, &nids, &nnids);
1659         if (rc != 0) {
1660                 snprintf(err_str, sizeof(err_str),
1661                          "\"bad parameter\"");
1662                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1663                 goto out;
1664         }
1665
1666         /*
1667          * no interfaces just the nw_id is specified
1668          */
1669         if (nnids == 0) {
1670                 nids = calloc(1, sizeof(*nids));
1671                 if (nids == NULL) {
1672                         snprintf(err_str, sizeof(err_str),
1673                                 "\"out of memory\"");
1674                         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
1675                         goto out;
1676                 }
1677                 nids[0] = LNET_MKNID(nw_descr->nw_id, 0);
1678                 nnids = 1;
1679         }
1680
1681         for (i = 0; i < nnids; i++) {
1682                 LIBCFS_IOC_INIT_V2(data, lic_cfg_hdr);
1683                 data.lic_nid = nids[i];
1684
1685                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DEL_LOCAL_NI, &data);
1686                 if (rc < 0) {
1687                         rc = -errno;
1688                         snprintf(err_str,
1689                                 sizeof(err_str),
1690                                 "\"cannot del network: %s\"", strerror(errno));
1691                 }
1692         }
1693
1694         list_for_each_entry_safe(intf_descr, tmp, &nw_descr->nw_intflist,
1695                                  intf_on_network) {
1696                 list_del(&intf_descr->intf_on_network);
1697                 free_intf_descr(intf_descr);
1698         }
1699
1700 out:
1701         cYAML_build_error(rc, seq_no, DEL_CMD, "net", err_str, err_rc);
1702
1703         if (nids != NULL)
1704                 free(nids);
1705
1706         return rc;
1707 }
1708
1709 int lustre_lnet_show_net(char *nw, int detail, int seq_no,
1710                          struct cYAML **show_rc, struct cYAML **err_rc)
1711 {
1712         char *buf;
1713         struct lnet_ioctl_config_ni *ni_data;
1714         struct lnet_ioctl_config_lnd_tunables *lnd;
1715         struct lnet_ioctl_element_stats *stats;
1716         __u32 net = LNET_NIDNET(LNET_NID_ANY);
1717         __u32 prev_net = LNET_NIDNET(LNET_NID_ANY);
1718         int rc = LUSTRE_CFG_RC_OUT_OF_MEM, i, j;
1719         int l_errno = 0;
1720         struct cYAML *root = NULL, *tunables = NULL,
1721                 *net_node = NULL, *interfaces = NULL,
1722                 *item = NULL, *first_seq = NULL,
1723                 *tmp = NULL, *statistics = NULL;
1724         int str_buf_len = LNET_MAX_SHOW_NUM_CPT * 2;
1725         char str_buf[str_buf_len];
1726         char *pos;
1727         char err_str[LNET_MAX_STR_LEN];
1728         bool exist = false, new_net = true;
1729         int net_num = 0;
1730         size_t buf_size = sizeof(*ni_data) + sizeof(*lnd) + sizeof(*stats);
1731
1732         snprintf(err_str, sizeof(err_str), "\"out of memory\"");
1733
1734         buf = calloc(1, buf_size);
1735         if (buf == NULL)
1736                 goto out;
1737
1738         ni_data = (struct lnet_ioctl_config_ni *)buf;
1739
1740         if (nw != NULL) {
1741                 net = libcfs_str2net(nw);
1742                 if (net == LNET_NIDNET(LNET_NID_ANY)) {
1743                         snprintf(err_str,
1744                                  sizeof(err_str),
1745                                  "\"cannot parse net '%s'\"", nw);
1746                         rc = LUSTRE_CFG_RC_BAD_PARAM;
1747                         goto out;
1748                 }
1749         }
1750
1751         root = cYAML_create_object(NULL, NULL);
1752         if (root == NULL)
1753                 goto out;
1754
1755         net_node = cYAML_create_seq(root, "net");
1756         if (net_node == NULL)
1757                 goto out;
1758
1759         for (i = 0;; i++) {
1760                 pos = str_buf;
1761                 __u32 rc_net;
1762
1763                 memset(buf, 0, buf_size);
1764
1765                 LIBCFS_IOC_INIT_V2(*ni_data, lic_cfg_hdr);
1766                 /*
1767                  * set the ioc_len to the proper value since INIT assumes
1768                  * size of data
1769                  */
1770                 ni_data->lic_cfg_hdr.ioc_len = buf_size;
1771                 ni_data->lic_idx = i;
1772
1773                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_LOCAL_NI, ni_data);
1774                 if (rc != 0) {
1775                         l_errno = errno;
1776                         break;
1777                 }
1778
1779                 rc_net = LNET_NIDNET(ni_data->lic_nid);
1780
1781                 /* filter on provided data */
1782                 if (net != LNET_NIDNET(LNET_NID_ANY) &&
1783                     net != rc_net)
1784                         continue;
1785
1786                 /* default rc to -1 in case we hit the goto */
1787                 rc = -1;
1788                 exist = true;
1789
1790                 stats = (struct lnet_ioctl_element_stats *)ni_data->lic_bulk;
1791                 lnd = (struct lnet_ioctl_config_lnd_tunables *)
1792                         (ni_data->lic_bulk + sizeof(*stats));
1793
1794                 if (rc_net != prev_net) {
1795                         prev_net = rc_net;
1796                         new_net = true;
1797                         net_num++;
1798                 }
1799
1800                 if (new_net) {
1801                         if (!cYAML_create_string(net_node, "net type",
1802                                                  libcfs_net2str(rc_net)))
1803                                 goto out;
1804
1805                         tmp = cYAML_create_seq(net_node, "local NI(s)");
1806                         if (tmp == NULL)
1807                                 goto out;
1808                         new_net = false;
1809                 }
1810
1811                 /* create the tree to be printed. */
1812                 item = cYAML_create_seq_item(tmp);
1813                 if (item == NULL)
1814                         goto out;
1815
1816                 if (first_seq == NULL)
1817                         first_seq = item;
1818
1819                 if (cYAML_create_string(item, "nid",
1820                                         libcfs_nid2str(ni_data->lic_nid)) == NULL)
1821                         goto out;
1822
1823                 if (cYAML_create_string(item,
1824                                         "status",
1825                                         (ni_data->lic_status ==
1826                                           LNET_NI_STATUS_UP) ?
1827                                             "up" : "down") == NULL)
1828                         goto out;
1829
1830                 /* don't add interfaces unless there is at least one
1831                  * interface */
1832                 if (strlen(ni_data->lic_ni_intf[0]) > 0) {
1833                         interfaces = cYAML_create_object(item, "interfaces");
1834                         if (interfaces == NULL)
1835                                 goto out;
1836
1837                         for (j = 0; j < LNET_NUM_INTERFACES; j++) {
1838                                 if (strlen(ni_data->lic_ni_intf[j]) > 0) {
1839                                         snprintf(str_buf,
1840                                                  sizeof(str_buf), "%d", j);
1841                                         if (cYAML_create_string(interfaces,
1842                                                 str_buf,
1843                                                 ni_data->lic_ni_intf[j]) ==
1844                                                         NULL)
1845                                                 goto out;
1846                                 }
1847                         }
1848                 }
1849
1850                 if (detail) {
1851                         char *limit;
1852
1853                         statistics = cYAML_create_object(item, "statistics");
1854                         if (statistics == NULL)
1855                                 goto out;
1856
1857                         if (cYAML_create_number(statistics, "send_count",
1858                                                 stats->iel_send_count)
1859                                                         == NULL)
1860                                 goto out;
1861
1862                         if (cYAML_create_number(statistics, "recv_count",
1863                                                 stats->iel_recv_count)
1864                                                         == NULL)
1865                                 goto out;
1866
1867                         if (cYAML_create_number(statistics, "drop_count",
1868                                                 stats->iel_drop_count)
1869                                                         == NULL)
1870                                 goto out;
1871
1872                         tunables = cYAML_create_object(item, "tunables");
1873                         if (!tunables)
1874                                 goto out;
1875
1876                         rc = lustre_net_show_tunables(tunables, &lnd->lt_cmn);
1877                         if (rc != LUSTRE_CFG_RC_NO_ERR)
1878                                 goto out;
1879
1880                         tunables = cYAML_create_object(item, "lnd tunables");
1881                         if (tunables == NULL)
1882                                 goto out;
1883
1884                         rc = lustre_ni_show_tunables(tunables, LNET_NETTYP(rc_net),
1885                                                      &lnd->lt_tun);
1886                         if (rc != LUSTRE_CFG_RC_NO_ERR)
1887                                 goto out;
1888
1889                         if (cYAML_create_number(item, "tcp bonding",
1890                                                 ni_data->lic_tcp_bonding)
1891                                                         == NULL)
1892                                 goto out;
1893
1894                         if (cYAML_create_number(item, "dev cpt",
1895                                                 ni_data->lic_dev_cpt) == NULL)
1896                                 goto out;
1897
1898                         /* out put the CPTs in the format: "[x,x,x,...]" */
1899                         limit = str_buf + str_buf_len - 3;
1900                         pos += snprintf(pos, limit - pos, "\"[");
1901                         for (j = 0 ; ni_data->lic_ncpts >= 1 &&
1902                                 j < ni_data->lic_ncpts &&
1903                                 pos < limit; j++) {
1904                                 pos += snprintf(pos, limit - pos,
1905                                                 "%d", ni_data->lic_cpts[j]);
1906                                 if ((j + 1) < ni_data->lic_ncpts)
1907                                         pos += snprintf(pos, limit - pos, ",");
1908                         }
1909                         pos += snprintf(pos, 3, "]\"");
1910
1911                         if (ni_data->lic_ncpts >= 1 &&
1912                             cYAML_create_string(item, "CPT",
1913                                                 str_buf) == NULL)
1914                                 goto out;
1915                 }
1916         }
1917
1918         /* Print out the net information only if show_rc is not provided */
1919         if (show_rc == NULL)
1920                 cYAML_print_tree(root);
1921
1922         if (l_errno != ENOENT) {
1923                 snprintf(err_str,
1924                          sizeof(err_str),
1925                          "\"cannot get networks: %s\"",
1926                          strerror(l_errno));
1927                 rc = -l_errno;
1928                 goto out;
1929         } else
1930                 rc = LUSTRE_CFG_RC_NO_ERR;
1931
1932         snprintf(err_str, sizeof(err_str), "\"success\"");
1933 out:
1934         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR || !exist) {
1935                 cYAML_free_tree(root);
1936         } else if (show_rc != NULL && *show_rc != NULL) {
1937                 struct cYAML *show_node;
1938                 /* find the net node, if one doesn't exist
1939                  * then insert one.  Otherwise add to the one there
1940                  */
1941                 show_node = cYAML_get_object_item(*show_rc, "net");
1942                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
1943                         cYAML_insert_child(show_node, first_seq);
1944                         free(net_node);
1945                         free(root);
1946                 } else if (show_node == NULL) {
1947                         cYAML_insert_sibling((*show_rc)->cy_child,
1948                                                 net_node);
1949                         free(root);
1950                 } else {
1951                         cYAML_free_tree(root);
1952                 }
1953         } else {
1954                 *show_rc = root;
1955         }
1956
1957         cYAML_build_error(rc, seq_no, SHOW_CMD, "net", err_str, err_rc);
1958
1959         return rc;
1960 }
1961
1962 int lustre_lnet_enable_routing(int enable, int seq_no, struct cYAML **err_rc)
1963 {
1964         struct lnet_ioctl_config_data data;
1965         int rc = LUSTRE_CFG_RC_NO_ERR;
1966         char err_str[LNET_MAX_STR_LEN];
1967
1968         snprintf(err_str, sizeof(err_str), "\"success\"");
1969
1970         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
1971         data.cfg_config_u.cfg_buffers.buf_enable = (enable) ? 1 : 0;
1972
1973         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_CONFIG_RTR, &data);
1974         if (rc != 0) {
1975                 rc = -errno;
1976                 snprintf(err_str,
1977                          sizeof(err_str),
1978                          "\"cannot %s routing %s\"",
1979                          (enable) ? "enable" : "disable", strerror(errno));
1980                 goto out;
1981         }
1982
1983 out:
1984         cYAML_build_error(rc, seq_no,
1985                          (enable) ? ADD_CMD : DEL_CMD,
1986                          "routing", err_str, err_rc);
1987
1988         return rc;
1989 }
1990
1991 int lustre_lnet_config_numa_range(int range, int seq_no, struct cYAML **err_rc)
1992 {
1993         struct lnet_ioctl_numa_range data;
1994         int rc = LUSTRE_CFG_RC_NO_ERR;
1995         char err_str[LNET_MAX_STR_LEN];
1996
1997         snprintf(err_str, sizeof(err_str), "\"success\"");
1998
1999         if (range < 0) {
2000                 snprintf(err_str,
2001                          sizeof(err_str),
2002                          "\"range must be >= 0\"");
2003                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
2004                 goto out;
2005         }
2006
2007         LIBCFS_IOC_INIT_V2(data, nr_hdr);
2008         data.nr_range = range;
2009
2010         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_SET_NUMA_RANGE, &data);
2011         if (rc != 0) {
2012                 rc = -errno;
2013                 snprintf(err_str,
2014                          sizeof(err_str),
2015                          "\"cannot configure buffers: %s\"", strerror(errno));
2016                 goto out;
2017         }
2018
2019 out:
2020         cYAML_build_error(rc, seq_no, ADD_CMD, "numa_range", err_str, err_rc);
2021
2022         return rc;
2023 }
2024
2025 int lustre_lnet_config_buffers(int tiny, int small, int large, int seq_no,
2026                                struct cYAML **err_rc)
2027 {
2028         struct lnet_ioctl_config_data data;
2029         int rc = LUSTRE_CFG_RC_NO_ERR;
2030         char err_str[LNET_MAX_STR_LEN];
2031
2032         snprintf(err_str, sizeof(err_str), "\"success\"");
2033
2034         /* -1 indicates to ignore changes to this field */
2035         if (tiny < -1 || small < -1 || large < -1) {
2036                 snprintf(err_str,
2037                          sizeof(err_str),
2038                          "\"tiny, small and large must be >= 0\"");
2039                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
2040                 goto out;
2041         }
2042
2043         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
2044         data.cfg_config_u.cfg_buffers.buf_tiny = tiny;
2045         data.cfg_config_u.cfg_buffers.buf_small = small;
2046         data.cfg_config_u.cfg_buffers.buf_large = large;
2047
2048         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_BUF, &data);
2049         if (rc != 0) {
2050                 rc = -errno;
2051                 snprintf(err_str,
2052                          sizeof(err_str),
2053                          "\"cannot configure buffers: %s\"", strerror(errno));
2054                 goto out;
2055         }
2056
2057 out:
2058         cYAML_build_error(rc, seq_no, ADD_CMD, "buf", err_str, err_rc);
2059
2060         return rc;
2061 }
2062
2063 int lustre_lnet_show_routing(int seq_no, struct cYAML **show_rc,
2064                              struct cYAML **err_rc)
2065 {
2066         struct lnet_ioctl_config_data *data;
2067         struct lnet_ioctl_pool_cfg *pool_cfg = NULL;
2068         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
2069         int l_errno = 0;
2070         char *buf;
2071         char *pools[LNET_NRBPOOLS] = {"tiny", "small", "large"};
2072         int buf_count[LNET_NRBPOOLS] = {0};
2073         struct cYAML *root = NULL, *pools_node = NULL,
2074                      *type_node = NULL, *item = NULL, *cpt = NULL,
2075                      *first_seq = NULL, *buffers = NULL;
2076         int i, j;
2077         char err_str[LNET_MAX_STR_LEN];
2078         char node_name[LNET_MAX_STR_LEN];
2079         bool exist = false;
2080
2081         snprintf(err_str, sizeof(err_str), "\"out of memory\"");
2082
2083         buf = calloc(1, sizeof(*data) + sizeof(*pool_cfg));
2084         if (buf == NULL)
2085                 goto out;
2086
2087         data = (struct lnet_ioctl_config_data *)buf;
2088
2089         root = cYAML_create_object(NULL, NULL);
2090         if (root == NULL)
2091                 goto out;
2092
2093         pools_node = cYAML_create_seq(root, "routing");
2094         if (pools_node == NULL)
2095                 goto out;
2096
2097         for (i = 0;; i++) {
2098                 LIBCFS_IOC_INIT_V2(*data, cfg_hdr);
2099                 data->cfg_hdr.ioc_len = sizeof(struct lnet_ioctl_config_data) +
2100                                         sizeof(struct lnet_ioctl_pool_cfg);
2101                 data->cfg_count = i;
2102
2103                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_BUF, data);
2104                 if (rc != 0) {
2105                         l_errno = errno;
2106                         break;
2107                 }
2108
2109                 exist = true;
2110
2111                 pool_cfg = (struct lnet_ioctl_pool_cfg *)data->cfg_bulk;
2112
2113                 snprintf(node_name, sizeof(node_name), "cpt[%d]", i);
2114                 item = cYAML_create_seq_item(pools_node);
2115                 if (item == NULL)
2116                         goto out;
2117
2118                 if (first_seq == NULL)
2119                         first_seq = item;
2120
2121                 cpt = cYAML_create_object(item, node_name);
2122                 if (cpt == NULL)
2123                         goto out;
2124
2125                 /* create the tree  and print */
2126                 for (j = 0; j < LNET_NRBPOOLS; j++) {
2127                         type_node = cYAML_create_object(cpt, pools[j]);
2128                         if (type_node == NULL)
2129                                 goto out;
2130                         if (cYAML_create_number(type_node, "npages",
2131                                                 pool_cfg->pl_pools[j].pl_npages)
2132                             == NULL)
2133                                 goto out;
2134                         if (cYAML_create_number(type_node, "nbuffers",
2135                                                 pool_cfg->pl_pools[j].
2136                                                   pl_nbuffers) == NULL)
2137                                 goto out;
2138                         if (cYAML_create_number(type_node, "credits",
2139                                                 pool_cfg->pl_pools[j].
2140                                                    pl_credits) == NULL)
2141                                 goto out;
2142                         if (cYAML_create_number(type_node, "mincredits",
2143                                                 pool_cfg->pl_pools[j].
2144                                                    pl_mincredits) == NULL)
2145                                 goto out;
2146                         /* keep track of the total count for each of the
2147                          * tiny, small and large buffers */
2148                         buf_count[j] += pool_cfg->pl_pools[j].pl_nbuffers;
2149                 }
2150         }
2151
2152         if (pool_cfg != NULL) {
2153                 item = cYAML_create_seq_item(pools_node);
2154                 if (item == NULL)
2155                         goto out;
2156
2157                 if (cYAML_create_number(item, "enable", pool_cfg->pl_routing) ==
2158                     NULL)
2159                         goto out;
2160         }
2161
2162         /* create a buffers entry in the show. This is necessary so that
2163          * if the YAML output is used to configure a node, the buffer
2164          * configuration takes hold */
2165         buffers = cYAML_create_object(root, "buffers");
2166         if (buffers == NULL)
2167                 goto out;
2168
2169         for (i = 0; i < LNET_NRBPOOLS; i++) {
2170                 if (cYAML_create_number(buffers, pools[i], buf_count[i]) == NULL)
2171                         goto out;
2172         }
2173
2174         if (show_rc == NULL)
2175                 cYAML_print_tree(root);
2176
2177         if (l_errno != ENOENT) {
2178                 snprintf(err_str,
2179                          sizeof(err_str),
2180                          "\"cannot get routing information: %s\"",
2181                          strerror(l_errno));
2182                 rc = -l_errno;
2183                 goto out;
2184         } else
2185                 rc = LUSTRE_CFG_RC_NO_ERR;
2186
2187         snprintf(err_str, sizeof(err_str), "\"success\"");
2188         rc = LUSTRE_CFG_RC_NO_ERR;
2189
2190 out:
2191         free(buf);
2192         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR || !exist) {
2193                 cYAML_free_tree(root);
2194         } else if (show_rc != NULL && *show_rc != NULL) {
2195                 struct cYAML *routing_node;
2196                 /* there should exist only one routing block and one
2197                  * buffers block. If there already exists a previous one
2198                  * then don't add another */
2199                 routing_node = cYAML_get_object_item(*show_rc, "routing");
2200                 if (routing_node == NULL) {
2201                         cYAML_insert_sibling((*show_rc)->cy_child,
2202                                                 root->cy_child);
2203                         free(root);
2204                 } else {
2205                         cYAML_free_tree(root);
2206                 }
2207         } else {
2208                 *show_rc = root;
2209         }
2210
2211         cYAML_build_error(rc, seq_no, SHOW_CMD, "routing", err_str, err_rc);
2212
2213         return rc;
2214 }
2215
2216 int lustre_lnet_show_peer(char *knid, int detail, int seq_no,
2217                           struct cYAML **show_rc, struct cYAML **err_rc)
2218 {
2219         /*
2220          * TODO: This function is changing in a future patch to accommodate
2221          * PEER_LIST and proper filtering on any nid of the peer
2222          */
2223         struct lnet_ioctl_peer_cfg peer_info;
2224         struct lnet_peer_ni_credit_info *lpni_cri;
2225         struct lnet_ioctl_element_stats *lpni_stats;
2226         int rc = LUSTRE_CFG_RC_OUT_OF_MEM, ncpt = 0, i = 0, j = 0;
2227         int l_errno = 0;
2228         struct cYAML *root = NULL, *peer = NULL, *peer_ni = NULL,
2229                      *first_seq = NULL, *peer_root = NULL, *tmp = NULL;
2230         char err_str[LNET_MAX_STR_LEN];
2231         lnet_nid_t prev_primary_nid = LNET_NID_ANY, primary_nid = LNET_NID_ANY;
2232         int data_size = sizeof(*lpni_cri) + sizeof(*lpni_stats);
2233         char *data = malloc(data_size);
2234         bool new_peer = true;
2235
2236         snprintf(err_str, sizeof(err_str),
2237                  "\"out of memory\"");
2238
2239         if (data == NULL)
2240                 goto out;
2241
2242         /* create struct cYAML root object */
2243         root = cYAML_create_object(NULL, NULL);
2244         if (root == NULL)
2245                 goto out;
2246
2247         peer_root = cYAML_create_seq(root, "peer");
2248         if (peer_root == NULL)
2249                 goto out;
2250
2251         if (knid != NULL)
2252                 primary_nid = libcfs_str2nid(knid);
2253
2254         do {
2255                 for (i = 0;; i++) {
2256                         memset(data, 0, data_size);
2257                         memset(&peer_info, 0, sizeof(peer_info));
2258                         LIBCFS_IOC_INIT_V2(peer_info, prcfg_hdr);
2259                         peer_info.prcfg_hdr.ioc_len = sizeof(peer_info);
2260                         peer_info.prcfg_count = i;
2261                         peer_info.prcfg_bulk = (void *)data;
2262                         peer_info.prcfg_size = data_size;
2263
2264                         rc = l_ioctl(LNET_DEV_ID,
2265                                      IOC_LIBCFS_GET_PEER_NI, &peer_info);
2266                         if (rc != 0) {
2267                                 l_errno = errno;
2268                                 break;
2269                         }
2270
2271                         if (primary_nid != LNET_NID_ANY &&
2272                             primary_nid != peer_info.prcfg_prim_nid)
2273                                         continue;
2274
2275                         lpni_cri = peer_info.prcfg_bulk;
2276                         lpni_stats = peer_info.prcfg_bulk + sizeof(*lpni_cri);
2277
2278                         peer = cYAML_create_seq_item(peer_root);
2279                         if (peer == NULL)
2280                                 goto out;
2281
2282                         if (peer_info.prcfg_prim_nid != prev_primary_nid) {
2283                                 prev_primary_nid = peer_info.prcfg_prim_nid;
2284                                 new_peer = true;
2285                         }
2286
2287                         if (new_peer) {
2288                                 lnet_nid_t pnid = peer_info.prcfg_prim_nid;
2289                                 if (cYAML_create_string(peer, "primary nid",
2290                                                         libcfs_nid2str(pnid))
2291                                     == NULL)
2292                                         goto out;
2293                                 if (cYAML_create_string(peer, "Multi-Rail",
2294                                                         peer_info.prcfg_mr ?
2295                                                         "True" : "False")
2296                                     == NULL)
2297                                         goto out;
2298                                 tmp = cYAML_create_seq(peer, "peer ni");
2299                                 if (tmp == NULL)
2300                                         goto out;
2301                                 new_peer = false;
2302                         }
2303
2304                         if (first_seq == NULL)
2305                                 first_seq = peer;
2306
2307                         peer_ni = cYAML_create_seq_item(tmp);
2308                         if (peer_ni == NULL)
2309                                 goto out;
2310
2311                         if (cYAML_create_string(peer_ni, "nid",
2312                                                 libcfs_nid2str
2313                                                  (peer_info.prcfg_cfg_nid))
2314                             == NULL)
2315                                 goto out;
2316
2317                         if (cYAML_create_string(peer_ni, "state",
2318                                                 lpni_cri->cr_aliveness)
2319                             == NULL)
2320                                 goto out;
2321
2322                         if (!detail)
2323                                 continue;
2324
2325                         if (cYAML_create_number(peer_ni, "max_ni_tx_credits",
2326                                                 lpni_cri->cr_ni_peer_tx_credits)
2327                             == NULL)
2328                                 goto out;
2329
2330                         if (cYAML_create_number(peer_ni, "available_tx_credits",
2331                                                 lpni_cri->cr_peer_tx_credits)
2332                             == NULL)
2333                                 goto out;
2334
2335                         if (cYAML_create_number(peer_ni, "min_tx_credits",
2336                                                 lpni_cri->cr_peer_min_tx_credits)
2337                             == NULL)
2338                                 goto out;
2339
2340                         if (cYAML_create_number(peer_ni, "tx_q_num_of_buf",
2341                                                 lpni_cri->cr_peer_tx_qnob)
2342                             == NULL)
2343                                 goto out;
2344
2345                         if (cYAML_create_number(peer_ni, "available_rtr_credits",
2346                                                 lpni_cri->cr_peer_rtr_credits)
2347                             == NULL)
2348                                 goto out;
2349
2350                         if (cYAML_create_number(peer_ni, "min_rtr_credits",
2351                                                 lpni_cri->cr_peer_min_rtr_credits)
2352                             == NULL)
2353                                 goto out;
2354
2355                         if (cYAML_create_number(peer_ni, "send_count",
2356                                                 lpni_stats->iel_send_count)
2357                             == NULL)
2358                                 goto out;
2359
2360                         if (cYAML_create_number(peer_ni, "recv_count",
2361                                                 lpni_stats->iel_recv_count)
2362                             == NULL)
2363                                 goto out;
2364
2365                         if (cYAML_create_number(peer_ni, "drop_count",
2366                                                 lpni_stats->iel_drop_count)
2367                             == NULL)
2368                                 goto out;
2369
2370                         if (cYAML_create_number(peer_ni, "refcount",
2371                                                 lpni_cri->cr_refcount) == NULL)
2372                                 goto out;
2373                 }
2374
2375                 if (l_errno != ENOENT) {
2376                         snprintf(err_str,
2377                                 sizeof(err_str),
2378                                 "\"cannot get peer information: %s\"",
2379                                 strerror(l_errno));
2380                         rc = -l_errno;
2381                         goto out;
2382                 }
2383
2384                 j++;
2385         } while (j < ncpt);
2386
2387         /* print output iff show_rc is not provided */
2388         if (show_rc == NULL)
2389                 cYAML_print_tree(root);
2390
2391         snprintf(err_str, sizeof(err_str), "\"success\"");
2392         rc = LUSTRE_CFG_RC_NO_ERR;
2393
2394 out:
2395         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
2396                 cYAML_free_tree(root);
2397         } else if (show_rc != NULL && *show_rc != NULL) {
2398                 struct cYAML *show_node;
2399                 /* find the peer node, if one doesn't exist then
2400                  * insert one.  Otherwise add to the one there
2401                  */
2402                 show_node = cYAML_get_object_item(*show_rc,
2403                                                   "peer");
2404                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
2405                         cYAML_insert_child(show_node, first_seq);
2406                         free(peer_root);
2407                         free(root);
2408                 } else if (show_node == NULL) {
2409                         cYAML_insert_sibling((*show_rc)->cy_child,
2410                                              peer_root);
2411                         free(root);
2412                 } else {
2413                         cYAML_free_tree(root);
2414                 }
2415         } else {
2416                 *show_rc = root;
2417         }
2418
2419         cYAML_build_error(rc, seq_no, SHOW_CMD, "peer", err_str,
2420                           err_rc);
2421
2422         return rc;
2423 }
2424
2425 int lustre_lnet_show_numa_range(int seq_no, struct cYAML **show_rc,
2426                                 struct cYAML **err_rc)
2427 {
2428         struct lnet_ioctl_numa_range data;
2429         int rc;
2430         int l_errno;
2431         char err_str[LNET_MAX_STR_LEN];
2432         struct cYAML *root = NULL, *range = NULL;
2433
2434         snprintf(err_str, sizeof(err_str), "\"out of memory\"");
2435
2436         LIBCFS_IOC_INIT_V2(data, nr_hdr);
2437
2438         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_NUMA_RANGE, &data);
2439         if (rc != 0) {
2440                 l_errno = errno;
2441                 snprintf(err_str,
2442                          sizeof(err_str),
2443                          "\"cannot get numa range: %s\"",
2444                          strerror(l_errno));
2445                 rc = -l_errno;
2446                 goto out;
2447         }
2448
2449         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
2450
2451         root = cYAML_create_object(NULL, NULL);
2452         if (root == NULL)
2453                 goto out;
2454
2455         range = cYAML_create_object(root, "numa");
2456         if (range == NULL)
2457                 goto out;
2458
2459         if (cYAML_create_number(range, "range",
2460                                 data.nr_range) == NULL)
2461                 goto out;
2462
2463         if (show_rc == NULL)
2464                 cYAML_print_tree(root);
2465
2466         snprintf(err_str, sizeof(err_str), "\"success\"");
2467         rc = LUSTRE_CFG_RC_NO_ERR;
2468 out:
2469         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
2470                 cYAML_free_tree(root);
2471         } else if (show_rc != NULL && *show_rc != NULL) {
2472                 cYAML_insert_sibling((*show_rc)->cy_child,
2473                                         root->cy_child);
2474                 free(root);
2475         } else {
2476                 *show_rc = root;
2477         }
2478
2479         cYAML_build_error(rc, seq_no, SHOW_CMD, "numa", err_str, err_rc);
2480
2481         return rc;
2482 }
2483
2484 int lustre_lnet_show_stats(int seq_no, struct cYAML **show_rc,
2485                            struct cYAML **err_rc)
2486 {
2487         struct lnet_ioctl_lnet_stats data;
2488         int rc;
2489         int l_errno;
2490         char err_str[LNET_MAX_STR_LEN];
2491         struct cYAML *root = NULL, *stats = NULL;
2492
2493         snprintf(err_str, sizeof(err_str), "\"out of memory\"");
2494
2495         LIBCFS_IOC_INIT_V2(data, st_hdr);
2496
2497         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_LNET_STATS, &data);
2498         if (rc != 0) {
2499                 l_errno = errno;
2500                 snprintf(err_str,
2501                          sizeof(err_str),
2502                          "\"cannot get lnet statistics: %s\"",
2503                          strerror(l_errno));
2504                 rc = -l_errno;
2505                 goto out;
2506         }
2507
2508         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
2509
2510         root = cYAML_create_object(NULL, NULL);
2511         if (root == NULL)
2512                 goto out;
2513
2514         stats = cYAML_create_object(root, "statistics");
2515         if (stats == NULL)
2516                 goto out;
2517
2518         if (cYAML_create_number(stats, "msgs_alloc",
2519                                 data.st_cntrs.msgs_alloc) == NULL)
2520                 goto out;
2521
2522         if (cYAML_create_number(stats, "msgs_max",
2523                                 data.st_cntrs.msgs_max) == NULL)
2524                 goto out;
2525
2526         if (cYAML_create_number(stats, "errors",
2527                                 data.st_cntrs.errors) == NULL)
2528                 goto out;
2529
2530         if (cYAML_create_number(stats, "send_count",
2531                                 data.st_cntrs.send_count) == NULL)
2532                 goto out;
2533
2534         if (cYAML_create_number(stats, "recv_count",
2535                                 data.st_cntrs.recv_count) == NULL)
2536                 goto out;
2537
2538         if (cYAML_create_number(stats, "route_count",
2539                                 data.st_cntrs.route_count) == NULL)
2540                 goto out;
2541
2542         if (cYAML_create_number(stats, "drop_count",
2543                                 data.st_cntrs.drop_count) == NULL)
2544                 goto out;
2545
2546         if (cYAML_create_number(stats, "send_length",
2547                                 data.st_cntrs.send_length) == NULL)
2548                 goto out;
2549
2550         if (cYAML_create_number(stats, "recv_length",
2551                                 data.st_cntrs.recv_length) == NULL)
2552                 goto out;
2553
2554         if (cYAML_create_number(stats, "route_length",
2555                                 data.st_cntrs.route_length) == NULL)
2556                 goto out;
2557
2558         if (cYAML_create_number(stats, "drop_length",
2559                                 data.st_cntrs.drop_length) == NULL)
2560                 goto out;
2561
2562         if (show_rc == NULL)
2563                 cYAML_print_tree(root);
2564
2565         snprintf(err_str, sizeof(err_str), "\"success\"");
2566         rc = LUSTRE_CFG_RC_NO_ERR;
2567 out:
2568         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
2569                 cYAML_free_tree(root);
2570         } else if (show_rc != NULL && *show_rc != NULL) {
2571                 cYAML_insert_sibling((*show_rc)->cy_child,
2572                                         root->cy_child);
2573                 free(root);
2574         } else {
2575                 *show_rc = root;
2576         }
2577
2578         cYAML_build_error(rc, seq_no, SHOW_CMD, "statistics", err_str, err_rc);
2579
2580         return rc;
2581 }
2582
2583 typedef int (*cmd_handler_t)(struct cYAML *tree,
2584                              struct cYAML **show_rc,
2585                              struct cYAML **err_rc);
2586
2587 static int handle_yaml_config_route(struct cYAML *tree, struct cYAML **show_rc,
2588                                     struct cYAML **err_rc)
2589 {
2590         struct cYAML *net, *gw, *hop, *prio, *seq_no;
2591
2592         net = cYAML_get_object_item(tree, "net");
2593         gw = cYAML_get_object_item(tree, "gateway");
2594         hop = cYAML_get_object_item(tree, "hop");
2595         prio = cYAML_get_object_item(tree, "priority");
2596         seq_no = cYAML_get_object_item(tree, "seq_no");
2597
2598         return lustre_lnet_config_route((net) ? net->cy_valuestring : NULL,
2599                                         (gw) ? gw->cy_valuestring : NULL,
2600                                         (hop) ? hop->cy_valueint : -1,
2601                                         (prio) ? prio->cy_valueint : -1,
2602                                         (seq_no) ? seq_no->cy_valueint : -1,
2603                                         err_rc);
2604 }
2605
2606 static void yaml_free_string_array(char **array, int num)
2607 {
2608         int i;
2609         char **sub_array = array;
2610
2611         for (i = 0; i < num; i++) {
2612                 if (*sub_array != NULL)
2613                         free(*sub_array);
2614                 sub_array++;
2615         }
2616         if (array)
2617                 free(array);
2618 }
2619
2620 /*
2621  *    interfaces:
2622  *        0: <intf_name>['['<expr>']']
2623  *        1: <intf_name>['['<expr>']']
2624  */
2625 static int yaml_copy_intf_info(struct cYAML *intf_tree,
2626                                struct lnet_dlc_network_descr *nw_descr)
2627 {
2628         struct cYAML *child = NULL;
2629         int intf_num = 0, rc = LUSTRE_CFG_RC_NO_ERR;
2630         struct lnet_dlc_intf_descr *intf_descr, *tmp;
2631
2632         if (intf_tree == NULL || nw_descr == NULL)
2633                 return LUSTRE_CFG_RC_BAD_PARAM;
2634
2635         /* now grab all the interfaces and their cpts */
2636         child = intf_tree->cy_child;
2637         while (child != NULL) {
2638                 if (child->cy_valuestring == NULL) {
2639                         child = child->cy_next;
2640                         continue;
2641                 }
2642
2643                 if (strlen(child->cy_valuestring) >= LNET_MAX_STR_LEN)
2644                         goto failed;
2645
2646                 rc = lustre_lnet_add_intf_descr(&nw_descr->nw_intflist,
2647                                                 child->cy_valuestring,
2648                                                 strlen(child->cy_valuestring));
2649                 if (rc != LUSTRE_CFG_RC_NO_ERR)
2650                         goto failed;
2651
2652                 intf_num++;
2653                 child = child->cy_next;
2654         }
2655
2656         if (intf_num == 0)
2657                 return LUSTRE_CFG_RC_MISSING_PARAM;
2658
2659         return intf_num;
2660
2661 failed:
2662         list_for_each_entry_safe(intf_descr, tmp, &nw_descr->nw_intflist,
2663                                  intf_on_network) {
2664                 list_del(&intf_descr->intf_on_network);
2665                 free_intf_descr(intf_descr);
2666         }
2667
2668         return rc;
2669 }
2670
2671 static bool
2672 yaml_extract_cmn_tunables(struct cYAML *tree,
2673                           struct lnet_ioctl_config_lnd_cmn_tunables *tunables,
2674                           struct cfs_expr_list **global_cpts)
2675 {
2676         struct cYAML *tun, *item, *smp;
2677         int rc;
2678
2679         tun = cYAML_get_object_item(tree, "tunables");
2680         if (tun != NULL) {
2681                 item = cYAML_get_object_item(tun, "peer_timeout");
2682                 if (item != NULL)
2683                         tunables->lct_peer_timeout = item->cy_valueint;
2684                 item = cYAML_get_object_item(tun, "peer_credits");
2685                 if (item != NULL)
2686                         tunables->lct_peer_tx_credits = item->cy_valueint;
2687                 item = cYAML_get_object_item(tun, "peer_buffer_credits");
2688                 if (item != NULL)
2689                         tunables->lct_peer_rtr_credits = item->cy_valueint;
2690                 item = cYAML_get_object_item(tun, "credits");
2691                 if (item != NULL)
2692                         tunables->lct_max_tx_credits = item->cy_valueint;
2693                 smp = cYAML_get_object_item(tun, "CPT");
2694                 if (smp != NULL) {
2695                         rc = cfs_expr_list_parse(smp->cy_valuestring,
2696                                                  strlen(smp->cy_valuestring),
2697                                                  0, UINT_MAX, global_cpts);
2698                         if (rc != 0)
2699                                 *global_cpts = NULL;
2700                 }
2701
2702                 return true;
2703         }
2704
2705         return false;
2706 }
2707
2708 static bool
2709 yaml_extract_tunables(struct cYAML *tree,
2710                       struct lnet_ioctl_config_lnd_tunables *tunables,
2711                       struct cfs_expr_list **global_cpts,
2712                       __u32 net_type)
2713 {
2714         bool rc;
2715
2716         rc = yaml_extract_cmn_tunables(tree, &tunables->lt_cmn,
2717                                        global_cpts);
2718
2719         if (!rc)
2720                 return rc;
2721
2722         lustre_yaml_extract_lnd_tunables(tree, net_type,
2723                                          &tunables->lt_tun);
2724
2725         return rc;
2726 }
2727
2728 /*
2729  * net:
2730  *    - net type: <net>[<NUM>]
2731   *      local NI(s):
2732  *        - nid: <ip>@<net>[<NUM>]
2733  *          status: up
2734  *          interfaces:
2735  *               0: <intf_name>['['<expr>']']
2736  *               1: <intf_name>['['<expr>']']
2737  *        tunables:
2738  *               peer_timeout: <NUM>
2739  *               peer_credits: <NUM>
2740  *               peer_buffer_credits: <NUM>
2741  *               credits: <NUM>
2742 *         lnd tunables:
2743  *               peercredits_hiw: <NUM>
2744  *               map_on_demand: <NUM>
2745  *               concurrent_sends: <NUM>
2746  *               fmr_pool_size: <NUM>
2747  *               fmr_flush_trigger: <NUM>
2748  *               fmr_cache: <NUM>
2749  *
2750  * At least one interface is required. If no interfaces are provided the
2751  * network interface can not be configured.
2752  */
2753 static int handle_yaml_config_ni(struct cYAML *tree, struct cYAML **show_rc,
2754                                  struct cYAML **err_rc)
2755 {
2756         struct cYAML *net, *intf, *seq_no, *ip2net = NULL, *local_nis = NULL,
2757                      *item = NULL;
2758         int num_entries = 0, rc;
2759         struct lnet_dlc_network_descr nw_descr;
2760         struct cfs_expr_list *global_cpts = NULL;
2761         struct lnet_ioctl_config_lnd_tunables tunables;
2762         bool found = false;
2763
2764         memset(&tunables, 0, sizeof(tunables));
2765
2766         INIT_LIST_HEAD(&nw_descr.network_on_rule);
2767         INIT_LIST_HEAD(&nw_descr.nw_intflist);
2768
2769         ip2net = cYAML_get_object_item(tree, "ip2net");
2770         net = cYAML_get_object_item(tree, "net type");
2771         if (net)
2772                 nw_descr.nw_id = libcfs_str2net(net->cy_valuestring);
2773         else
2774                 nw_descr.nw_id = LOLND;
2775
2776         /*
2777          * if neither net nor ip2nets are present, then we can not
2778          * configure the network.
2779          */
2780         if (!net && !ip2net)
2781                 return LUSTRE_CFG_RC_MISSING_PARAM;
2782
2783         local_nis = cYAML_get_object_item(tree, "local NI(s)");
2784         if (local_nis == NULL)
2785                 return LUSTRE_CFG_RC_MISSING_PARAM;
2786
2787         if (!cYAML_is_sequence(local_nis))
2788                 return LUSTRE_CFG_RC_BAD_PARAM;
2789
2790         while (cYAML_get_next_seq_item(local_nis, &item) != NULL) {
2791                 intf = cYAML_get_object_item(item, "interfaces");
2792                 if (intf == NULL)
2793                         continue;
2794                 num_entries = yaml_copy_intf_info(intf, &nw_descr);
2795                 if (num_entries <= 0) {
2796                         cYAML_build_error(num_entries, -1, "ni", "add",
2797                                         "bad interface list",
2798                                         err_rc);
2799                         return LUSTRE_CFG_RC_BAD_PARAM;
2800                 }
2801         }
2802
2803         found = yaml_extract_tunables(tree, &tunables, &global_cpts,
2804                                       LNET_NETTYP(nw_descr.nw_id));
2805         seq_no = cYAML_get_object_item(tree, "seq_no");
2806
2807         rc = lustre_lnet_config_ni(&nw_descr,
2808                                    global_cpts,
2809                                    (ip2net) ? ip2net->cy_valuestring : NULL,
2810                                    (found) ? &tunables: NULL,
2811                                    (seq_no) ? seq_no->cy_valueint : -1,
2812                                    err_rc);
2813
2814         if (global_cpts != NULL)
2815                 cfs_expr_list_free(global_cpts);
2816
2817         return rc;
2818 }
2819
2820 /*
2821  * ip2nets:
2822  *  - net-spec: <tcp|o2ib|gni>[NUM]
2823  *    interfaces:
2824  *        0: <intf name>['['<expr>']']
2825  *        1: <intf name>['['<expr>']']
2826  *    ip-range:
2827  *        0: <expr.expr.expr.expr>
2828  *        1: <expr.expr.expr.expr>
2829  */
2830 static int handle_yaml_config_ip2nets(struct cYAML *tree,
2831                                       struct cYAML **show_rc,
2832                                       struct cYAML **err_rc)
2833 {
2834         struct cYAML *net, *ip_range, *item = NULL, *intf = NULL,
2835                      *seq_no = NULL;
2836         struct lustre_lnet_ip2nets ip2nets;
2837         struct lustre_lnet_ip_range_descr *ip_range_descr = NULL,
2838                                           *tmp = NULL;
2839         int rc = LUSTRE_CFG_RC_NO_ERR;
2840         struct cfs_expr_list *global_cpts = NULL;
2841         struct cfs_expr_list *el, *el_tmp;
2842         struct lnet_ioctl_config_lnd_tunables tunables;
2843         struct lnet_dlc_intf_descr *intf_descr, *intf_tmp;
2844         bool found = false;
2845
2846         memset(&tunables, 0, sizeof(tunables));
2847
2848         /* initialize all lists */
2849         INIT_LIST_HEAD(&ip2nets.ip2nets_ip_ranges);
2850         INIT_LIST_HEAD(&ip2nets.ip2nets_net.network_on_rule);
2851         INIT_LIST_HEAD(&ip2nets.ip2nets_net.nw_intflist);
2852
2853         net = cYAML_get_object_item(tree, "net-spec");
2854         if (net == NULL)
2855                 return LUSTRE_CFG_RC_BAD_PARAM;
2856
2857         if (net != NULL && net->cy_valuestring == NULL)
2858                 return LUSTRE_CFG_RC_BAD_PARAM;
2859
2860         /* assign the network id */
2861         ip2nets.ip2nets_net.nw_id = libcfs_str2net(net->cy_valuestring);
2862         if (ip2nets.ip2nets_net.nw_id == LNET_NID_ANY)
2863                 return LUSTRE_CFG_RC_BAD_PARAM;
2864
2865         seq_no = cYAML_get_object_item(tree, "seq_no");
2866
2867         intf = cYAML_get_object_item(tree, "interfaces");
2868         if (intf != NULL) {
2869                 rc = yaml_copy_intf_info(intf, &ip2nets.ip2nets_net);
2870                 if (rc <= 0)
2871                         return LUSTRE_CFG_RC_BAD_PARAM;
2872         }
2873
2874         ip_range = cYAML_get_object_item(tree, "ip-range");
2875         if (ip_range != NULL) {
2876                 item = ip_range->cy_child;
2877                 while (item != NULL) {
2878                         if (item->cy_valuestring == NULL) {
2879                                 item = item->cy_next;
2880                                 continue;
2881                         }
2882
2883                         rc = lustre_lnet_add_ip_range(&ip2nets.ip2nets_ip_ranges,
2884                                                       item->cy_valuestring);
2885
2886                         if (rc != LUSTRE_CFG_RC_NO_ERR)
2887                                 goto out;
2888
2889                         item = item->cy_next;
2890                 }
2891         }
2892
2893         found = yaml_extract_tunables(tree, &tunables, &global_cpts,
2894                                       LNET_NETTYP(ip2nets.ip2nets_net.nw_id));
2895
2896         rc = lustre_lnet_config_ip2nets(&ip2nets,
2897                         (found) ? &tunables : NULL,
2898                         global_cpts,
2899                         (seq_no) ? seq_no->cy_valueint : -1,
2900                         err_rc);
2901
2902         /*
2903          * don't stop because there was no match. Continue processing the
2904          * rest of the rules. If non-match then nothing is configured
2905          */
2906         if (rc == LUSTRE_CFG_RC_NO_MATCH)
2907                 rc = LUSTRE_CFG_RC_NO_ERR;
2908 out:
2909         list_for_each_entry_safe(intf_descr, intf_tmp,
2910                                  &ip2nets.ip2nets_net.nw_intflist,
2911                                  intf_on_network) {
2912                 list_del(&intf_descr->intf_on_network);
2913                 free_intf_descr(intf_descr);
2914         }
2915
2916         list_for_each_entry_safe(ip_range_descr, tmp,
2917                                  &ip2nets.ip2nets_ip_ranges,
2918                                  ipr_entry) {
2919                 list_del(&ip_range_descr->ipr_entry);
2920                 list_for_each_entry_safe(el, el_tmp, &ip_range_descr->ipr_expr,
2921                                          el_link) {
2922                         list_del(&el->el_link);
2923                         cfs_expr_list_free(el);
2924                 }
2925                 free(ip_range_descr);
2926         }
2927
2928         return rc;
2929 }
2930
2931 static int handle_yaml_del_ni(struct cYAML *tree, struct cYAML **show_rc,
2932                               struct cYAML **err_rc)
2933 {
2934         struct cYAML *net = NULL, *intf = NULL, *seq_no = NULL, *item = NULL,
2935                      *local_nis = NULL;
2936         int num_entries, rc;
2937         struct lnet_dlc_network_descr nw_descr;
2938
2939         INIT_LIST_HEAD(&nw_descr.network_on_rule);
2940         INIT_LIST_HEAD(&nw_descr.nw_intflist);
2941
2942         net = cYAML_get_object_item(tree, "net type");
2943         if (net != NULL)
2944                 nw_descr.nw_id = libcfs_str2net(net->cy_valuestring);
2945
2946         local_nis = cYAML_get_object_item(tree, "local NI(s)");
2947         if (local_nis == NULL)
2948                 return LUSTRE_CFG_RC_MISSING_PARAM;
2949
2950         if (!cYAML_is_sequence(local_nis))
2951                 return LUSTRE_CFG_RC_BAD_PARAM;
2952
2953         while (cYAML_get_next_seq_item(local_nis, &item) != NULL) {
2954                 intf = cYAML_get_object_item(item, "interfaces");
2955                 if (intf == NULL)
2956                         continue;
2957                 num_entries = yaml_copy_intf_info(intf, &nw_descr);
2958                 if (num_entries <= 0) {
2959                         cYAML_build_error(num_entries, -1, "ni", "add",
2960                                         "bad interface list",
2961                                         err_rc);
2962                         return LUSTRE_CFG_RC_BAD_PARAM;
2963                 }
2964         }
2965
2966         seq_no = cYAML_get_object_item(tree, "seq_no");
2967
2968         rc = lustre_lnet_del_ni((net) ? &nw_descr : NULL,
2969                                 (seq_no) ? seq_no->cy_valueint : -1,
2970                                 err_rc);
2971
2972         return rc;
2973 }
2974
2975 static int yaml_copy_peer_nids(struct cYAML *nids_entry, char ***nidsppp,
2976                                char *prim_nid, bool del)
2977 {
2978         struct cYAML *child = NULL, *entry = NULL;
2979         char **nids = NULL;
2980         int num = 0, rc = LUSTRE_CFG_RC_NO_ERR;
2981
2982         if (cYAML_is_sequence(nids_entry)) {
2983                 while (cYAML_get_next_seq_item(nids_entry, &child)) {
2984                         entry = cYAML_get_object_item(child, "nid");
2985                         /* don't count an empty entry */
2986                         if (!entry || !entry->cy_valuestring)
2987                                 continue;
2988
2989                         if (prim_nid &&
2990                             (strcmp(entry->cy_valuestring, prim_nid)
2991                                         == 0) && del) {
2992                                 /*
2993                                  * primary nid is present in the list of
2994                                  * nids so that means we want to delete
2995                                  * the entire peer, so no need to go
2996                                  * further. Just delete the entire peer.
2997                                  */
2998                                 return 0;
2999                         }
3000
3001                         num++;
3002                 }
3003         }
3004
3005         if (num == 0)
3006                 return LUSTRE_CFG_RC_MISSING_PARAM;
3007
3008         nids = calloc(sizeof(*nids), num);
3009         if (!nids)
3010                 return LUSTRE_CFG_RC_OUT_OF_MEM;
3011
3012         /* now grab all the nids */
3013         num = 0;
3014         child = NULL;
3015         while (cYAML_get_next_seq_item(nids_entry, &child)) {
3016                 entry = cYAML_get_object_item(child, "nid");
3017                 if (!entry || !entry->cy_valuestring)
3018                         continue;
3019
3020                 nids[num] = calloc(strlen(entry->cy_valuestring) + 1, 1);
3021                 if (!nids[num]) {
3022                         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
3023                         goto failed;
3024                 }
3025                 strncpy(nids[num], entry->cy_valuestring,
3026                         strlen(entry->cy_valuestring));
3027                 num++;
3028         }
3029         rc = num;
3030
3031         *nidsppp = nids;
3032         return rc;
3033
3034 failed:
3035         if (nids != NULL)
3036                 yaml_free_string_array(nids, num);
3037         *nidsppp = NULL;
3038         return rc;
3039 }
3040
3041 static int handle_yaml_config_peer(struct cYAML *tree, struct cYAML **show_rc,
3042                                    struct cYAML **err_rc)
3043 {
3044         char **nids = NULL;
3045         int num, rc;
3046         struct cYAML *seq_no, *prim_nid, *non_mr, *ip2nets, *peer_nis;
3047         char err_str[LNET_MAX_STR_LEN];
3048
3049         seq_no = cYAML_get_object_item(tree, "seq_no");
3050         prim_nid = cYAML_get_object_item(tree, "primary nid");
3051         non_mr = cYAML_get_object_item(tree, "non_mr");
3052         ip2nets = cYAML_get_object_item(tree, "ip2nets");
3053         peer_nis = cYAML_get_object_item(tree, "peer ni");
3054
3055         if (ip2nets && (prim_nid || peer_nis)) {
3056                 rc = LUSTRE_CFG_RC_BAD_PARAM;
3057                 snprintf(err_str, sizeof(err_str),
3058                          "ip2nets can not be specified along side prim_nid"
3059                          " or peer ni fields");
3060                 cYAML_build_error(rc, (seq_no) ? seq_no->cy_valueint : -1,
3061                                   ADD_CMD, "peer", err_str, err_rc);
3062                 return rc;
3063         }
3064
3065         num = yaml_copy_peer_nids((ip2nets) ? ip2nets : peer_nis, &nids,
3066                                   (prim_nid) ? prim_nid->cy_valuestring : NULL,
3067                                    false);
3068
3069         if (num < 0) {
3070                 snprintf(err_str, sizeof(err_str),
3071                          "error copying nids from YAML block");
3072                 cYAML_build_error(num, (seq_no) ? seq_no->cy_valueint : -1,
3073                                   ADD_CMD, "peer", err_str, err_rc);
3074                 return num;
3075         }
3076
3077         rc = lustre_lnet_config_peer_nid((prim_nid) ? prim_nid->cy_valuestring : NULL,
3078                                          nids, num,
3079                                          (non_mr) ? false : true,
3080                                          (ip2nets) ? true : false,
3081                                          (seq_no) ? seq_no->cy_valueint : -1,
3082                                          err_rc);
3083
3084         yaml_free_string_array(nids, num);
3085         return rc;
3086 }
3087
3088 static int handle_yaml_del_peer(struct cYAML *tree, struct cYAML **show_rc,
3089                                 struct cYAML **err_rc)
3090 {
3091         char **nids = NULL;
3092         int num, rc;
3093         struct cYAML *seq_no, *prim_nid, *ip2nets, *peer_nis;
3094         char err_str[LNET_MAX_STR_LEN];
3095
3096         seq_no = cYAML_get_object_item(tree, "seq_no");
3097         prim_nid = cYAML_get_object_item(tree, "primary nid");
3098         ip2nets = cYAML_get_object_item(tree, "ip2nets");
3099         peer_nis = cYAML_get_object_item(tree, "peer ni");
3100
3101         if (ip2nets && (prim_nid || peer_nis)) {
3102                 rc = LUSTRE_CFG_RC_BAD_PARAM;
3103                 snprintf(err_str, sizeof(err_str),
3104                          "ip2nets can not be specified along side prim_nid"
3105                          " or peer ni fields");
3106                 cYAML_build_error(rc, (seq_no) ? seq_no->cy_valueint : -1,
3107                                   DEL_CMD, "peer", err_str, err_rc);
3108                 return rc;
3109         }
3110
3111         num = yaml_copy_peer_nids((ip2nets) ? ip2nets : peer_nis , &nids,
3112                                   (prim_nid) ? prim_nid->cy_valuestring : NULL,
3113                                   true);
3114         if (num < 0) {
3115                 snprintf(err_str, sizeof(err_str),
3116                          "error copying nids from YAML block");
3117                 cYAML_build_error(num, (seq_no) ? seq_no->cy_valueint : -1,
3118                                   ADD_CMD, "peer", err_str, err_rc);
3119                 return num;
3120         }
3121
3122         rc = lustre_lnet_del_peer_nid((prim_nid) ? prim_nid->cy_valuestring : NULL,
3123                                       nids, num, (ip2nets) ? true : false,
3124                                       (seq_no) ? seq_no->cy_valueint : -1,
3125                                       err_rc);
3126
3127         yaml_free_string_array(nids, num);
3128         return rc;
3129 }
3130
3131 static int handle_yaml_config_buffers(struct cYAML *tree,
3132                                       struct cYAML **show_rc,
3133                                       struct cYAML **err_rc)
3134 {
3135         int rc;
3136         struct cYAML *tiny, *small, *large, *seq_no;
3137
3138         tiny = cYAML_get_object_item(tree, "tiny");
3139         small = cYAML_get_object_item(tree, "small");
3140         large = cYAML_get_object_item(tree, "large");
3141         seq_no = cYAML_get_object_item(tree, "seq_no");
3142
3143         rc = lustre_lnet_config_buffers((tiny) ? tiny->cy_valueint : -1,
3144                                         (small) ? small->cy_valueint : -1,
3145                                         (large) ? large->cy_valueint : -1,
3146                                         (seq_no) ? seq_no->cy_valueint : -1,
3147                                         err_rc);
3148
3149         return rc;
3150 }
3151
3152 static int handle_yaml_config_routing(struct cYAML *tree,
3153                                       struct cYAML **show_rc,
3154                                       struct cYAML **err_rc)
3155 {
3156         int rc = LUSTRE_CFG_RC_NO_ERR;
3157         struct cYAML *seq_no, *enable;
3158
3159         seq_no = cYAML_get_object_item(tree, "seq_no");
3160         enable = cYAML_get_object_item(tree, "enable");
3161
3162         if (enable) {
3163                 rc = lustre_lnet_enable_routing(enable->cy_valueint,
3164                                                 (seq_no) ?
3165                                                     seq_no->cy_valueint : -1,
3166                                                 err_rc);
3167         }
3168
3169         return rc;
3170 }
3171
3172 static int handle_yaml_del_route(struct cYAML *tree, struct cYAML **show_rc,
3173                                  struct cYAML **err_rc)
3174 {
3175         struct cYAML *net;
3176         struct cYAML *gw;
3177         struct cYAML *seq_no;
3178
3179         net = cYAML_get_object_item(tree, "net");
3180         gw = cYAML_get_object_item(tree, "gateway");
3181         seq_no = cYAML_get_object_item(tree, "seq_no");
3182
3183         return lustre_lnet_del_route((net) ? net->cy_valuestring : NULL,
3184                                      (gw) ? gw->cy_valuestring : NULL,
3185                                      (seq_no) ? seq_no->cy_valueint : -1,
3186                                      err_rc);
3187 }
3188
3189 static int handle_yaml_del_routing(struct cYAML *tree, struct cYAML **show_rc,
3190                                    struct cYAML **err_rc)
3191 {
3192         struct cYAML *seq_no;
3193
3194         seq_no = cYAML_get_object_item(tree, "seq_no");
3195
3196         return lustre_lnet_enable_routing(0, (seq_no) ?
3197                                                 seq_no->cy_valueint : -1,
3198                                         err_rc);
3199 }
3200
3201 static int handle_yaml_show_route(struct cYAML *tree, struct cYAML **show_rc,
3202                                   struct cYAML **err_rc)
3203 {
3204         struct cYAML *net;
3205         struct cYAML *gw;
3206         struct cYAML *hop;
3207         struct cYAML *prio;
3208         struct cYAML *detail;
3209         struct cYAML *seq_no;
3210
3211         net = cYAML_get_object_item(tree, "net");
3212         gw = cYAML_get_object_item(tree, "gateway");
3213         hop = cYAML_get_object_item(tree, "hop");
3214         prio = cYAML_get_object_item(tree, "priority");
3215         detail = cYAML_get_object_item(tree, "detail");
3216         seq_no = cYAML_get_object_item(tree, "seq_no");
3217
3218         return lustre_lnet_show_route((net) ? net->cy_valuestring : NULL,
3219                                       (gw) ? gw->cy_valuestring : NULL,
3220                                       (hop) ? hop->cy_valueint : -1,
3221                                       (prio) ? prio->cy_valueint : -1,
3222                                       (detail) ? detail->cy_valueint : 0,
3223                                       (seq_no) ? seq_no->cy_valueint : -1,
3224                                       show_rc,
3225                                       err_rc);
3226 }
3227
3228 static int handle_yaml_show_net(struct cYAML *tree, struct cYAML **show_rc,
3229                                 struct cYAML **err_rc)
3230 {
3231         struct cYAML *net, *detail, *seq_no;
3232
3233         net = cYAML_get_object_item(tree, "net");
3234         detail = cYAML_get_object_item(tree, "detail");
3235         seq_no = cYAML_get_object_item(tree, "seq_no");
3236
3237         return lustre_lnet_show_net((net) ? net->cy_valuestring : NULL,
3238                                     (detail) ? detail->cy_valueint : 0,
3239                                     (seq_no) ? seq_no->cy_valueint : -1,
3240                                     show_rc,
3241                                     err_rc);
3242 }
3243
3244 static int handle_yaml_show_routing(struct cYAML *tree, struct cYAML **show_rc,
3245                                     struct cYAML **err_rc)
3246 {
3247         struct cYAML *seq_no;
3248
3249         seq_no = cYAML_get_object_item(tree, "seq_no");
3250
3251         return lustre_lnet_show_routing((seq_no) ? seq_no->cy_valueint : -1,
3252                                         show_rc, err_rc);
3253 }
3254
3255 static int handle_yaml_show_peers(struct cYAML *tree, struct cYAML **show_rc,
3256                                   struct cYAML **err_rc)
3257 {
3258         struct cYAML *seq_no, *nid, *detail;
3259
3260         seq_no = cYAML_get_object_item(tree, "seq_no");
3261         detail = cYAML_get_object_item(tree, "detail");
3262         nid = cYAML_get_object_item(tree, "nid");
3263
3264         return lustre_lnet_show_peer((nid) ? nid->cy_valuestring : NULL,
3265                                      (detail) ? detail->cy_valueint : 0,
3266                                      (seq_no) ? seq_no->cy_valueint : -1,
3267                                      show_rc, err_rc);
3268 }
3269
3270 static int handle_yaml_show_stats(struct cYAML *tree, struct cYAML **show_rc,
3271                                   struct cYAML **err_rc)
3272 {
3273         struct cYAML *seq_no;
3274
3275         seq_no = cYAML_get_object_item(tree, "seq_no");
3276
3277         return lustre_lnet_show_stats((seq_no) ? seq_no->cy_valueint : -1,
3278                                       show_rc, err_rc);
3279 }
3280
3281 static int handle_yaml_config_numa(struct cYAML *tree, struct cYAML **show_rc,
3282                                   struct cYAML **err_rc)
3283 {
3284         struct cYAML *seq_no, *range;
3285
3286         seq_no = cYAML_get_object_item(tree, "seq_no");
3287         range = cYAML_get_object_item(tree, "range");
3288
3289         return lustre_lnet_config_numa_range(range ? range->cy_valueint : -1,
3290                                              seq_no ? seq_no->cy_valueint : -1,
3291                                              err_rc);
3292 }
3293
3294 static int handle_yaml_del_numa(struct cYAML *tree, struct cYAML **show_rc,
3295                                struct cYAML **err_rc)
3296 {
3297         struct cYAML *seq_no;
3298
3299         seq_no = cYAML_get_object_item(tree, "seq_no");
3300
3301         return lustre_lnet_config_numa_range(0, seq_no ? seq_no->cy_valueint : -1,
3302                                              err_rc);
3303 }
3304
3305 static int handle_yaml_show_numa(struct cYAML *tree, struct cYAML **show_rc,
3306                                 struct cYAML **err_rc)
3307 {
3308         struct cYAML *seq_no;
3309
3310         seq_no = cYAML_get_object_item(tree, "seq_no");
3311
3312         return lustre_lnet_show_numa_range(seq_no ? seq_no->cy_valueint : -1,
3313                                            show_rc, err_rc);
3314 }
3315
3316 struct lookup_cmd_hdlr_tbl {
3317         char *name;
3318         cmd_handler_t cb;
3319 };
3320
3321 static struct lookup_cmd_hdlr_tbl lookup_config_tbl[] = {
3322         { .name = "route",      .cb = handle_yaml_config_route },
3323         { .name = "net",        .cb = handle_yaml_config_ni },
3324         { .name = "ip2nets",    .cb = handle_yaml_config_ip2nets },
3325         { .name = "peer",       .cb = handle_yaml_config_peer },
3326         { .name = "routing",    .cb = handle_yaml_config_routing },
3327         { .name = "buffers",    .cb = handle_yaml_config_buffers },
3328         { .name = "numa",       .cb = handle_yaml_config_numa },
3329         { .name = NULL } };
3330
3331 static struct lookup_cmd_hdlr_tbl lookup_del_tbl[] = {
3332         { .name = "route",      .cb = handle_yaml_del_route },
3333         { .name = "net",        .cb = handle_yaml_del_ni },
3334         { .name = "peer",       .cb = handle_yaml_del_peer },
3335         { .name = "routing",    .cb = handle_yaml_del_routing },
3336         { .name = "numa",       .cb = handle_yaml_del_numa },
3337         { .name = NULL } };
3338
3339 static struct lookup_cmd_hdlr_tbl lookup_show_tbl[] = {
3340         { .name = "route",      .cb = handle_yaml_show_route },
3341         { .name = "net",        .cb = handle_yaml_show_net },
3342         { .name = "buffers",    .cb = handle_yaml_show_routing },
3343         { .name = "routing",    .cb = handle_yaml_show_routing },
3344         { .name = "peer",       .cb = handle_yaml_show_peers },
3345         { .name = "statistics", .cb = handle_yaml_show_stats },
3346         { .name = "numa",       .cb = handle_yaml_show_numa },
3347         { .name = NULL } };
3348
3349 static cmd_handler_t lookup_fn(char *key,
3350                                struct lookup_cmd_hdlr_tbl *tbl)
3351 {
3352         int i;
3353         if (key == NULL)
3354                 return NULL;
3355
3356         for (i = 0; tbl[i].name != NULL; i++) {
3357                 if (strncmp(key, tbl[i].name, strlen(tbl[i].name)) == 0)
3358                         return tbl[i].cb;
3359         }
3360
3361         return NULL;
3362 }
3363
3364 static int lustre_yaml_cb_helper(char *f, struct lookup_cmd_hdlr_tbl *table,
3365                                  struct cYAML **show_rc, struct cYAML **err_rc)
3366 {
3367         struct cYAML *tree, *item = NULL, *head, *child;
3368         cmd_handler_t cb;
3369         char err_str[LNET_MAX_STR_LEN];
3370         int rc = LUSTRE_CFG_RC_NO_ERR, return_rc = LUSTRE_CFG_RC_NO_ERR;
3371
3372         tree = cYAML_build_tree(f, NULL, 0, err_rc, false);
3373         if (tree == NULL)
3374                 return LUSTRE_CFG_RC_BAD_PARAM;
3375
3376         child = tree->cy_child;
3377         while (child != NULL) {
3378                 cb = lookup_fn(child->cy_string, table);
3379                 if (cb == NULL) {
3380                         snprintf(err_str, sizeof(err_str),
3381                                 "\"call back for '%s' not found\"",
3382                                 child->cy_string);
3383                         cYAML_build_error(LUSTRE_CFG_RC_BAD_PARAM, -1,
3384                                         "yaml", "helper", err_str, err_rc);
3385                         goto out;
3386                 }
3387
3388                 if (cYAML_is_sequence(child)) {
3389                         while ((head = cYAML_get_next_seq_item(child, &item))
3390                                != NULL) {
3391                                 rc = cb(head, show_rc, err_rc);
3392                                 if (rc != LUSTRE_CFG_RC_NO_ERR)
3393                                         return_rc = rc;
3394                         }
3395                 } else {
3396                         rc = cb(child, show_rc, err_rc);
3397                         if (rc != LUSTRE_CFG_RC_NO_ERR)
3398                                 return_rc = rc;
3399                 }
3400                 item = NULL;
3401                 child = child->cy_next;
3402         }
3403
3404 out:
3405         cYAML_free_tree(tree);
3406
3407         return return_rc;
3408 }
3409
3410 int lustre_yaml_config(char *f, struct cYAML **err_rc)
3411 {
3412         return lustre_yaml_cb_helper(f, lookup_config_tbl,
3413                                      NULL, err_rc);
3414 }
3415
3416 int lustre_yaml_del(char *f, struct cYAML **err_rc)
3417 {
3418         return lustre_yaml_cb_helper(f, lookup_del_tbl,
3419                                      NULL, err_rc);
3420 }
3421
3422 int lustre_yaml_show(char *f, struct cYAML **show_rc, struct cYAML **err_rc)
3423 {
3424         return lustre_yaml_cb_helper(f, lookup_show_tbl,
3425                                      show_rc, err_rc);
3426 }
3427