Whamcloud - gitweb
LU-10825 lnet: add ip2nets syntax handling for peer
[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         __u32 net = LNET_NIDNET(LNET_NID_ANY);
732         char err_str[LNET_MAX_STR_LEN];
733
734         snprintf(err_str, sizeof(err_str), "\"Success\"");
735
736         if (nw == NULL || gw == NULL) {
737                 snprintf(err_str,
738                          sizeof(err_str),
739                          "\"missing mandatory parameter(s): '%s'\"",
740                          (nw == NULL && gw == NULL) ? "network, gateway" :
741                          (nw == NULL) ? "network" : "gateway");
742                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
743                 goto out;
744         }
745
746         net = libcfs_str2net(nw);
747         if (net == LNET_NIDNET(LNET_NID_ANY)) {
748                 snprintf(err_str,
749                          sizeof(err_str),
750                          "\"cannot parse net %s\"", nw);
751                 rc = LUSTRE_CFG_RC_BAD_PARAM;
752                 goto out;
753         }
754
755         gateway_nid = libcfs_str2nid(gw);
756         if (gateway_nid == LNET_NID_ANY) {
757                 snprintf(err_str,
758                         sizeof(err_str),
759                         "\"cannot parse gateway NID '%s'\"", gw);
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         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
788         data.cfg_net = net;
789         data.cfg_config_u.cfg_route.rtr_hop = hops;
790         data.cfg_config_u.cfg_route.rtr_priority = prio;
791         data.cfg_nid = gateway_nid;
792
793         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_ROUTE, &data);
794         if (rc != 0) {
795                 rc = -errno;
796                 snprintf(err_str,
797                          sizeof(err_str),
798                          "\"cannot add route: %s\"", strerror(errno));
799                 goto out;
800         }
801
802 out:
803         cYAML_build_error(rc, seq_no, ADD_CMD, "route", err_str, err_rc);
804
805         return rc;
806 }
807
808 int lustre_lnet_del_route(char *nw, char *gw,
809                           int seq_no, struct cYAML **err_rc)
810 {
811         struct lnet_ioctl_config_data data;
812         lnet_nid_t gateway_nid;
813         int rc = LUSTRE_CFG_RC_NO_ERR;
814         __u32 net = LNET_NIDNET(LNET_NID_ANY);
815         char err_str[LNET_MAX_STR_LEN];
816
817         snprintf(err_str, sizeof(err_str), "\"Success\"");
818
819         if (nw == NULL || gw == NULL) {
820                 snprintf(err_str,
821                          sizeof(err_str),
822                          "\"missing mandatory parameter(s): '%s'\"",
823                          (nw == NULL && gw == NULL) ? "network, gateway" :
824                          (nw == NULL) ? "network" : "gateway");
825                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
826                 goto out;
827         }
828
829         net = libcfs_str2net(nw);
830         if (net == LNET_NIDNET(LNET_NID_ANY)) {
831                 snprintf(err_str,
832                          sizeof(err_str),
833                          "\"cannot parse net '%s'\"", nw);
834                 rc = LUSTRE_CFG_RC_BAD_PARAM;
835                 goto out;
836         }
837
838         gateway_nid = libcfs_str2nid(gw);
839         if (gateway_nid == LNET_NID_ANY) {
840                 snprintf(err_str,
841                          sizeof(err_str),
842                          "\"cannot parse gateway NID '%s'\"", gw);
843                 rc = LUSTRE_CFG_RC_BAD_PARAM;
844                 goto out;
845         }
846
847         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
848         data.cfg_net = net;
849         data.cfg_nid = gateway_nid;
850
851         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DEL_ROUTE, &data);
852         if (rc != 0) {
853                 rc = -errno;
854                 snprintf(err_str,
855                          sizeof(err_str),
856                          "\"cannot delete route: %s\"", strerror(errno));
857                 goto out;
858         }
859
860 out:
861         cYAML_build_error(rc, seq_no, DEL_CMD, "route", err_str, err_rc);
862
863         return rc;
864 }
865
866 int lustre_lnet_show_route(char *nw, char *gw, int hops, int prio, int detail,
867                            int seq_no, struct cYAML **show_rc,
868                            struct cYAML **err_rc)
869 {
870         struct lnet_ioctl_config_data data;
871         lnet_nid_t gateway_nid;
872         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
873         int l_errno = 0;
874         __u32 net = LNET_NIDNET(LNET_NID_ANY);
875         int i;
876         struct cYAML *root = NULL, *route = NULL, *item = NULL;
877         struct cYAML *first_seq = NULL;
878         char err_str[LNET_MAX_STR_LEN];
879         bool exist = false;
880
881         snprintf(err_str, sizeof(err_str),
882                  "\"out of memory\"");
883
884         if (nw != NULL) {
885                 net = libcfs_str2net(nw);
886                 if (net == LNET_NIDNET(LNET_NID_ANY)) {
887                         snprintf(err_str,
888                                  sizeof(err_str),
889                                  "\"cannot parse net '%s'\"", nw);
890                         rc = LUSTRE_CFG_RC_BAD_PARAM;
891                         goto out;
892                 }
893
894         } else {
895                 /* show all routes without filtering on net */
896                 net = LNET_NIDNET(LNET_NID_ANY);
897         }
898
899         if (gw != NULL) {
900                 gateway_nid = libcfs_str2nid(gw);
901                 if (gateway_nid == LNET_NID_ANY) {
902                         snprintf(err_str,
903                                  sizeof(err_str),
904                                  "\"cannot parse gateway NID '%s'\"", gw);
905                         rc = LUSTRE_CFG_RC_BAD_PARAM;
906                         goto out;
907                 }
908         } else
909                 /* show all routes with out filtering on gateway */
910                 gateway_nid = LNET_NID_ANY;
911
912         if ((hops < 1 && hops != -1) || hops > 255) {
913                 snprintf(err_str,
914                          sizeof(err_str),
915                          "\"invalid hop count %d, must be between 0 and 256\"",
916                          hops);
917                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
918                 goto out;
919         }
920
921         /* create struct cYAML root object */
922         root = cYAML_create_object(NULL, NULL);
923         if (root == NULL)
924                 goto out;
925
926         route = cYAML_create_seq(root, "route");
927         if (route == NULL)
928                 goto out;
929
930         for (i = 0;; i++) {
931                 LIBCFS_IOC_INIT_V2(data, cfg_hdr);
932                 data.cfg_count = i;
933
934                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_ROUTE, &data);
935                 if (rc != 0) {
936                         l_errno = errno;
937                         break;
938                 }
939
940                 /* filter on provided data */
941                 if (net != LNET_NIDNET(LNET_NID_ANY) &&
942                     net != data.cfg_net)
943                         continue;
944
945                 if (gateway_nid != LNET_NID_ANY &&
946                     gateway_nid != data.cfg_nid)
947                         continue;
948
949                 if (hops != -1 &&
950                     hops != data.cfg_config_u.cfg_route.rtr_hop)
951                         continue;
952
953                 if (prio != -1 &&
954                     prio != data.cfg_config_u.cfg_route.rtr_priority)
955                         continue;
956
957                 /* default rc to -1 incase we hit the goto */
958                 rc = -1;
959                 exist = true;
960
961                 item = cYAML_create_seq_item(route);
962                 if (item == NULL)
963                         goto out;
964
965                 if (first_seq == NULL)
966                         first_seq = item;
967
968                 if (cYAML_create_string(item, "net",
969                                         libcfs_net2str(data.cfg_net)) == NULL)
970                         goto out;
971
972                 if (cYAML_create_string(item, "gateway",
973                                         libcfs_nid2str(data.cfg_nid)) == NULL)
974                         goto out;
975
976                 if (detail) {
977                         if (cYAML_create_number(item, "hop",
978                                                 (int) data.cfg_config_u.
979                                                 cfg_route.rtr_hop) ==
980                             NULL)
981                                 goto out;
982
983                         if (cYAML_create_number(item, "priority",
984                                                 data.cfg_config_u.
985                                                 cfg_route.rtr_priority) == NULL)
986                                 goto out;
987
988                         if (cYAML_create_string(item, "state",
989                                                 data.cfg_config_u.cfg_route.
990                                                         rtr_flags ?
991                                                 "up" : "down") == NULL)
992                                 goto out;
993                 }
994         }
995
996         /* print output iff show_rc is not provided */
997         if (show_rc == NULL)
998                 cYAML_print_tree(root);
999
1000         if (l_errno != ENOENT) {
1001                 snprintf(err_str,
1002                          sizeof(err_str),
1003                          "\"cannot get routes: %s\"",
1004                          strerror(l_errno));
1005                 rc = -l_errno;
1006                 goto out;
1007         } else
1008                 rc = LUSTRE_CFG_RC_NO_ERR;
1009
1010         snprintf(err_str, sizeof(err_str), "\"success\"");
1011 out:
1012         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR || !exist) {
1013                 cYAML_free_tree(root);
1014         } else if (show_rc != NULL && *show_rc != NULL) {
1015                 struct cYAML *show_node;
1016                 /* find the route node, if one doesn't exist then
1017                  * insert one.  Otherwise add to the one there
1018                  */
1019                 show_node = cYAML_get_object_item(*show_rc, "route");
1020                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
1021                         cYAML_insert_child(show_node, first_seq);
1022                         free(route);
1023                         free(root);
1024                 } else if (show_node == NULL) {
1025                         cYAML_insert_sibling((*show_rc)->cy_child,
1026                                                 route);
1027                         free(root);
1028                 } else {
1029                         cYAML_free_tree(root);
1030                 }
1031         } else {
1032                 *show_rc = root;
1033         }
1034
1035         cYAML_build_error(rc, seq_no, SHOW_CMD, "route", err_str, err_rc);
1036
1037         return rc;
1038 }
1039
1040 static int socket_intf_query(int request, char *intf,
1041                              struct ifreq *ifr)
1042 {
1043         int rc = 0;
1044         int sockfd;
1045
1046         if (strlen(intf) >= IFNAMSIZ || ifr == NULL)
1047                 return LUSTRE_CFG_RC_BAD_PARAM;
1048
1049         sockfd = socket(AF_INET, SOCK_DGRAM, 0);
1050         if (sockfd < 0)
1051                 return LUSTRE_CFG_RC_BAD_PARAM;
1052
1053         strcpy(ifr->ifr_name, intf);
1054         rc = ioctl(sockfd, request, ifr);
1055         if (rc != 0)
1056                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1057
1058         close(sockfd);
1059
1060         return rc;
1061 }
1062
1063 /*
1064  * for each interface in the array of interfaces find the IP address of
1065  * that interface, create its nid and add it to an array of NIDs.
1066  * Stop if any of the interfaces is down
1067  */
1068 static int lustre_lnet_intf2nids(struct lnet_dlc_network_descr *nw,
1069                                  lnet_nid_t **nids, __u32 *nnids)
1070 {
1071         int i = 0, count = 0, rc;
1072         struct ifreq ifr;
1073         __u32 ip;
1074         struct lnet_dlc_intf_descr *intf;
1075
1076         if (nw == NULL || nids == NULL)
1077                 return LUSTRE_CFG_RC_BAD_PARAM;
1078
1079         list_for_each_entry(intf, &nw->nw_intflist, intf_on_network)
1080                 count++;
1081
1082         *nids = calloc(count, sizeof(lnet_nid_t));
1083         if (*nids == NULL)
1084                 return LUSTRE_CFG_RC_OUT_OF_MEM;
1085
1086         list_for_each_entry(intf, &nw->nw_intflist, intf_on_network) {
1087                 memset(&ifr, 0, sizeof(ifr));
1088                 rc = socket_intf_query(SIOCGIFFLAGS, intf->intf_name, &ifr);
1089                 if (rc != 0)
1090                         goto failed;
1091
1092                 if ((ifr.ifr_flags & IFF_UP) == 0) {
1093                         rc = LUSTRE_CFG_RC_BAD_PARAM;
1094                         goto failed;
1095                 }
1096
1097                 memset(&ifr, 0, sizeof(ifr));
1098                 rc = socket_intf_query(SIOCGIFADDR, intf->intf_name, &ifr);
1099                 if (rc != 0)
1100                         goto failed;
1101
1102                 ip = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
1103                 ip = bswap_32(ip);
1104                 (*nids)[i] = LNET_MKNID(nw->nw_id, ip);
1105                 i++;
1106         }
1107
1108         *nnids = count;
1109
1110         return 0;
1111
1112 failed:
1113         free(*nids);
1114         *nids = NULL;
1115         return rc;
1116 }
1117
1118 /*
1119  * called repeatedly until a match or no more ip range
1120  * What do you have?
1121  *      ip_range expression
1122  *      interface list with all the interface names.
1123  *      all the interfaces in the system.
1124  *
1125  *      try to match the ip_range expr to one of the interfaces' IPs in
1126  *      the system. If we hit a patch for an interface. Check if that
1127  *      interface name is in the list.
1128  *
1129  *      If there are more than one interface in the list, then make sure
1130  *      that the IPs for all of these interfaces match the ip ranges
1131  *      given.
1132  *
1133  *      for each interface in intf_list
1134  *              look up the intf name in ifa
1135  *              if not there then no match
1136  *              check ip obtained from ifa against a match to any of the
1137  *              ip_ranges given.
1138  *              If no match, then fail
1139  *
1140  *      The result is that all the interfaces have to match.
1141  */
1142 int lustre_lnet_match_ip_to_intf(struct ifaddrs *ifa,
1143                                  struct list_head *intf_list,
1144                                  struct list_head *ip_ranges)
1145 {
1146         int rc;
1147         __u32 ip;
1148         struct lnet_dlc_intf_descr *intf_descr, *tmp;
1149         struct ifaddrs *ifaddr = ifa;
1150         struct lustre_lnet_ip_range_descr *ip_range;
1151         int family;
1152
1153         /*
1154          * if there are no explicit interfaces, and no ip ranges, then
1155          * configure the first tcp interface we encounter.
1156          */
1157         if (list_empty(intf_list) && list_empty(ip_ranges)) {
1158                 for (ifaddr = ifa; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {
1159                         if (ifaddr->ifa_addr == NULL)
1160                                 continue;
1161
1162                         if ((ifaddr->ifa_flags & IFF_UP) == 0)
1163                                 continue;
1164
1165                         family = ifaddr->ifa_addr->sa_family;
1166                         if (family == AF_INET &&
1167                             strcmp(ifaddr->ifa_name, "lo") != 0) {
1168                                 rc = lustre_lnet_add_intf_descr
1169                                         (intf_list, ifaddr->ifa_name,
1170                                         strlen(ifaddr->ifa_name));
1171
1172                                 if (rc != LUSTRE_CFG_RC_NO_ERR)
1173                                         return rc;
1174
1175                                 return LUSTRE_CFG_RC_MATCH;
1176                         }
1177                 }
1178                 return LUSTRE_CFG_RC_NO_MATCH;
1179         }
1180
1181         /*
1182          * First interface which matches an IP pattern will be used
1183          */
1184         if (list_empty(intf_list)) {
1185                 /*
1186                  * no interfaces provided in the rule, but an ip range is
1187                  * provided, so try and match an interface to the ip
1188                  * range.
1189                  */
1190                 for (ifaddr = ifa; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {
1191                         if (ifaddr->ifa_addr == NULL)
1192                                 continue;
1193
1194                         if ((ifaddr->ifa_flags & IFF_UP) == 0)
1195                                 continue;
1196
1197                         family = ifaddr->ifa_addr->sa_family;
1198                         if (family == AF_INET) {
1199                                 ip = ((struct sockaddr_in *)ifaddr->ifa_addr)->
1200                                         sin_addr.s_addr;
1201
1202                                 list_for_each_entry(ip_range, ip_ranges,
1203                                                     ipr_entry) {
1204                                         rc = cfs_ip_addr_match(bswap_32(ip),
1205                                                         &ip_range->ipr_expr);
1206                                         if (!rc)
1207                                                 continue;
1208
1209                                         rc = lustre_lnet_add_intf_descr
1210                                           (intf_list, ifaddr->ifa_name,
1211                                            strlen(ifaddr->ifa_name));
1212
1213                                         if (rc != LUSTRE_CFG_RC_NO_ERR)
1214                                                 return rc;
1215                                 }
1216                         }
1217                 }
1218
1219                 if (!list_empty(intf_list))
1220                         return LUSTRE_CFG_RC_MATCH;
1221
1222                 return LUSTRE_CFG_RC_NO_MATCH;
1223         }
1224
1225         /*
1226          * If an interface is explicitly specified the ip-range might or
1227          * might not be specified. if specified the interface needs to match the
1228          * ip-range. If no ip-range then the interfaces are
1229          * automatically matched if they are all up.
1230          * If > 1 interfaces all the interfaces must match for the NI to
1231          * be configured.
1232          */
1233         list_for_each_entry_safe(intf_descr, tmp, intf_list, intf_on_network) {
1234                 for (ifaddr = ifa; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {
1235                         if (ifaddr->ifa_addr == NULL)
1236                                 continue;
1237
1238                         family = ifaddr->ifa_addr->sa_family;
1239                         if (family == AF_INET &&
1240                             strcmp(intf_descr->intf_name,
1241                                    ifaddr->ifa_name) == 0)
1242                                 break;
1243                 }
1244
1245                 if (ifaddr == NULL) {
1246                         list_del(&intf_descr->intf_on_network);
1247                         free_intf_descr(intf_descr);
1248                         continue;
1249                 }
1250
1251                 if ((ifaddr->ifa_flags & IFF_UP) == 0) {
1252                         list_del(&intf_descr->intf_on_network);
1253                         free_intf_descr(intf_descr);
1254                         continue;
1255                 }
1256
1257                 ip = ((struct sockaddr_in *)ifaddr->ifa_addr)->sin_addr.s_addr;
1258
1259                 rc = 1;
1260                 list_for_each_entry(ip_range, ip_ranges, ipr_entry) {
1261                         rc = cfs_ip_addr_match(bswap_32(ip), &ip_range->ipr_expr);
1262                         if (rc)
1263                                 break;
1264                 }
1265
1266                 if (!rc) {
1267                         /* no match for this interface */
1268                         list_del(&intf_descr->intf_on_network);
1269                         free_intf_descr(intf_descr);
1270                 }
1271         }
1272
1273         return LUSTRE_CFG_RC_MATCH;
1274 }
1275
1276 int lustre_lnet_resolve_ip2nets_rule(struct lustre_lnet_ip2nets *ip2nets,
1277                                      lnet_nid_t **nids, __u32 *nnids)
1278 {
1279         struct ifaddrs *ifa;
1280         int rc = LUSTRE_CFG_RC_NO_ERR;
1281
1282         rc = getifaddrs(&ifa);
1283         if (rc < 0)
1284                 return -errno;
1285
1286         rc = lustre_lnet_match_ip_to_intf(ifa,
1287                                           &ip2nets->ip2nets_net.nw_intflist,
1288                                           &ip2nets->ip2nets_ip_ranges);
1289         if (rc != LUSTRE_CFG_RC_MATCH) {
1290                 freeifaddrs(ifa);
1291                 return rc;
1292         }
1293
1294         rc = lustre_lnet_intf2nids(&ip2nets->ip2nets_net, nids, nnids);
1295         if (rc != LUSTRE_CFG_RC_NO_ERR) {
1296                 *nids = NULL;
1297                 *nnids = 0;
1298         }
1299
1300         freeifaddrs(ifa);
1301
1302         return rc;
1303 }
1304
1305 static int
1306 lustre_lnet_ioctl_config_ni(struct list_head *intf_list,
1307                             struct lnet_ioctl_config_lnd_tunables *tunables,
1308                             struct cfs_expr_list *global_cpts,
1309                             lnet_nid_t *nids, char *err_str)
1310 {
1311         char *data;
1312         struct lnet_ioctl_config_ni *conf;
1313         struct lnet_ioctl_config_lnd_tunables *tun = NULL;
1314         int rc = LUSTRE_CFG_RC_NO_ERR, i = 0;
1315         size_t len;
1316         int count;
1317         struct lnet_dlc_intf_descr *intf_descr;
1318         __u32 *cpt_array;
1319         struct cfs_expr_list *cpt_expr;
1320
1321         list_for_each_entry(intf_descr, intf_list,
1322                             intf_on_network) {
1323                 if (tunables != NULL)
1324                         len = sizeof(struct lnet_ioctl_config_ni) +
1325                               sizeof(struct lnet_ioctl_config_lnd_tunables);
1326                 else
1327                         len = sizeof(struct lnet_ioctl_config_ni);
1328
1329                 data = calloc(1, len);
1330                 if (!data)
1331                         return LUSTRE_CFG_RC_OUT_OF_MEM;
1332                 conf = (struct lnet_ioctl_config_ni*) data;
1333                 if (tunables != NULL)
1334                         tun = (struct lnet_ioctl_config_lnd_tunables*)
1335                                 conf->lic_bulk;
1336
1337                 LIBCFS_IOC_INIT_V2(*conf, lic_cfg_hdr);
1338                 conf->lic_cfg_hdr.ioc_len = len;
1339                 conf->lic_nid = nids[i];
1340                 strncpy(conf->lic_ni_intf[0], intf_descr->intf_name,
1341                         LNET_MAX_STR_LEN);
1342
1343                 if (intf_descr->cpt_expr != NULL)
1344                         cpt_expr = intf_descr->cpt_expr;
1345                 else if (global_cpts != NULL)
1346                         cpt_expr = global_cpts;
1347                 else
1348                         cpt_expr = NULL;
1349
1350                 if (cpt_expr != NULL) {
1351                         count = cfs_expr_list_values(cpt_expr,
1352                                                      LNET_MAX_SHOW_NUM_CPT,
1353                                                      &cpt_array);
1354                         if (count > 0) {
1355                                 memcpy(conf->lic_cpts, cpt_array,
1356                                        sizeof(cpt_array[0]) * LNET_MAX_STR_LEN);
1357                                 free(cpt_array);
1358                         } else {
1359                                 count = 0;
1360                         }
1361                 } else {
1362                         count = 0;
1363                 }
1364
1365                 conf->lic_ncpts = count;
1366
1367                 if (tunables != NULL)
1368                         memcpy(tun, tunables, sizeof(*tunables));
1369
1370                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_LOCAL_NI, data);
1371                 if (rc < 0) {
1372                         rc = -errno;
1373                         snprintf(err_str,
1374                                  LNET_MAX_STR_LEN,
1375                                  "\"cannot add network: %s\"", strerror(errno));
1376                         free(data);
1377                         return rc;
1378                 }
1379                 free(data);
1380                 i++;
1381         }
1382
1383         return LUSTRE_CFG_RC_NO_ERR;
1384 }
1385
1386 int
1387 lustre_lnet_config_ip2nets(struct lustre_lnet_ip2nets *ip2nets,
1388                            struct lnet_ioctl_config_lnd_tunables *tunables,
1389                            struct cfs_expr_list *global_cpts,
1390                            int seq_no, struct cYAML **err_rc)
1391 {
1392         lnet_nid_t *nids = NULL;
1393         __u32 nnids = 0;
1394         int rc;
1395         char err_str[LNET_MAX_STR_LEN];
1396
1397         snprintf(err_str, sizeof(err_str), "\"success\"");
1398
1399         if (!ip2nets) {
1400                 snprintf(err_str,
1401                          sizeof(err_str),
1402                          "\"incomplete ip2nets information\"");
1403                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1404                 goto out;
1405         }
1406
1407         /*
1408          * call below function to resolve the rules into a list of nids.
1409          * The memory is allocated in that function then freed here when
1410          * it's no longer needed.
1411          */
1412         rc = lustre_lnet_resolve_ip2nets_rule(ip2nets, &nids, &nnids);
1413         if (rc != LUSTRE_CFG_RC_NO_ERR && rc != LUSTRE_CFG_RC_MATCH) {
1414                 snprintf(err_str,
1415                          sizeof(err_str),
1416                          "\"cannot resolve ip2nets rule\"");
1417                 goto out;
1418         }
1419
1420         if (list_empty(&ip2nets->ip2nets_net.nw_intflist)) {
1421                 snprintf(err_str, sizeof(err_str),
1422                          "\"no interfaces match ip2nets rules\"");
1423                 goto free_nids_out;
1424         }
1425
1426         rc = lustre_lnet_ioctl_config_ni(&ip2nets->ip2nets_net.nw_intflist,
1427                                          tunables, global_cpts, nids,
1428                                          err_str);
1429
1430 free_nids_out:
1431         free(nids);
1432
1433 out:
1434         cYAML_build_error(rc, seq_no, ADD_CMD, "ip2nets", err_str, err_rc);
1435         return rc;
1436 }
1437
1438 int lustre_lnet_config_ni(struct lnet_dlc_network_descr *nw_descr,
1439                           struct cfs_expr_list *global_cpts,
1440                           char *ip2net,
1441                           struct lnet_ioctl_config_lnd_tunables *tunables,
1442                           int seq_no, struct cYAML **err_rc)
1443 {
1444         char *data = NULL;
1445         struct lnet_ioctl_config_ni *conf;
1446         struct lnet_ioctl_config_lnd_tunables *tun = NULL;
1447         char buf[LNET_MAX_STR_LEN];
1448         int rc = LUSTRE_CFG_RC_NO_ERR;
1449         char err_str[LNET_MAX_STR_LEN];
1450         lnet_nid_t *nids = NULL;
1451         __u32 nnids = 0;
1452         size_t len;
1453         int count;
1454         struct lnet_dlc_intf_descr *intf_descr, *tmp;
1455         __u32 *cpt_array;
1456
1457         snprintf(err_str, sizeof(err_str), "\"success\"");
1458
1459         if (ip2net == NULL && nw_descr == NULL) {
1460                 snprintf(err_str,
1461                          sizeof(err_str),
1462                          "\"mandatory parameters not specified.\"");
1463                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
1464                 goto out;
1465         }
1466
1467         if (ip2net != NULL && strlen(ip2net) >= sizeof(buf)) {
1468                 snprintf(err_str,
1469                          sizeof(err_str),
1470                          "\"ip2net string too long %d\"",
1471                                 (int)strlen(ip2net));
1472                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
1473                 goto out;
1474         }
1475
1476         if (ip2net != NULL) {
1477                 if (tunables != NULL)
1478                         len = sizeof(struct lnet_ioctl_config_ni) +
1479                               sizeof(struct lnet_ioctl_config_lnd_tunables);
1480                 else
1481                         len = sizeof(struct lnet_ioctl_config_ni);
1482                 data = calloc(1, len);
1483                 if (!data) {
1484                         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
1485                         goto out;
1486                 }
1487                 conf = (struct lnet_ioctl_config_ni*) data;
1488                 if (tunables != NULL)
1489                         tun = (struct lnet_ioctl_config_lnd_tunables*)
1490                                 (data + sizeof(*conf));
1491
1492                 LIBCFS_IOC_INIT_V2(*conf, lic_cfg_hdr);
1493                 conf->lic_cfg_hdr.ioc_len = len;
1494                 strncpy(conf->lic_legacy_ip2nets, ip2net,
1495                         LNET_MAX_STR_LEN);
1496
1497                 if (global_cpts != NULL) {
1498                         count = cfs_expr_list_values(global_cpts,
1499                                                      LNET_MAX_SHOW_NUM_CPT,
1500                                                      &cpt_array);
1501                         if (count > 0) {
1502                                 memcpy(conf->lic_cpts, cpt_array,
1503                                        sizeof(cpt_array[0]) * LNET_MAX_STR_LEN);
1504                                 free(cpt_array);
1505                         } else {
1506                                 count = 0;
1507                         }
1508                 } else {
1509                         count = 0;
1510                 }
1511
1512                 conf->lic_ncpts = count;
1513
1514                 if (tunables != NULL)
1515                         memcpy(tun, tunables, sizeof(*tunables));
1516
1517                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_LOCAL_NI, data);
1518                 if (rc < 0) {
1519                         rc = -errno;
1520                         snprintf(err_str,
1521                                 sizeof(err_str),
1522                                 "\"cannot add network: %s\"", strerror(errno));
1523                         goto out;
1524                 }
1525
1526                 goto out;
1527         }
1528
1529         if (LNET_NETTYP(nw_descr->nw_id) == LOLND) {
1530                 rc = LUSTRE_CFG_RC_NO_ERR;
1531                 goto out;
1532         }
1533
1534         if (nw_descr->nw_id == LNET_NIDNET(LNET_NID_ANY)) {
1535                 snprintf(err_str,
1536                         sizeof(err_str),
1537                         "\"cannot parse net '%s'\"",
1538                         libcfs_net2str(nw_descr->nw_id));
1539                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1540                 goto out;
1541         }
1542
1543         if (list_empty(&nw_descr->nw_intflist)) {
1544                 snprintf(err_str,
1545                         sizeof(err_str),
1546                         "\"no interface name provided\"");
1547                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1548                 goto out;
1549         }
1550
1551         rc = lustre_lnet_intf2nids(nw_descr, &nids, &nnids);
1552         if (rc != 0) {
1553                 snprintf(err_str, sizeof(err_str),
1554                          "\"bad parameter\"");
1555                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1556                 goto out;
1557         }
1558
1559         rc = lustre_lnet_ioctl_config_ni(&nw_descr->nw_intflist,
1560                                          tunables, global_cpts, nids,
1561                                          err_str);
1562
1563 out:
1564         if (nw_descr != NULL) {
1565                 list_for_each_entry_safe(intf_descr, tmp,
1566                                          &nw_descr->nw_intflist,
1567                                          intf_on_network) {
1568                         list_del(&intf_descr->intf_on_network);
1569                         free_intf_descr(intf_descr);
1570                 }
1571         }
1572
1573         cYAML_build_error(rc, seq_no, ADD_CMD, "net", err_str, err_rc);
1574
1575         if (nids)
1576                 free(nids);
1577
1578         if (data)
1579                 free(data);
1580
1581         return rc;
1582 }
1583
1584 int lustre_lnet_del_ni(struct lnet_dlc_network_descr *nw_descr,
1585                        int seq_no, struct cYAML **err_rc)
1586 {
1587         struct lnet_ioctl_config_ni data;
1588         int rc = LUSTRE_CFG_RC_NO_ERR, i;
1589         char err_str[LNET_MAX_STR_LEN];
1590         lnet_nid_t *nids = NULL;
1591         __u32 nnids = 0;
1592         struct lnet_dlc_intf_descr *intf_descr, *tmp;
1593
1594         snprintf(err_str, sizeof(err_str), "\"success\"");
1595
1596         if (nw_descr == NULL) {
1597                 snprintf(err_str,
1598                          sizeof(err_str),
1599                          "\"missing mandatory parameter\"");
1600                 rc = LUSTRE_CFG_RC_MISSING_PARAM;
1601                 goto out;
1602         }
1603
1604         if (LNET_NETTYP(nw_descr->nw_id) == LOLND)
1605                 return LUSTRE_CFG_RC_NO_ERR;
1606
1607         if (nw_descr->nw_id == LNET_NIDNET(LNET_NID_ANY)) {
1608                 snprintf(err_str,
1609                          sizeof(err_str),
1610                          "\"cannot parse net '%s'\"",
1611                          libcfs_net2str(nw_descr->nw_id));
1612                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1613                 goto out;
1614         }
1615
1616         rc = lustre_lnet_intf2nids(nw_descr, &nids, &nnids);
1617         if (rc != 0) {
1618                 snprintf(err_str, sizeof(err_str),
1619                          "\"bad parameter\"");
1620                 rc = LUSTRE_CFG_RC_BAD_PARAM;
1621                 goto out;
1622         }
1623
1624         /*
1625          * no interfaces just the nw_id is specified
1626          */
1627         if (nnids == 0) {
1628                 nids = calloc(1, sizeof(*nids));
1629                 if (nids == NULL) {
1630                         snprintf(err_str, sizeof(err_str),
1631                                 "\"out of memory\"");
1632                         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
1633                         goto out;
1634                 }
1635                 nids[0] = LNET_MKNID(nw_descr->nw_id, 0);
1636                 nnids = 1;
1637         }
1638
1639         for (i = 0; i < nnids; i++) {
1640                 LIBCFS_IOC_INIT_V2(data, lic_cfg_hdr);
1641                 data.lic_nid = nids[i];
1642
1643                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DEL_LOCAL_NI, &data);
1644                 if (rc < 0) {
1645                         rc = -errno;
1646                         snprintf(err_str,
1647                                 sizeof(err_str),
1648                                 "\"cannot del network: %s\"", strerror(errno));
1649                 }
1650         }
1651
1652         list_for_each_entry_safe(intf_descr, tmp, &nw_descr->nw_intflist,
1653                                  intf_on_network) {
1654                 list_del(&intf_descr->intf_on_network);
1655                 free_intf_descr(intf_descr);
1656         }
1657
1658 out:
1659         cYAML_build_error(rc, seq_no, DEL_CMD, "net", err_str, err_rc);
1660
1661         if (nids != NULL)
1662                 free(nids);
1663
1664         return rc;
1665 }
1666
1667 int lustre_lnet_show_net(char *nw, int detail, int seq_no,
1668                          struct cYAML **show_rc, struct cYAML **err_rc)
1669 {
1670         char *buf;
1671         struct lnet_ioctl_config_ni *ni_data;
1672         struct lnet_ioctl_config_lnd_tunables *lnd;
1673         struct lnet_ioctl_element_stats *stats;
1674         __u32 net = LNET_NIDNET(LNET_NID_ANY);
1675         __u32 prev_net = LNET_NIDNET(LNET_NID_ANY);
1676         int rc = LUSTRE_CFG_RC_OUT_OF_MEM, i, j;
1677         int l_errno = 0;
1678         struct cYAML *root = NULL, *tunables = NULL,
1679                 *net_node = NULL, *interfaces = NULL,
1680                 *item = NULL, *first_seq = NULL,
1681                 *tmp = NULL, *statistics = NULL;
1682         int str_buf_len = LNET_MAX_SHOW_NUM_CPT * 2;
1683         char str_buf[str_buf_len];
1684         char *pos;
1685         char err_str[LNET_MAX_STR_LEN];
1686         bool exist = false, new_net = true;
1687         int net_num = 0;
1688         size_t buf_size = sizeof(*ni_data) + sizeof(*lnd) + sizeof(*stats);
1689
1690         snprintf(err_str, sizeof(err_str), "\"out of memory\"");
1691
1692         buf = calloc(1, buf_size);
1693         if (buf == NULL)
1694                 goto out;
1695
1696         ni_data = (struct lnet_ioctl_config_ni *)buf;
1697
1698         if (nw != NULL) {
1699                 net = libcfs_str2net(nw);
1700                 if (net == LNET_NIDNET(LNET_NID_ANY)) {
1701                         snprintf(err_str,
1702                                  sizeof(err_str),
1703                                  "\"cannot parse net '%s'\"", nw);
1704                         rc = LUSTRE_CFG_RC_BAD_PARAM;
1705                         goto out;
1706                 }
1707         }
1708
1709         root = cYAML_create_object(NULL, NULL);
1710         if (root == NULL)
1711                 goto out;
1712
1713         net_node = cYAML_create_seq(root, "net");
1714         if (net_node == NULL)
1715                 goto out;
1716
1717         for (i = 0;; i++) {
1718                 pos = str_buf;
1719                 __u32 rc_net;
1720
1721                 memset(buf, 0, buf_size);
1722
1723                 LIBCFS_IOC_INIT_V2(*ni_data, lic_cfg_hdr);
1724                 /*
1725                  * set the ioc_len to the proper value since INIT assumes
1726                  * size of data
1727                  */
1728                 ni_data->lic_cfg_hdr.ioc_len = buf_size;
1729                 ni_data->lic_idx = i;
1730
1731                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_LOCAL_NI, ni_data);
1732                 if (rc != 0) {
1733                         l_errno = errno;
1734                         break;
1735                 }
1736
1737                 rc_net = LNET_NIDNET(ni_data->lic_nid);
1738
1739                 /* filter on provided data */
1740                 if (net != LNET_NIDNET(LNET_NID_ANY) &&
1741                     net != rc_net)
1742                         continue;
1743
1744                 /* default rc to -1 in case we hit the goto */
1745                 rc = -1;
1746                 exist = true;
1747
1748                 stats = (struct lnet_ioctl_element_stats *)ni_data->lic_bulk;
1749                 lnd = (struct lnet_ioctl_config_lnd_tunables *)
1750                         (ni_data->lic_bulk + sizeof(*stats));
1751
1752                 if (rc_net != prev_net) {
1753                         prev_net = rc_net;
1754                         new_net = true;
1755                         net_num++;
1756                 }
1757
1758                 if (new_net) {
1759                         if (!cYAML_create_string(net_node, "net type",
1760                                                  libcfs_net2str(rc_net)))
1761                                 goto out;
1762
1763                         tmp = cYAML_create_seq(net_node, "local NI(s)");
1764                         if (tmp == NULL)
1765                                 goto out;
1766                         new_net = false;
1767                 }
1768
1769                 /* create the tree to be printed. */
1770                 item = cYAML_create_seq_item(tmp);
1771                 if (item == NULL)
1772                         goto out;
1773
1774                 if (first_seq == NULL)
1775                         first_seq = item;
1776
1777                 if (cYAML_create_string(item, "nid",
1778                                         libcfs_nid2str(ni_data->lic_nid)) == NULL)
1779                         goto out;
1780
1781                 if (cYAML_create_string(item,
1782                                         "status",
1783                                         (ni_data->lic_status ==
1784                                           LNET_NI_STATUS_UP) ?
1785                                             "up" : "down") == NULL)
1786                         goto out;
1787
1788                 /* don't add interfaces unless there is at least one
1789                  * interface */
1790                 if (strlen(ni_data->lic_ni_intf[0]) > 0) {
1791                         interfaces = cYAML_create_object(item, "interfaces");
1792                         if (interfaces == NULL)
1793                                 goto out;
1794
1795                         for (j = 0; j < LNET_NUM_INTERFACES; j++) {
1796                                 if (strlen(ni_data->lic_ni_intf[j]) > 0) {
1797                                         snprintf(str_buf,
1798                                                  sizeof(str_buf), "%d", j);
1799                                         if (cYAML_create_string(interfaces,
1800                                                 str_buf,
1801                                                 ni_data->lic_ni_intf[j]) ==
1802                                                         NULL)
1803                                                 goto out;
1804                                 }
1805                         }
1806                 }
1807
1808                 if (detail) {
1809                         char *limit;
1810
1811                         statistics = cYAML_create_object(item, "statistics");
1812                         if (statistics == NULL)
1813                                 goto out;
1814
1815                         if (cYAML_create_number(statistics, "send_count",
1816                                                 stats->iel_send_count)
1817                                                         == NULL)
1818                                 goto out;
1819
1820                         if (cYAML_create_number(statistics, "recv_count",
1821                                                 stats->iel_recv_count)
1822                                                         == NULL)
1823                                 goto out;
1824
1825                         if (cYAML_create_number(statistics, "drop_count",
1826                                                 stats->iel_drop_count)
1827                                                         == NULL)
1828                                 goto out;
1829
1830                         tunables = cYAML_create_object(item, "tunables");
1831                         if (!tunables)
1832                                 goto out;
1833
1834                         rc = lustre_net_show_tunables(tunables, &lnd->lt_cmn);
1835                         if (rc != LUSTRE_CFG_RC_NO_ERR)
1836                                 goto out;
1837
1838                         tunables = cYAML_create_object(item, "lnd tunables");
1839                         if (tunables == NULL)
1840                                 goto out;
1841
1842                         rc = lustre_ni_show_tunables(tunables, LNET_NETTYP(rc_net),
1843                                                      &lnd->lt_tun);
1844                         if (rc != LUSTRE_CFG_RC_NO_ERR)
1845                                 goto out;
1846
1847                         if (cYAML_create_number(item, "tcp bonding",
1848                                                 ni_data->lic_tcp_bonding)
1849                                                         == NULL)
1850                                 goto out;
1851
1852                         if (cYAML_create_number(item, "dev cpt",
1853                                                 ni_data->lic_dev_cpt) == NULL)
1854                                 goto out;
1855
1856                         /* out put the CPTs in the format: "[x,x,x,...]" */
1857                         limit = str_buf + str_buf_len - 3;
1858                         pos += snprintf(pos, limit - pos, "\"[");
1859                         for (j = 0 ; ni_data->lic_ncpts >= 1 &&
1860                                 j < ni_data->lic_ncpts &&
1861                                 pos < limit; j++) {
1862                                 pos += snprintf(pos, limit - pos,
1863                                                 "%d", ni_data->lic_cpts[j]);
1864                                 if ((j + 1) < ni_data->lic_ncpts)
1865                                         pos += snprintf(pos, limit - pos, ",");
1866                         }
1867                         pos += snprintf(pos, 3, "]\"");
1868
1869                         if (ni_data->lic_ncpts >= 1 &&
1870                             cYAML_create_string(item, "CPT",
1871                                                 str_buf) == NULL)
1872                                 goto out;
1873                 }
1874         }
1875
1876         /* Print out the net information only if show_rc is not provided */
1877         if (show_rc == NULL)
1878                 cYAML_print_tree(root);
1879
1880         if (l_errno != ENOENT) {
1881                 snprintf(err_str,
1882                          sizeof(err_str),
1883                          "\"cannot get networks: %s\"",
1884                          strerror(l_errno));
1885                 rc = -l_errno;
1886                 goto out;
1887         } else
1888                 rc = LUSTRE_CFG_RC_NO_ERR;
1889
1890         snprintf(err_str, sizeof(err_str), "\"success\"");
1891 out:
1892         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR || !exist) {
1893                 cYAML_free_tree(root);
1894         } else if (show_rc != NULL && *show_rc != NULL) {
1895                 struct cYAML *show_node;
1896                 /* find the net node, if one doesn't exist
1897                  * then insert one.  Otherwise add to the one there
1898                  */
1899                 show_node = cYAML_get_object_item(*show_rc, "net");
1900                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
1901                         cYAML_insert_child(show_node, first_seq);
1902                         free(net_node);
1903                         free(root);
1904                 } else if (show_node == NULL) {
1905                         cYAML_insert_sibling((*show_rc)->cy_child,
1906                                                 net_node);
1907                         free(root);
1908                 } else {
1909                         cYAML_free_tree(root);
1910                 }
1911         } else {
1912                 *show_rc = root;
1913         }
1914
1915         cYAML_build_error(rc, seq_no, SHOW_CMD, "net", err_str, err_rc);
1916
1917         return rc;
1918 }
1919
1920 int lustre_lnet_enable_routing(int enable, int seq_no, struct cYAML **err_rc)
1921 {
1922         struct lnet_ioctl_config_data data;
1923         int rc = LUSTRE_CFG_RC_NO_ERR;
1924         char err_str[LNET_MAX_STR_LEN];
1925
1926         snprintf(err_str, sizeof(err_str), "\"success\"");
1927
1928         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
1929         data.cfg_config_u.cfg_buffers.buf_enable = (enable) ? 1 : 0;
1930
1931         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_CONFIG_RTR, &data);
1932         if (rc != 0) {
1933                 rc = -errno;
1934                 snprintf(err_str,
1935                          sizeof(err_str),
1936                          "\"cannot %s routing %s\"",
1937                          (enable) ? "enable" : "disable", strerror(errno));
1938                 goto out;
1939         }
1940
1941 out:
1942         cYAML_build_error(rc, seq_no,
1943                          (enable) ? ADD_CMD : DEL_CMD,
1944                          "routing", err_str, err_rc);
1945
1946         return rc;
1947 }
1948
1949 int lustre_lnet_config_numa_range(int range, int seq_no, struct cYAML **err_rc)
1950 {
1951         struct lnet_ioctl_numa_range data;
1952         int rc = LUSTRE_CFG_RC_NO_ERR;
1953         char err_str[LNET_MAX_STR_LEN];
1954
1955         snprintf(err_str, sizeof(err_str), "\"success\"");
1956
1957         if (range < 0) {
1958                 snprintf(err_str,
1959                          sizeof(err_str),
1960                          "\"range must be >= 0\"");
1961                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
1962                 goto out;
1963         }
1964
1965         LIBCFS_IOC_INIT_V2(data, nr_hdr);
1966         data.nr_range = range;
1967
1968         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_SET_NUMA_RANGE, &data);
1969         if (rc != 0) {
1970                 rc = -errno;
1971                 snprintf(err_str,
1972                          sizeof(err_str),
1973                          "\"cannot configure buffers: %s\"", strerror(errno));
1974                 goto out;
1975         }
1976
1977 out:
1978         cYAML_build_error(rc, seq_no, ADD_CMD, "numa_range", err_str, err_rc);
1979
1980         return rc;
1981 }
1982
1983 int lustre_lnet_config_buffers(int tiny, int small, int large, int seq_no,
1984                                struct cYAML **err_rc)
1985 {
1986         struct lnet_ioctl_config_data data;
1987         int rc = LUSTRE_CFG_RC_NO_ERR;
1988         char err_str[LNET_MAX_STR_LEN];
1989
1990         snprintf(err_str, sizeof(err_str), "\"success\"");
1991
1992         /* -1 indicates to ignore changes to this field */
1993         if (tiny < -1 || small < -1 || large < -1) {
1994                 snprintf(err_str,
1995                          sizeof(err_str),
1996                          "\"tiny, small and large must be >= 0\"");
1997                 rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
1998                 goto out;
1999         }
2000
2001         LIBCFS_IOC_INIT_V2(data, cfg_hdr);
2002         data.cfg_config_u.cfg_buffers.buf_tiny = tiny;
2003         data.cfg_config_u.cfg_buffers.buf_small = small;
2004         data.cfg_config_u.cfg_buffers.buf_large = large;
2005
2006         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_BUF, &data);
2007         if (rc != 0) {
2008                 rc = -errno;
2009                 snprintf(err_str,
2010                          sizeof(err_str),
2011                          "\"cannot configure buffers: %s\"", strerror(errno));
2012                 goto out;
2013         }
2014
2015 out:
2016         cYAML_build_error(rc, seq_no, ADD_CMD, "buf", err_str, err_rc);
2017
2018         return rc;
2019 }
2020
2021 int lustre_lnet_show_routing(int seq_no, struct cYAML **show_rc,
2022                              struct cYAML **err_rc)
2023 {
2024         struct lnet_ioctl_config_data *data;
2025         struct lnet_ioctl_pool_cfg *pool_cfg = NULL;
2026         int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
2027         int l_errno = 0;
2028         char *buf;
2029         char *pools[LNET_NRBPOOLS] = {"tiny", "small", "large"};
2030         int buf_count[LNET_NRBPOOLS] = {0};
2031         struct cYAML *root = NULL, *pools_node = NULL,
2032                      *type_node = NULL, *item = NULL, *cpt = NULL,
2033                      *first_seq = NULL, *buffers = NULL;
2034         int i, j;
2035         char err_str[LNET_MAX_STR_LEN];
2036         char node_name[LNET_MAX_STR_LEN];
2037         bool exist = false;
2038
2039         snprintf(err_str, sizeof(err_str), "\"out of memory\"");
2040
2041         buf = calloc(1, sizeof(*data) + sizeof(*pool_cfg));
2042         if (buf == NULL)
2043                 goto out;
2044
2045         data = (struct lnet_ioctl_config_data *)buf;
2046
2047         root = cYAML_create_object(NULL, NULL);
2048         if (root == NULL)
2049                 goto out;
2050
2051         pools_node = cYAML_create_seq(root, "routing");
2052         if (pools_node == NULL)
2053                 goto out;
2054
2055         for (i = 0;; i++) {
2056                 LIBCFS_IOC_INIT_V2(*data, cfg_hdr);
2057                 data->cfg_hdr.ioc_len = sizeof(struct lnet_ioctl_config_data) +
2058                                         sizeof(struct lnet_ioctl_pool_cfg);
2059                 data->cfg_count = i;
2060
2061                 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_BUF, data);
2062                 if (rc != 0) {
2063                         l_errno = errno;
2064                         break;
2065                 }
2066
2067                 exist = true;
2068
2069                 pool_cfg = (struct lnet_ioctl_pool_cfg *)data->cfg_bulk;
2070
2071                 snprintf(node_name, sizeof(node_name), "cpt[%d]", i);
2072                 item = cYAML_create_seq_item(pools_node);
2073                 if (item == NULL)
2074                         goto out;
2075
2076                 if (first_seq == NULL)
2077                         first_seq = item;
2078
2079                 cpt = cYAML_create_object(item, node_name);
2080                 if (cpt == NULL)
2081                         goto out;
2082
2083                 /* create the tree  and print */
2084                 for (j = 0; j < LNET_NRBPOOLS; j++) {
2085                         type_node = cYAML_create_object(cpt, pools[j]);
2086                         if (type_node == NULL)
2087                                 goto out;
2088                         if (cYAML_create_number(type_node, "npages",
2089                                                 pool_cfg->pl_pools[j].pl_npages)
2090                             == NULL)
2091                                 goto out;
2092                         if (cYAML_create_number(type_node, "nbuffers",
2093                                                 pool_cfg->pl_pools[j].
2094                                                   pl_nbuffers) == NULL)
2095                                 goto out;
2096                         if (cYAML_create_number(type_node, "credits",
2097                                                 pool_cfg->pl_pools[j].
2098                                                    pl_credits) == NULL)
2099                                 goto out;
2100                         if (cYAML_create_number(type_node, "mincredits",
2101                                                 pool_cfg->pl_pools[j].
2102                                                    pl_mincredits) == NULL)
2103                                 goto out;
2104                         /* keep track of the total count for each of the
2105                          * tiny, small and large buffers */
2106                         buf_count[j] += pool_cfg->pl_pools[j].pl_nbuffers;
2107                 }
2108         }
2109
2110         if (pool_cfg != NULL) {
2111                 item = cYAML_create_seq_item(pools_node);
2112                 if (item == NULL)
2113                         goto out;
2114
2115                 if (cYAML_create_number(item, "enable", pool_cfg->pl_routing) ==
2116                     NULL)
2117                         goto out;
2118         }
2119
2120         /* create a buffers entry in the show. This is necessary so that
2121          * if the YAML output is used to configure a node, the buffer
2122          * configuration takes hold */
2123         buffers = cYAML_create_object(root, "buffers");
2124         if (buffers == NULL)
2125                 goto out;
2126
2127         for (i = 0; i < LNET_NRBPOOLS; i++) {
2128                 if (cYAML_create_number(buffers, pools[i], buf_count[i]) == NULL)
2129                         goto out;
2130         }
2131
2132         if (show_rc == NULL)
2133                 cYAML_print_tree(root);
2134
2135         if (l_errno != ENOENT) {
2136                 snprintf(err_str,
2137                          sizeof(err_str),
2138                          "\"cannot get routing information: %s\"",
2139                          strerror(l_errno));
2140                 rc = -l_errno;
2141                 goto out;
2142         } else
2143                 rc = LUSTRE_CFG_RC_NO_ERR;
2144
2145         snprintf(err_str, sizeof(err_str), "\"success\"");
2146         rc = LUSTRE_CFG_RC_NO_ERR;
2147
2148 out:
2149         free(buf);
2150         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR || !exist) {
2151                 cYAML_free_tree(root);
2152         } else if (show_rc != NULL && *show_rc != NULL) {
2153                 struct cYAML *routing_node;
2154                 /* there should exist only one routing block and one
2155                  * buffers block. If there already exists a previous one
2156                  * then don't add another */
2157                 routing_node = cYAML_get_object_item(*show_rc, "routing");
2158                 if (routing_node == NULL) {
2159                         cYAML_insert_sibling((*show_rc)->cy_child,
2160                                                 root->cy_child);
2161                         free(root);
2162                 } else {
2163                         cYAML_free_tree(root);
2164                 }
2165         } else {
2166                 *show_rc = root;
2167         }
2168
2169         cYAML_build_error(rc, seq_no, SHOW_CMD, "routing", err_str, err_rc);
2170
2171         return rc;
2172 }
2173
2174 int lustre_lnet_show_peer(char *knid, int detail, int seq_no,
2175                           struct cYAML **show_rc, struct cYAML **err_rc)
2176 {
2177         /*
2178          * TODO: This function is changing in a future patch to accommodate
2179          * PEER_LIST and proper filtering on any nid of the peer
2180          */
2181         struct lnet_ioctl_peer_cfg peer_info;
2182         struct lnet_peer_ni_credit_info *lpni_cri;
2183         struct lnet_ioctl_element_stats *lpni_stats;
2184         int rc = LUSTRE_CFG_RC_OUT_OF_MEM, ncpt = 0, i = 0, j = 0;
2185         int l_errno = 0;
2186         struct cYAML *root = NULL, *peer = NULL, *peer_ni = NULL,
2187                      *first_seq = NULL, *peer_root = NULL, *tmp = NULL;
2188         char err_str[LNET_MAX_STR_LEN];
2189         lnet_nid_t prev_primary_nid = LNET_NID_ANY, primary_nid = LNET_NID_ANY;
2190         int data_size = sizeof(*lpni_cri) + sizeof(*lpni_stats);
2191         char *data = malloc(data_size);
2192         bool new_peer = true;
2193
2194         snprintf(err_str, sizeof(err_str),
2195                  "\"out of memory\"");
2196
2197         if (data == NULL)
2198                 goto out;
2199
2200         /* create struct cYAML root object */
2201         root = cYAML_create_object(NULL, NULL);
2202         if (root == NULL)
2203                 goto out;
2204
2205         peer_root = cYAML_create_seq(root, "peer");
2206         if (peer_root == NULL)
2207                 goto out;
2208
2209         if (knid != NULL)
2210                 primary_nid = libcfs_str2nid(knid);
2211
2212         do {
2213                 for (i = 0;; i++) {
2214                         memset(data, 0, data_size);
2215                         memset(&peer_info, 0, sizeof(peer_info));
2216                         LIBCFS_IOC_INIT_V2(peer_info, prcfg_hdr);
2217                         peer_info.prcfg_hdr.ioc_len = sizeof(peer_info);
2218                         peer_info.prcfg_count = i;
2219                         peer_info.prcfg_bulk = (void *)data;
2220                         peer_info.prcfg_size = data_size;
2221
2222                         rc = l_ioctl(LNET_DEV_ID,
2223                                      IOC_LIBCFS_GET_PEER_NI, &peer_info);
2224                         if (rc != 0) {
2225                                 l_errno = errno;
2226                                 break;
2227                         }
2228
2229                         if (primary_nid != LNET_NID_ANY &&
2230                             primary_nid != peer_info.prcfg_prim_nid)
2231                                         continue;
2232
2233                         lpni_cri = peer_info.prcfg_bulk;
2234                         lpni_stats = peer_info.prcfg_bulk + sizeof(*lpni_cri);
2235
2236                         peer = cYAML_create_seq_item(peer_root);
2237                         if (peer == NULL)
2238                                 goto out;
2239
2240                         if (peer_info.prcfg_prim_nid != prev_primary_nid) {
2241                                 prev_primary_nid = peer_info.prcfg_prim_nid;
2242                                 new_peer = true;
2243                         }
2244
2245                         if (new_peer) {
2246                                 lnet_nid_t pnid = peer_info.prcfg_prim_nid;
2247                                 if (cYAML_create_string(peer, "primary nid",
2248                                                         libcfs_nid2str(pnid))
2249                                     == NULL)
2250                                         goto out;
2251                                 if (cYAML_create_string(peer, "Multi-Rail",
2252                                                         peer_info.prcfg_mr ?
2253                                                         "True" : "False")
2254                                     == NULL)
2255                                         goto out;
2256                                 tmp = cYAML_create_seq(peer, "peer ni");
2257                                 if (tmp == NULL)
2258                                         goto out;
2259                                 new_peer = false;
2260                         }
2261
2262                         if (first_seq == NULL)
2263                                 first_seq = peer;
2264
2265                         peer_ni = cYAML_create_seq_item(tmp);
2266                         if (peer_ni == NULL)
2267                                 goto out;
2268
2269                         if (cYAML_create_string(peer_ni, "nid",
2270                                                 libcfs_nid2str
2271                                                  (peer_info.prcfg_cfg_nid))
2272                             == NULL)
2273                                 goto out;
2274
2275                         if (cYAML_create_string(peer_ni, "state",
2276                                                 lpni_cri->cr_aliveness)
2277                             == NULL)
2278                                 goto out;
2279
2280                         if (!detail)
2281                                 continue;
2282
2283                         if (cYAML_create_number(peer_ni, "max_ni_tx_credits",
2284                                                 lpni_cri->cr_ni_peer_tx_credits)
2285                             == NULL)
2286                                 goto out;
2287
2288                         if (cYAML_create_number(peer_ni, "available_tx_credits",
2289                                                 lpni_cri->cr_peer_tx_credits)
2290                             == NULL)
2291                                 goto out;
2292
2293                         if (cYAML_create_number(peer_ni, "min_tx_credits",
2294                                                 lpni_cri->cr_peer_min_tx_credits)
2295                             == NULL)
2296                                 goto out;
2297
2298                         if (cYAML_create_number(peer_ni, "tx_q_num_of_buf",
2299                                                 lpni_cri->cr_peer_tx_qnob)
2300                             == NULL)
2301                                 goto out;
2302
2303                         if (cYAML_create_number(peer_ni, "available_rtr_credits",
2304                                                 lpni_cri->cr_peer_rtr_credits)
2305                             == NULL)
2306                                 goto out;
2307
2308                         if (cYAML_create_number(peer_ni, "min_rtr_credits",
2309                                                 lpni_cri->cr_peer_min_rtr_credits)
2310                             == NULL)
2311                                 goto out;
2312
2313                         if (cYAML_create_number(peer_ni, "send_count",
2314                                                 lpni_stats->iel_send_count)
2315                             == NULL)
2316                                 goto out;
2317
2318                         if (cYAML_create_number(peer_ni, "recv_count",
2319                                                 lpni_stats->iel_recv_count)
2320                             == NULL)
2321                                 goto out;
2322
2323                         if (cYAML_create_number(peer_ni, "drop_count",
2324                                                 lpni_stats->iel_drop_count)
2325                             == NULL)
2326                                 goto out;
2327
2328                         if (cYAML_create_number(peer_ni, "refcount",
2329                                                 lpni_cri->cr_refcount) == NULL)
2330                                 goto out;
2331                 }
2332
2333                 if (l_errno != ENOENT) {
2334                         snprintf(err_str,
2335                                 sizeof(err_str),
2336                                 "\"cannot get peer information: %s\"",
2337                                 strerror(l_errno));
2338                         rc = -l_errno;
2339                         goto out;
2340                 }
2341
2342                 j++;
2343         } while (j < ncpt);
2344
2345         /* print output iff show_rc is not provided */
2346         if (show_rc == NULL)
2347                 cYAML_print_tree(root);
2348
2349         snprintf(err_str, sizeof(err_str), "\"success\"");
2350         rc = LUSTRE_CFG_RC_NO_ERR;
2351
2352 out:
2353         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
2354                 cYAML_free_tree(root);
2355         } else if (show_rc != NULL && *show_rc != NULL) {
2356                 struct cYAML *show_node;
2357                 /* find the peer node, if one doesn't exist then
2358                  * insert one.  Otherwise add to the one there
2359                  */
2360                 show_node = cYAML_get_object_item(*show_rc,
2361                                                   "peer");
2362                 if (show_node != NULL && cYAML_is_sequence(show_node)) {
2363                         cYAML_insert_child(show_node, first_seq);
2364                         free(peer_root);
2365                         free(root);
2366                 } else if (show_node == NULL) {
2367                         cYAML_insert_sibling((*show_rc)->cy_child,
2368                                              peer_root);
2369                         free(root);
2370                 } else {
2371                         cYAML_free_tree(root);
2372                 }
2373         } else {
2374                 *show_rc = root;
2375         }
2376
2377         cYAML_build_error(rc, seq_no, SHOW_CMD, "peer", err_str,
2378                           err_rc);
2379
2380         return rc;
2381 }
2382
2383 int lustre_lnet_show_numa_range(int seq_no, struct cYAML **show_rc,
2384                                 struct cYAML **err_rc)
2385 {
2386         struct lnet_ioctl_numa_range data;
2387         int rc;
2388         int l_errno;
2389         char err_str[LNET_MAX_STR_LEN];
2390         struct cYAML *root = NULL, *range = NULL;
2391
2392         snprintf(err_str, sizeof(err_str), "\"out of memory\"");
2393
2394         LIBCFS_IOC_INIT_V2(data, nr_hdr);
2395
2396         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_NUMA_RANGE, &data);
2397         if (rc != 0) {
2398                 l_errno = errno;
2399                 snprintf(err_str,
2400                          sizeof(err_str),
2401                          "\"cannot get numa range: %s\"",
2402                          strerror(l_errno));
2403                 rc = -l_errno;
2404                 goto out;
2405         }
2406
2407         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
2408
2409         root = cYAML_create_object(NULL, NULL);
2410         if (root == NULL)
2411                 goto out;
2412
2413         range = cYAML_create_object(root, "numa");
2414         if (range == NULL)
2415                 goto out;
2416
2417         if (cYAML_create_number(range, "range",
2418                                 data.nr_range) == NULL)
2419                 goto out;
2420
2421         if (show_rc == NULL)
2422                 cYAML_print_tree(root);
2423
2424         snprintf(err_str, sizeof(err_str), "\"success\"");
2425         rc = LUSTRE_CFG_RC_NO_ERR;
2426 out:
2427         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
2428                 cYAML_free_tree(root);
2429         } else if (show_rc != NULL && *show_rc != NULL) {
2430                 cYAML_insert_sibling((*show_rc)->cy_child,
2431                                         root->cy_child);
2432                 free(root);
2433         } else {
2434                 *show_rc = root;
2435         }
2436
2437         cYAML_build_error(rc, seq_no, SHOW_CMD, "numa", err_str, err_rc);
2438
2439         return rc;
2440 }
2441
2442 int lustre_lnet_show_stats(int seq_no, struct cYAML **show_rc,
2443                            struct cYAML **err_rc)
2444 {
2445         struct lnet_ioctl_lnet_stats data;
2446         int rc;
2447         int l_errno;
2448         char err_str[LNET_MAX_STR_LEN];
2449         struct cYAML *root = NULL, *stats = NULL;
2450
2451         snprintf(err_str, sizeof(err_str), "\"out of memory\"");
2452
2453         LIBCFS_IOC_INIT_V2(data, st_hdr);
2454
2455         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_LNET_STATS, &data);
2456         if (rc != 0) {
2457                 l_errno = errno;
2458                 snprintf(err_str,
2459                          sizeof(err_str),
2460                          "\"cannot get lnet statistics: %s\"",
2461                          strerror(l_errno));
2462                 rc = -l_errno;
2463                 goto out;
2464         }
2465
2466         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
2467
2468         root = cYAML_create_object(NULL, NULL);
2469         if (root == NULL)
2470                 goto out;
2471
2472         stats = cYAML_create_object(root, "statistics");
2473         if (stats == NULL)
2474                 goto out;
2475
2476         if (cYAML_create_number(stats, "msgs_alloc",
2477                                 data.st_cntrs.msgs_alloc) == NULL)
2478                 goto out;
2479
2480         if (cYAML_create_number(stats, "msgs_max",
2481                                 data.st_cntrs.msgs_max) == NULL)
2482                 goto out;
2483
2484         if (cYAML_create_number(stats, "errors",
2485                                 data.st_cntrs.errors) == NULL)
2486                 goto out;
2487
2488         if (cYAML_create_number(stats, "send_count",
2489                                 data.st_cntrs.send_count) == NULL)
2490                 goto out;
2491
2492         if (cYAML_create_number(stats, "recv_count",
2493                                 data.st_cntrs.recv_count) == NULL)
2494                 goto out;
2495
2496         if (cYAML_create_number(stats, "route_count",
2497                                 data.st_cntrs.route_count) == NULL)
2498                 goto out;
2499
2500         if (cYAML_create_number(stats, "drop_count",
2501                                 data.st_cntrs.drop_count) == NULL)
2502                 goto out;
2503
2504         if (cYAML_create_number(stats, "send_length",
2505                                 data.st_cntrs.send_length) == NULL)
2506                 goto out;
2507
2508         if (cYAML_create_number(stats, "recv_length",
2509                                 data.st_cntrs.recv_length) == NULL)
2510                 goto out;
2511
2512         if (cYAML_create_number(stats, "route_length",
2513                                 data.st_cntrs.route_length) == NULL)
2514                 goto out;
2515
2516         if (cYAML_create_number(stats, "drop_length",
2517                                 data.st_cntrs.drop_length) == NULL)
2518                 goto out;
2519
2520         if (show_rc == NULL)
2521                 cYAML_print_tree(root);
2522
2523         snprintf(err_str, sizeof(err_str), "\"success\"");
2524         rc = LUSTRE_CFG_RC_NO_ERR;
2525 out:
2526         if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
2527                 cYAML_free_tree(root);
2528         } else if (show_rc != NULL && *show_rc != NULL) {
2529                 cYAML_insert_sibling((*show_rc)->cy_child,
2530                                         root->cy_child);
2531                 free(root);
2532         } else {
2533                 *show_rc = root;
2534         }
2535
2536         cYAML_build_error(rc, seq_no, SHOW_CMD, "statistics", err_str, err_rc);
2537
2538         return rc;
2539 }
2540
2541 typedef int (*cmd_handler_t)(struct cYAML *tree,
2542                              struct cYAML **show_rc,
2543                              struct cYAML **err_rc);
2544
2545 static int handle_yaml_config_route(struct cYAML *tree, struct cYAML **show_rc,
2546                                     struct cYAML **err_rc)
2547 {
2548         struct cYAML *net, *gw, *hop, *prio, *seq_no;
2549
2550         net = cYAML_get_object_item(tree, "net");
2551         gw = cYAML_get_object_item(tree, "gateway");
2552         hop = cYAML_get_object_item(tree, "hop");
2553         prio = cYAML_get_object_item(tree, "priority");
2554         seq_no = cYAML_get_object_item(tree, "seq_no");
2555
2556         return lustre_lnet_config_route((net) ? net->cy_valuestring : NULL,
2557                                         (gw) ? gw->cy_valuestring : NULL,
2558                                         (hop) ? hop->cy_valueint : -1,
2559                                         (prio) ? prio->cy_valueint : -1,
2560                                         (seq_no) ? seq_no->cy_valueint : -1,
2561                                         err_rc);
2562 }
2563
2564 static void yaml_free_string_array(char **array, int num)
2565 {
2566         int i;
2567         char **sub_array = array;
2568
2569         for (i = 0; i < num; i++) {
2570                 if (*sub_array != NULL)
2571                         free(*sub_array);
2572                 sub_array++;
2573         }
2574         if (array)
2575                 free(array);
2576 }
2577
2578 /*
2579  *    interfaces:
2580  *        0: <intf_name>['['<expr>']']
2581  *        1: <intf_name>['['<expr>']']
2582  */
2583 static int yaml_copy_intf_info(struct cYAML *intf_tree,
2584                                struct lnet_dlc_network_descr *nw_descr)
2585 {
2586         struct cYAML *child = NULL;
2587         int intf_num = 0, rc = LUSTRE_CFG_RC_NO_ERR;
2588         struct lnet_dlc_intf_descr *intf_descr, *tmp;
2589
2590         if (intf_tree == NULL || nw_descr == NULL)
2591                 return LUSTRE_CFG_RC_BAD_PARAM;
2592
2593         /* now grab all the interfaces and their cpts */
2594         child = intf_tree->cy_child;
2595         while (child != NULL) {
2596                 if (child->cy_valuestring == NULL) {
2597                         child = child->cy_next;
2598                         continue;
2599                 }
2600
2601                 if (strlen(child->cy_valuestring) >= LNET_MAX_STR_LEN)
2602                         goto failed;
2603
2604                 rc = lustre_lnet_add_intf_descr(&nw_descr->nw_intflist,
2605                                                 child->cy_valuestring,
2606                                                 strlen(child->cy_valuestring));
2607                 if (rc != LUSTRE_CFG_RC_NO_ERR)
2608                         goto failed;
2609
2610                 intf_num++;
2611                 child = child->cy_next;
2612         }
2613
2614         if (intf_num == 0)
2615                 return LUSTRE_CFG_RC_MISSING_PARAM;
2616
2617         return intf_num;
2618
2619 failed:
2620         list_for_each_entry_safe(intf_descr, tmp, &nw_descr->nw_intflist,
2621                                  intf_on_network) {
2622                 list_del(&intf_descr->intf_on_network);
2623                 free_intf_descr(intf_descr);
2624         }
2625
2626         return rc;
2627 }
2628
2629 static bool
2630 yaml_extract_cmn_tunables(struct cYAML *tree,
2631                           struct lnet_ioctl_config_lnd_cmn_tunables *tunables,
2632                           struct cfs_expr_list **global_cpts)
2633 {
2634         struct cYAML *tun, *item, *smp;
2635         int rc;
2636
2637         tun = cYAML_get_object_item(tree, "tunables");
2638         if (tun != NULL) {
2639                 item = cYAML_get_object_item(tun, "peer_timeout");
2640                 if (item != NULL)
2641                         tunables->lct_peer_timeout = item->cy_valueint;
2642                 item = cYAML_get_object_item(tun, "peer_credits");
2643                 if (item != NULL)
2644                         tunables->lct_peer_tx_credits = item->cy_valueint;
2645                 item = cYAML_get_object_item(tun, "peer_buffer_credits");
2646                 if (item != NULL)
2647                         tunables->lct_peer_rtr_credits = item->cy_valueint;
2648                 item = cYAML_get_object_item(tun, "credits");
2649                 if (item != NULL)
2650                         tunables->lct_max_tx_credits = item->cy_valueint;
2651                 smp = cYAML_get_object_item(tun, "CPT");
2652                 if (smp != NULL) {
2653                         rc = cfs_expr_list_parse(smp->cy_valuestring,
2654                                                  strlen(smp->cy_valuestring),
2655                                                  0, UINT_MAX, global_cpts);
2656                         if (rc != 0)
2657                                 *global_cpts = NULL;
2658                 }
2659
2660                 return true;
2661         }
2662
2663         return false;
2664 }
2665
2666 static bool
2667 yaml_extract_tunables(struct cYAML *tree,
2668                       struct lnet_ioctl_config_lnd_tunables *tunables,
2669                       struct cfs_expr_list **global_cpts,
2670                       __u32 net_type)
2671 {
2672         bool rc;
2673
2674         rc = yaml_extract_cmn_tunables(tree, &tunables->lt_cmn,
2675                                        global_cpts);
2676
2677         if (!rc)
2678                 return rc;
2679
2680         lustre_yaml_extract_lnd_tunables(tree, net_type,
2681                                          &tunables->lt_tun);
2682
2683         return rc;
2684 }
2685
2686 /*
2687  * net:
2688  *    - net type: <net>[<NUM>]
2689   *      local NI(s):
2690  *        - nid: <ip>@<net>[<NUM>]
2691  *          status: up
2692  *          interfaces:
2693  *               0: <intf_name>['['<expr>']']
2694  *               1: <intf_name>['['<expr>']']
2695  *        tunables:
2696  *               peer_timeout: <NUM>
2697  *               peer_credits: <NUM>
2698  *               peer_buffer_credits: <NUM>
2699  *               credits: <NUM>
2700 *         lnd tunables:
2701  *               peercredits_hiw: <NUM>
2702  *               map_on_demand: <NUM>
2703  *               concurrent_sends: <NUM>
2704  *               fmr_pool_size: <NUM>
2705  *               fmr_flush_trigger: <NUM>
2706  *               fmr_cache: <NUM>
2707  *
2708  * At least one interface is required. If no interfaces are provided the
2709  * network interface can not be configured.
2710  */
2711 static int handle_yaml_config_ni(struct cYAML *tree, struct cYAML **show_rc,
2712                                  struct cYAML **err_rc)
2713 {
2714         struct cYAML *net, *intf, *seq_no, *ip2net = NULL, *local_nis = NULL,
2715                      *item = NULL;
2716         int num_entries = 0, rc;
2717         struct lnet_dlc_network_descr nw_descr;
2718         struct cfs_expr_list *global_cpts = NULL;
2719         struct lnet_ioctl_config_lnd_tunables tunables;
2720         bool found = false;
2721
2722         memset(&tunables, 0, sizeof(tunables));
2723
2724         INIT_LIST_HEAD(&nw_descr.network_on_rule);
2725         INIT_LIST_HEAD(&nw_descr.nw_intflist);
2726
2727         ip2net = cYAML_get_object_item(tree, "ip2net");
2728         net = cYAML_get_object_item(tree, "net type");
2729         if (net)
2730                 nw_descr.nw_id = libcfs_str2net(net->cy_valuestring);
2731         else
2732                 nw_descr.nw_id = LOLND;
2733
2734         /*
2735          * if neither net nor ip2nets are present, then we can not
2736          * configure the network.
2737          */
2738         if (!net && !ip2net)
2739                 return LUSTRE_CFG_RC_MISSING_PARAM;
2740
2741         local_nis = cYAML_get_object_item(tree, "local NI(s)");
2742         if (local_nis == NULL)
2743                 return LUSTRE_CFG_RC_MISSING_PARAM;
2744
2745         if (!cYAML_is_sequence(local_nis))
2746                 return LUSTRE_CFG_RC_BAD_PARAM;
2747
2748         while (cYAML_get_next_seq_item(local_nis, &item) != NULL) {
2749                 intf = cYAML_get_object_item(item, "interfaces");
2750                 if (intf == NULL)
2751                         continue;
2752                 num_entries = yaml_copy_intf_info(intf, &nw_descr);
2753                 if (num_entries <= 0) {
2754                         cYAML_build_error(num_entries, -1, "ni", "add",
2755                                         "bad interface list",
2756                                         err_rc);
2757                         return LUSTRE_CFG_RC_BAD_PARAM;
2758                 }
2759         }
2760
2761         found = yaml_extract_tunables(tree, &tunables, &global_cpts,
2762                                       LNET_NETTYP(nw_descr.nw_id));
2763         seq_no = cYAML_get_object_item(tree, "seq_no");
2764
2765         rc = lustre_lnet_config_ni(&nw_descr,
2766                                    global_cpts,
2767                                    (ip2net) ? ip2net->cy_valuestring : NULL,
2768                                    (found) ? &tunables: NULL,
2769                                    (seq_no) ? seq_no->cy_valueint : -1,
2770                                    err_rc);
2771
2772         if (global_cpts != NULL)
2773                 cfs_expr_list_free(global_cpts);
2774
2775         return rc;
2776 }
2777
2778 /*
2779  * ip2nets:
2780  *  - net-spec: <tcp|o2ib|gni>[NUM]
2781  *    interfaces:
2782  *        0: <intf name>['['<expr>']']
2783  *        1: <intf name>['['<expr>']']
2784  *    ip-range:
2785  *        0: <expr.expr.expr.expr>
2786  *        1: <expr.expr.expr.expr>
2787  */
2788 static int handle_yaml_config_ip2nets(struct cYAML *tree,
2789                                       struct cYAML **show_rc,
2790                                       struct cYAML **err_rc)
2791 {
2792         struct cYAML *net, *ip_range, *item = NULL, *intf = NULL,
2793                      *seq_no = NULL;
2794         struct lustre_lnet_ip2nets ip2nets;
2795         struct lustre_lnet_ip_range_descr *ip_range_descr = NULL,
2796                                           *tmp = NULL;
2797         int rc = LUSTRE_CFG_RC_NO_ERR;
2798         struct cfs_expr_list *global_cpts = NULL;
2799         struct cfs_expr_list *el, *el_tmp;
2800         struct lnet_ioctl_config_lnd_tunables tunables;
2801         struct lnet_dlc_intf_descr *intf_descr, *intf_tmp;
2802         bool found = false;
2803
2804         memset(&tunables, 0, sizeof(tunables));
2805
2806         /* initialize all lists */
2807         INIT_LIST_HEAD(&ip2nets.ip2nets_ip_ranges);
2808         INIT_LIST_HEAD(&ip2nets.ip2nets_net.network_on_rule);
2809         INIT_LIST_HEAD(&ip2nets.ip2nets_net.nw_intflist);
2810
2811         net = cYAML_get_object_item(tree, "net-spec");
2812         if (net == NULL)
2813                 return LUSTRE_CFG_RC_BAD_PARAM;
2814
2815         if (net != NULL && net->cy_valuestring == NULL)
2816                 return LUSTRE_CFG_RC_BAD_PARAM;
2817
2818         /* assign the network id */
2819         ip2nets.ip2nets_net.nw_id = libcfs_str2net(net->cy_valuestring);
2820         if (ip2nets.ip2nets_net.nw_id == LNET_NID_ANY)
2821                 return LUSTRE_CFG_RC_BAD_PARAM;
2822
2823         seq_no = cYAML_get_object_item(tree, "seq_no");
2824
2825         intf = cYAML_get_object_item(tree, "interfaces");
2826         if (intf != NULL) {
2827                 rc = yaml_copy_intf_info(intf, &ip2nets.ip2nets_net);
2828                 if (rc <= 0)
2829                         return LUSTRE_CFG_RC_BAD_PARAM;
2830         }
2831
2832         ip_range = cYAML_get_object_item(tree, "ip-range");
2833         if (ip_range != NULL) {
2834                 item = ip_range->cy_child;
2835                 while (item != NULL) {
2836                         if (item->cy_valuestring == NULL) {
2837                                 item = item->cy_next;
2838                                 continue;
2839                         }
2840
2841                         rc = lustre_lnet_add_ip_range(&ip2nets.ip2nets_ip_ranges,
2842                                                       item->cy_valuestring);
2843
2844                         if (rc != LUSTRE_CFG_RC_NO_ERR)
2845                                 goto out;
2846
2847                         item = item->cy_next;
2848                 }
2849         }
2850
2851         found = yaml_extract_tunables(tree, &tunables, &global_cpts,
2852                                       LNET_NETTYP(ip2nets.ip2nets_net.nw_id));
2853
2854         rc = lustre_lnet_config_ip2nets(&ip2nets,
2855                         (found) ? &tunables : NULL,
2856                         global_cpts,
2857                         (seq_no) ? seq_no->cy_valueint : -1,
2858                         err_rc);
2859
2860         /*
2861          * don't stop because there was no match. Continue processing the
2862          * rest of the rules. If non-match then nothing is configured
2863          */
2864         if (rc == LUSTRE_CFG_RC_NO_MATCH)
2865                 rc = LUSTRE_CFG_RC_NO_ERR;
2866 out:
2867         list_for_each_entry_safe(intf_descr, intf_tmp,
2868                                  &ip2nets.ip2nets_net.nw_intflist,
2869                                  intf_on_network) {
2870                 list_del(&intf_descr->intf_on_network);
2871                 free_intf_descr(intf_descr);
2872         }
2873
2874         list_for_each_entry_safe(ip_range_descr, tmp,
2875                                  &ip2nets.ip2nets_ip_ranges,
2876                                  ipr_entry) {
2877                 list_del(&ip_range_descr->ipr_entry);
2878                 list_for_each_entry_safe(el, el_tmp, &ip_range_descr->ipr_expr,
2879                                          el_link) {
2880                         list_del(&el->el_link);
2881                         cfs_expr_list_free(el);
2882                 }
2883                 free(ip_range_descr);
2884         }
2885
2886         return rc;
2887 }
2888
2889 static int handle_yaml_del_ni(struct cYAML *tree, struct cYAML **show_rc,
2890                               struct cYAML **err_rc)
2891 {
2892         struct cYAML *net = NULL, *intf = NULL, *seq_no = NULL, *item = NULL,
2893                      *local_nis = NULL;
2894         int num_entries, rc;
2895         struct lnet_dlc_network_descr nw_descr;
2896
2897         INIT_LIST_HEAD(&nw_descr.network_on_rule);
2898         INIT_LIST_HEAD(&nw_descr.nw_intflist);
2899
2900         net = cYAML_get_object_item(tree, "net type");
2901         if (net != NULL)
2902                 nw_descr.nw_id = libcfs_str2net(net->cy_valuestring);
2903
2904         local_nis = cYAML_get_object_item(tree, "local NI(s)");
2905         if (local_nis == NULL)
2906                 return LUSTRE_CFG_RC_MISSING_PARAM;
2907
2908         if (!cYAML_is_sequence(local_nis))
2909                 return LUSTRE_CFG_RC_BAD_PARAM;
2910
2911         while (cYAML_get_next_seq_item(local_nis, &item) != NULL) {
2912                 intf = cYAML_get_object_item(item, "interfaces");
2913                 if (intf == NULL)
2914                         continue;
2915                 num_entries = yaml_copy_intf_info(intf, &nw_descr);
2916                 if (num_entries <= 0) {
2917                         cYAML_build_error(num_entries, -1, "ni", "add",
2918                                         "bad interface list",
2919                                         err_rc);
2920                         return LUSTRE_CFG_RC_BAD_PARAM;
2921                 }
2922         }
2923
2924         seq_no = cYAML_get_object_item(tree, "seq_no");
2925
2926         rc = lustre_lnet_del_ni((net) ? &nw_descr : NULL,
2927                                 (seq_no) ? seq_no->cy_valueint : -1,
2928                                 err_rc);
2929
2930         return rc;
2931 }
2932
2933 static int yaml_copy_peer_nids(struct cYAML *nids_entry, char ***nidsppp,
2934                                char *prim_nid, bool del)
2935 {
2936         struct cYAML *child = NULL, *entry = NULL;
2937         char **nids = NULL;
2938         int num = 0, rc = LUSTRE_CFG_RC_NO_ERR;
2939
2940         if (cYAML_is_sequence(nids_entry)) {
2941                 while (cYAML_get_next_seq_item(nids_entry, &child)) {
2942                         entry = cYAML_get_object_item(child, "nid");
2943                         /* don't count an empty entry */
2944                         if (!entry || !entry->cy_valuestring)
2945                                 continue;
2946
2947                         if (prim_nid &&
2948                             (strcmp(entry->cy_valuestring, prim_nid)
2949                                         == 0) && del) {
2950                                 /*
2951                                  * primary nid is present in the list of
2952                                  * nids so that means we want to delete
2953                                  * the entire peer, so no need to go
2954                                  * further. Just delete the entire peer.
2955                                  */
2956                                 return 0;
2957                         }
2958
2959                         num++;
2960                 }
2961         }
2962
2963         if (num == 0)
2964                 return LUSTRE_CFG_RC_MISSING_PARAM;
2965
2966         nids = calloc(sizeof(*nids), num);
2967         if (!nids)
2968                 return LUSTRE_CFG_RC_OUT_OF_MEM;
2969
2970         /* now grab all the nids */
2971         num = 0;
2972         child = NULL;
2973         while (cYAML_get_next_seq_item(nids_entry, &child)) {
2974                 entry = cYAML_get_object_item(child, "nid");
2975                 if (!entry || !entry->cy_valuestring)
2976                         continue;
2977
2978                 nids[num] = calloc(strlen(entry->cy_valuestring) + 1, 1);
2979                 if (!nids[num]) {
2980                         rc = LUSTRE_CFG_RC_OUT_OF_MEM;
2981                         goto failed;
2982                 }
2983                 strncpy(nids[num], entry->cy_valuestring,
2984                         strlen(entry->cy_valuestring));
2985                 num++;
2986         }
2987         rc = num;
2988
2989         *nidsppp = nids;
2990         return rc;
2991
2992 failed:
2993         if (nids != NULL)
2994                 yaml_free_string_array(nids, num);
2995         *nidsppp = NULL;
2996         return rc;
2997 }
2998
2999 static int handle_yaml_config_peer(struct cYAML *tree, struct cYAML **show_rc,
3000                                    struct cYAML **err_rc)
3001 {
3002         char **nids = NULL;
3003         int num, rc;
3004         struct cYAML *seq_no, *prim_nid, *non_mr, *ip2nets, *peer_nis;
3005         char err_str[LNET_MAX_STR_LEN];
3006
3007         seq_no = cYAML_get_object_item(tree, "seq_no");
3008         prim_nid = cYAML_get_object_item(tree, "primary nid");
3009         non_mr = cYAML_get_object_item(tree, "non_mr");
3010         ip2nets = cYAML_get_object_item(tree, "ip2nets");
3011         peer_nis = cYAML_get_object_item(tree, "peer ni");
3012
3013         if (ip2nets && (prim_nid || peer_nis)) {
3014                 rc = LUSTRE_CFG_RC_BAD_PARAM;
3015                 snprintf(err_str, sizeof(err_str),
3016                          "ip2nets can not be specified along side prim_nid"
3017                          " or peer ni fields");
3018                 cYAML_build_error(rc, (seq_no) ? seq_no->cy_valueint : -1,
3019                                   ADD_CMD, "peer", err_str, err_rc);
3020                 return rc;
3021         }
3022
3023         num = yaml_copy_peer_nids((ip2nets) ? ip2nets : peer_nis, &nids,
3024                                   (prim_nid) ? prim_nid->cy_valuestring : NULL,
3025                                    false);
3026
3027         if (num < 0) {
3028                 snprintf(err_str, sizeof(err_str),
3029                          "error copying nids from YAML block");
3030                 cYAML_build_error(num, (seq_no) ? seq_no->cy_valueint : -1,
3031                                   ADD_CMD, "peer", err_str, err_rc);
3032                 return num;
3033         }
3034
3035         rc = lustre_lnet_config_peer_nid((prim_nid) ? prim_nid->cy_valuestring : NULL,
3036                                          nids, num,
3037                                          (non_mr) ? false : true,
3038                                          (ip2nets) ? true : false,
3039                                          (seq_no) ? seq_no->cy_valueint : -1,
3040                                          err_rc);
3041
3042         yaml_free_string_array(nids, num);
3043         return rc;
3044 }
3045
3046 static int handle_yaml_del_peer(struct cYAML *tree, struct cYAML **show_rc,
3047                                 struct cYAML **err_rc)
3048 {
3049         char **nids = NULL;
3050         int num, rc;
3051         struct cYAML *seq_no, *prim_nid, *ip2nets, *peer_nis;
3052         char err_str[LNET_MAX_STR_LEN];
3053
3054         seq_no = cYAML_get_object_item(tree, "seq_no");
3055         prim_nid = cYAML_get_object_item(tree, "primary nid");
3056         ip2nets = cYAML_get_object_item(tree, "ip2nets");
3057         peer_nis = cYAML_get_object_item(tree, "peer ni");
3058
3059         if (ip2nets && (prim_nid || peer_nis)) {
3060                 rc = LUSTRE_CFG_RC_BAD_PARAM;
3061                 snprintf(err_str, sizeof(err_str),
3062                          "ip2nets can not be specified along side prim_nid"
3063                          " or peer ni fields");
3064                 cYAML_build_error(rc, (seq_no) ? seq_no->cy_valueint : -1,
3065                                   DEL_CMD, "peer", err_str, err_rc);
3066                 return rc;
3067         }
3068
3069         num = yaml_copy_peer_nids((ip2nets) ? ip2nets : peer_nis , &nids,
3070                                   (prim_nid) ? prim_nid->cy_valuestring : NULL,
3071                                   true);
3072         if (num < 0) {
3073                 snprintf(err_str, sizeof(err_str),
3074                          "error copying nids from YAML block");
3075                 cYAML_build_error(num, (seq_no) ? seq_no->cy_valueint : -1,
3076                                   ADD_CMD, "peer", err_str, err_rc);
3077                 return num;
3078         }
3079
3080         rc = lustre_lnet_del_peer_nid((prim_nid) ? prim_nid->cy_valuestring : NULL,
3081                                       nids, num, (ip2nets) ? true : false,
3082                                       (seq_no) ? seq_no->cy_valueint : -1,
3083                                       err_rc);
3084
3085         yaml_free_string_array(nids, num);
3086         return rc;
3087 }
3088
3089 static int handle_yaml_config_buffers(struct cYAML *tree,
3090                                       struct cYAML **show_rc,
3091                                       struct cYAML **err_rc)
3092 {
3093         int rc;
3094         struct cYAML *tiny, *small, *large, *seq_no;
3095
3096         tiny = cYAML_get_object_item(tree, "tiny");
3097         small = cYAML_get_object_item(tree, "small");
3098         large = cYAML_get_object_item(tree, "large");
3099         seq_no = cYAML_get_object_item(tree, "seq_no");
3100
3101         rc = lustre_lnet_config_buffers((tiny) ? tiny->cy_valueint : -1,
3102                                         (small) ? small->cy_valueint : -1,
3103                                         (large) ? large->cy_valueint : -1,
3104                                         (seq_no) ? seq_no->cy_valueint : -1,
3105                                         err_rc);
3106
3107         return rc;
3108 }
3109
3110 static int handle_yaml_config_routing(struct cYAML *tree,
3111                                       struct cYAML **show_rc,
3112                                       struct cYAML **err_rc)
3113 {
3114         int rc = LUSTRE_CFG_RC_NO_ERR;
3115         struct cYAML *seq_no, *enable;
3116
3117         seq_no = cYAML_get_object_item(tree, "seq_no");
3118         enable = cYAML_get_object_item(tree, "enable");
3119
3120         if (enable) {
3121                 rc = lustre_lnet_enable_routing(enable->cy_valueint,
3122                                                 (seq_no) ?
3123                                                     seq_no->cy_valueint : -1,
3124                                                 err_rc);
3125         }
3126
3127         return rc;
3128 }
3129
3130 static int handle_yaml_del_route(struct cYAML *tree, struct cYAML **show_rc,
3131                                  struct cYAML **err_rc)
3132 {
3133         struct cYAML *net;
3134         struct cYAML *gw;
3135         struct cYAML *seq_no;
3136
3137         net = cYAML_get_object_item(tree, "net");
3138         gw = cYAML_get_object_item(tree, "gateway");
3139         seq_no = cYAML_get_object_item(tree, "seq_no");
3140
3141         return lustre_lnet_del_route((net) ? net->cy_valuestring : NULL,
3142                                      (gw) ? gw->cy_valuestring : NULL,
3143                                      (seq_no) ? seq_no->cy_valueint : -1,
3144                                      err_rc);
3145 }
3146
3147 static int handle_yaml_del_routing(struct cYAML *tree, struct cYAML **show_rc,
3148                                    struct cYAML **err_rc)
3149 {
3150         struct cYAML *seq_no;
3151
3152         seq_no = cYAML_get_object_item(tree, "seq_no");
3153
3154         return lustre_lnet_enable_routing(0, (seq_no) ?
3155                                                 seq_no->cy_valueint : -1,
3156                                         err_rc);
3157 }
3158
3159 static int handle_yaml_show_route(struct cYAML *tree, struct cYAML **show_rc,
3160                                   struct cYAML **err_rc)
3161 {
3162         struct cYAML *net;
3163         struct cYAML *gw;
3164         struct cYAML *hop;
3165         struct cYAML *prio;
3166         struct cYAML *detail;
3167         struct cYAML *seq_no;
3168
3169         net = cYAML_get_object_item(tree, "net");
3170         gw = cYAML_get_object_item(tree, "gateway");
3171         hop = cYAML_get_object_item(tree, "hop");
3172         prio = cYAML_get_object_item(tree, "priority");
3173         detail = cYAML_get_object_item(tree, "detail");
3174         seq_no = cYAML_get_object_item(tree, "seq_no");
3175
3176         return lustre_lnet_show_route((net) ? net->cy_valuestring : NULL,
3177                                       (gw) ? gw->cy_valuestring : NULL,
3178                                       (hop) ? hop->cy_valueint : -1,
3179                                       (prio) ? prio->cy_valueint : -1,
3180                                       (detail) ? detail->cy_valueint : 0,
3181                                       (seq_no) ? seq_no->cy_valueint : -1,
3182                                       show_rc,
3183                                       err_rc);
3184 }
3185
3186 static int handle_yaml_show_net(struct cYAML *tree, struct cYAML **show_rc,
3187                                 struct cYAML **err_rc)
3188 {
3189         struct cYAML *net, *detail, *seq_no;
3190
3191         net = cYAML_get_object_item(tree, "net");
3192         detail = cYAML_get_object_item(tree, "detail");
3193         seq_no = cYAML_get_object_item(tree, "seq_no");
3194
3195         return lustre_lnet_show_net((net) ? net->cy_valuestring : NULL,
3196                                     (detail) ? detail->cy_valueint : 0,
3197                                     (seq_no) ? seq_no->cy_valueint : -1,
3198                                     show_rc,
3199                                     err_rc);
3200 }
3201
3202 static int handle_yaml_show_routing(struct cYAML *tree, struct cYAML **show_rc,
3203                                     struct cYAML **err_rc)
3204 {
3205         struct cYAML *seq_no;
3206
3207         seq_no = cYAML_get_object_item(tree, "seq_no");
3208
3209         return lustre_lnet_show_routing((seq_no) ? seq_no->cy_valueint : -1,
3210                                         show_rc, err_rc);
3211 }
3212
3213 static int handle_yaml_show_peers(struct cYAML *tree, struct cYAML **show_rc,
3214                                   struct cYAML **err_rc)
3215 {
3216         struct cYAML *seq_no, *nid, *detail;
3217
3218         seq_no = cYAML_get_object_item(tree, "seq_no");
3219         detail = cYAML_get_object_item(tree, "detail");
3220         nid = cYAML_get_object_item(tree, "nid");
3221
3222         return lustre_lnet_show_peer((nid) ? nid->cy_valuestring : NULL,
3223                                      (detail) ? detail->cy_valueint : 0,
3224                                      (seq_no) ? seq_no->cy_valueint : -1,
3225                                      show_rc, err_rc);
3226 }
3227
3228 static int handle_yaml_show_stats(struct cYAML *tree, struct cYAML **show_rc,
3229                                   struct cYAML **err_rc)
3230 {
3231         struct cYAML *seq_no;
3232
3233         seq_no = cYAML_get_object_item(tree, "seq_no");
3234
3235         return lustre_lnet_show_stats((seq_no) ? seq_no->cy_valueint : -1,
3236                                       show_rc, err_rc);
3237 }
3238
3239 static int handle_yaml_config_numa(struct cYAML *tree, struct cYAML **show_rc,
3240                                   struct cYAML **err_rc)
3241 {
3242         struct cYAML *seq_no, *range;
3243
3244         seq_no = cYAML_get_object_item(tree, "seq_no");
3245         range = cYAML_get_object_item(tree, "range");
3246
3247         return lustre_lnet_config_numa_range(range ? range->cy_valueint : -1,
3248                                              seq_no ? seq_no->cy_valueint : -1,
3249                                              err_rc);
3250 }
3251
3252 static int handle_yaml_del_numa(struct cYAML *tree, struct cYAML **show_rc,
3253                                struct cYAML **err_rc)
3254 {
3255         struct cYAML *seq_no;
3256
3257         seq_no = cYAML_get_object_item(tree, "seq_no");
3258
3259         return lustre_lnet_config_numa_range(0, seq_no ? seq_no->cy_valueint : -1,
3260                                              err_rc);
3261 }
3262
3263 static int handle_yaml_show_numa(struct cYAML *tree, struct cYAML **show_rc,
3264                                 struct cYAML **err_rc)
3265 {
3266         struct cYAML *seq_no;
3267
3268         seq_no = cYAML_get_object_item(tree, "seq_no");
3269
3270         return lustre_lnet_show_numa_range(seq_no ? seq_no->cy_valueint : -1,
3271                                            show_rc, err_rc);
3272 }
3273
3274 struct lookup_cmd_hdlr_tbl {
3275         char *name;
3276         cmd_handler_t cb;
3277 };
3278
3279 static struct lookup_cmd_hdlr_tbl lookup_config_tbl[] = {
3280         { .name = "route",      .cb = handle_yaml_config_route },
3281         { .name = "net",        .cb = handle_yaml_config_ni },
3282         { .name = "ip2nets",    .cb = handle_yaml_config_ip2nets },
3283         { .name = "peer",       .cb = handle_yaml_config_peer },
3284         { .name = "routing",    .cb = handle_yaml_config_routing },
3285         { .name = "buffers",    .cb = handle_yaml_config_buffers },
3286         { .name = "numa",       .cb = handle_yaml_config_numa },
3287         { .name = NULL } };
3288
3289 static struct lookup_cmd_hdlr_tbl lookup_del_tbl[] = {
3290         { .name = "route",      .cb = handle_yaml_del_route },
3291         { .name = "net",        .cb = handle_yaml_del_ni },
3292         { .name = "peer",       .cb = handle_yaml_del_peer },
3293         { .name = "routing",    .cb = handle_yaml_del_routing },
3294         { .name = "numa",       .cb = handle_yaml_del_numa },
3295         { .name = NULL } };
3296
3297 static struct lookup_cmd_hdlr_tbl lookup_show_tbl[] = {
3298         { .name = "route",      .cb = handle_yaml_show_route },
3299         { .name = "net",        .cb = handle_yaml_show_net },
3300         { .name = "buffers",    .cb = handle_yaml_show_routing },
3301         { .name = "routing",    .cb = handle_yaml_show_routing },
3302         { .name = "peer",       .cb = handle_yaml_show_peers },
3303         { .name = "statistics", .cb = handle_yaml_show_stats },
3304         { .name = "numa",       .cb = handle_yaml_show_numa },
3305         { .name = NULL } };
3306
3307 static cmd_handler_t lookup_fn(char *key,
3308                                struct lookup_cmd_hdlr_tbl *tbl)
3309 {
3310         int i;
3311         if (key == NULL)
3312                 return NULL;
3313
3314         for (i = 0; tbl[i].name != NULL; i++) {
3315                 if (strncmp(key, tbl[i].name, strlen(tbl[i].name)) == 0)
3316                         return tbl[i].cb;
3317         }
3318
3319         return NULL;
3320 }
3321
3322 static int lustre_yaml_cb_helper(char *f, struct lookup_cmd_hdlr_tbl *table,
3323                                  struct cYAML **show_rc, struct cYAML **err_rc)
3324 {
3325         struct cYAML *tree, *item = NULL, *head, *child;
3326         cmd_handler_t cb;
3327         char err_str[LNET_MAX_STR_LEN];
3328         int rc = LUSTRE_CFG_RC_NO_ERR, return_rc = LUSTRE_CFG_RC_NO_ERR;
3329
3330         tree = cYAML_build_tree(f, NULL, 0, err_rc, false);
3331         if (tree == NULL)
3332                 return LUSTRE_CFG_RC_BAD_PARAM;
3333
3334         child = tree->cy_child;
3335         while (child != NULL) {
3336                 cb = lookup_fn(child->cy_string, table);
3337                 if (cb == NULL) {
3338                         snprintf(err_str, sizeof(err_str),
3339                                 "\"call back for '%s' not found\"",
3340                                 child->cy_string);
3341                         cYAML_build_error(LUSTRE_CFG_RC_BAD_PARAM, -1,
3342                                         "yaml", "helper", err_str, err_rc);
3343                         goto out;
3344                 }
3345
3346                 if (cYAML_is_sequence(child)) {
3347                         while ((head = cYAML_get_next_seq_item(child, &item))
3348                                != NULL) {
3349                                 rc = cb(head, show_rc, err_rc);
3350                                 if (rc != LUSTRE_CFG_RC_NO_ERR)
3351                                         return_rc = rc;
3352                         }
3353                 } else {
3354                         rc = cb(child, show_rc, err_rc);
3355                         if (rc != LUSTRE_CFG_RC_NO_ERR)
3356                                 return_rc = rc;
3357                 }
3358                 item = NULL;
3359                 child = child->cy_next;
3360         }
3361
3362 out:
3363         cYAML_free_tree(tree);
3364
3365         return return_rc;
3366 }
3367
3368 int lustre_yaml_config(char *f, struct cYAML **err_rc)
3369 {
3370         return lustre_yaml_cb_helper(f, lookup_config_tbl,
3371                                      NULL, err_rc);
3372 }
3373
3374 int lustre_yaml_del(char *f, struct cYAML **err_rc)
3375 {
3376         return lustre_yaml_cb_helper(f, lookup_del_tbl,
3377                                      NULL, err_rc);
3378 }
3379
3380 int lustre_yaml_show(char *f, struct cYAML **show_rc, struct cYAML **err_rc)
3381 {
3382         return lustre_yaml_cb_helper(f, lookup_show_tbl,
3383                                      show_rc, err_rc);
3384 }
3385