Whamcloud - gitweb
LU-2456 lnet: DLC user space Configuration library 25/8025/63
authorAmir Shehata <amir.shehata@intel.com>
Tue, 15 Oct 2013 20:12:54 +0000 (13:12 -0700)
committerAndreas Dilger <andreas.dilger@intel.com>
Wed, 22 Oct 2014 05:05:49 +0000 (05:05 +0000)
This is the seventh patch of a set of patches that enables DLC.

This patch adds a user space library liblnetconfig, which provides
an API to add/delete/show LNET parameters.  This library has been
added to the /lnet/utils/lnetconfig directory.

There are two sets of APIs which are presented.  There are the
APIs which configure a specific parameter such as routes, and
there are a set of APIs which take in a YAML block of entities
which are then added/deleted/showed.  The latter is intended for
use by IML or other similar tools.

All APIs return a cYAML error block, and the show APIs return a
cYAML show block as well.  The cYAML block is a structural
represenation of a YAML block.  This can be stored/queried/printed
and deleted by the caller of the API.  A cYAML API is provided
to facilitate these operations

DLC can be enabled via --enable-dlc or disabled via --disable-dlc
parameters passed to configure.  DLC is by default enabled.
If the yaml library is installed and --enable-dlc is set then
dlc is added to the build, otherwise if libyaml is not installed
or --disable-dlc is set then dlc is not added to the build.

When building the rpm, this configure options are used to decide
to add the Require and BuildRequire conditions or not.

Currently SLES doesn't include libyaml package so it will need
to be installed manually if users want to build DLC

Signed-off-by: Amir Shehata <amir.shehata@intel.com>
Change-Id: Id6f7eeff8c63ab3f3b27fca92dc31066f7b87968
Reviewed-on: http://review.whamcloud.com/8025
Reviewed-by: John L. Hammond <john.hammond@intel.com>
Tested-by: Jenkins
Reviewed-by: James Simmons <uja.ornl@gmail.com>
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
config/lustre-build.m4
lnet/autoconf/lustre-lnet.m4
lnet/utils/Makefile.am
lnet/utils/cyaml/cyaml.c [new file with mode: 0644]
lnet/utils/cyaml/cyaml.h [new file with mode: 0644]
lnet/utils/lnetconfig/.gitignore [new file with mode: 0644]
lnet/utils/lnetconfig/Makefile.am [new file with mode: 0644]
lnet/utils/lnetconfig/liblnetconfig.c [new file with mode: 0644]
lnet/utils/lnetconfig/liblnetconfig.h [new file with mode: 0644]
lustre.spec.in

index 496303b..d5bbbd5 100644 (file)
@@ -599,6 +599,10 @@ if test x$enable_iokit != xyes ; then
        RPMBINARGS="$RPMBINARGS --without lustre_iokit"
        RPMSRCARGS="$RPMSRCARGS --without lustre_iokit"
 fi
+if test x$BUILD_DLC != xyes ; then
+       RPMBINARGS="$RPMBINARGS --without lnet_dlc"
+       RPMSRCARGS="$RPMSRCARGS --without lnet_dlc"
+fi
 
 RPMBUILD_BINARY_ARGS=$RPMBINARGS
 RPMBUILD_SOURCE_ARGS=$RPMSRCARGS
index 1df8ca3..314e935 100644 (file)
@@ -139,6 +139,36 @@ AC_SUBST(USOCKLND)
 ]) # LN_CONFIG_USOCKLND
 
 #
+# LN_CONFIG_DLC
+#
+# Configure dlc if enabled
+#
+# if libyaml is set (IE libyaml installed) and enable_dlc = yes then build
+# dlc other wise (IE if libyaml is not set or enable_dlc = no) then don't
+# build dlc.
+#
+AC_DEFUN([LN_CONFIG_DLC], [
+       AC_CHECK_LIB([yaml],  [yaml_parser_initialize],[
+               LIBYAML="libyaml"],[
+               LIBYAML=""],[-lm])
+       AC_MSG_CHECKING([whether to enable dlc])
+       AC_ARG_ENABLE([dlc],
+               AC_HELP_STRING([--disable-dlc],
+                       [disable building dlc]),
+                       [], [enable_dlc="yes"])
+       AC_MSG_RESULT([$enable_dlc])
+       USE_DLC=""
+       AS_IF([test "x$enable_dlc" = xyes],
+             [AS_IF([test "x$LIBYAML" = xlibyaml], [
+                       USE_DLC="yes"
+               ], [
+                       AC_MSG_RESULT([no (libyaml not present)])
+               ])
+       ])
+       AC_SUBST(USE_DLC)
+])
+
+#
 # LN_CONFIG_QUADRICS
 #
 # check if quadrics support is in this kernel
@@ -667,6 +697,7 @@ AC_SUBST(LIBWRAP)
 
 LN_CONFIG_MAX_PAYLOAD
 LN_CONFIG_USOCKLND
+LN_CONFIG_DLC
 ]) # LN_CONFIGURE
 
 #
@@ -682,6 +713,7 @@ AM_CONDITIONAL(BUILD_RALND,      test x$RALND = "xralnd")
 AM_CONDITIONAL(BUILD_GNILND,     test x$GNILND = "xgnilnd")
 AM_CONDITIONAL(BUILD_GNILND_RCA, test x$GNILNDRCA = "xgnilndrca")
 AM_CONDITIONAL(BUILD_USOCKLND,   test x$USOCKLND = "xusocklnd")
+AM_CONDITIONAL(BUILD_DLC,        test x$USE_DLC = "xyes")
 ]) # LN_CONDITIONALS
 
 #
@@ -721,5 +753,6 @@ lnet/ulnds/Makefile
 lnet/ulnds/autoMakefile
 lnet/ulnds/socklnd/Makefile
 lnet/utils/Makefile
+lnet/utils/lnetconfig/Makefile
 ])
 ]) # LN_CONFIG_FILES
index d45dcf2..28228ee 100644 (file)
 
 AM_CFLAGS = $(LLCFLAGS)
 
+if BUILD_DLC
+SUBDIRS = lnetconfig
+endif
+
 LIBCFS= $(top_builddir)/libcfs/libcfs/libcfs.a
 LIBCFSUTIL= $(top_builddir)/libcfs/libcfs/libcfsutil.a
 
diff --git a/lnet/utils/cyaml/cyaml.c b/lnet/utils/cyaml/cyaml.c
new file mode 100644 (file)
index 0000000..dccce6c
--- /dev/null
@@ -0,0 +1,1175 @@
+/*
+ * LGPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * LGPL HEADER END
+ *
+ * Copyright (c) 2013, Intel Corporation.
+ *
+ * Author:
+ *   Amir Shehata <amir.shehata@intel.com>
+ */
+
+/*
+ *  The cYAML tree is constructed as an n-tree.
+ *  root -> cmd 1
+ *          ||
+ *          \/
+ *          cmd 2 -> attr1 -> attr2
+ *                             ||
+ *                             \/
+ *                           attr2.1 -> attr2.1.1 -> attr2.1.2
+ */
+
+#include <yaml.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <float.h>
+#include <limits.h>
+#include <ctype.h>
+#include "libcfs/list.h"
+#include "cyaml.h"
+
+#define INDENT         4
+#define EXTRA_IND      2
+
+/*
+ * cYAML_print_info
+ *   This structure contains print information
+ *   required when printing the node
+ */
+struct cYAML_print_info {
+       int level;
+       int array_first_elem;
+       int extra_ind;
+};
+
+/*
+ *  cYAML_ll
+ *  Linked list of different trees representing YAML
+ *  documents.
+ */
+struct cYAML_ll {
+       struct list_head list;
+       struct cYAML *obj;
+       struct cYAML_print_info *print_info;
+};
+
+static void print_value(FILE *f, struct list_head *stack);
+
+enum cYAML_handler_error {
+       CYAML_ERROR_NONE = 0,
+       CYAML_ERROR_UNEXPECTED_STATE = -1,
+       CYAML_ERROR_NOT_SUPPORTED = -2,
+       CYAML_ERROR_OUT_OF_MEM = -3,
+       CYAML_ERROR_BAD_VALUE = -4,
+       CYAML_ERROR_PARSE = -5,
+};
+
+enum cYAML_tree_state {
+       TREE_STATE_COMPLETE = 0,
+       TREE_STATE_INITED,
+       TREE_STATE_TREE_STARTED,
+       TREE_STATE_BLK_STARTED,
+       TREE_STATE_KEY,
+       TREE_STATE_KEY_FILLED,
+       TREE_STATE_VALUE,
+       TREE_STATE_SEQ_START,
+};
+
+struct cYAML_tree_node {
+       struct cYAML *root;
+       /* cur is the current node we're operating on */
+       struct cYAML *cur;
+       enum cYAML_tree_state state;
+       int from_blk_map_start;
+       /* represents the tree depth */
+       struct list_head ll;
+};
+
+typedef enum cYAML_handler_error (*yaml_token_handler)(yaml_token_t *token,
+                                               struct cYAML_tree_node *);
+
+static enum cYAML_handler_error yaml_parse_error(yaml_token_t *token,
+                                       struct cYAML_tree_node *tree);
+static enum cYAML_handler_error yaml_stream_start(yaml_token_t *token,
+                                       struct cYAML_tree_node *tree);
+static enum cYAML_handler_error yaml_stream_end(yaml_token_t *token,
+                                       struct cYAML_tree_node *tree);
+static enum cYAML_handler_error yaml_not_supported(yaml_token_t *token,
+                                               struct cYAML_tree_node *tree);
+static enum cYAML_handler_error yaml_document_start(yaml_token_t *token,
+                                               struct cYAML_tree_node *tree);
+static enum cYAML_handler_error yaml_document_end(yaml_token_t *token,
+                                              struct cYAML_tree_node *tree);
+static enum cYAML_handler_error yaml_blk_seq_start(yaml_token_t *token,
+                                               struct cYAML_tree_node *tree);
+static enum cYAML_handler_error yaml_blk_mapping_start(yaml_token_t *token,
+                                               struct cYAML_tree_node *tree);
+static enum cYAML_handler_error yaml_block_end(yaml_token_t *token,
+                                       struct cYAML_tree_node *tree);
+static enum cYAML_handler_error yaml_key(yaml_token_t *token,
+                               struct cYAML_tree_node *tree);
+static enum cYAML_handler_error yaml_value(yaml_token_t *token,
+                                       struct cYAML_tree_node *tree);
+static enum cYAML_handler_error yaml_scalar(yaml_token_t *token,
+                                       struct cYAML_tree_node *tree);
+static enum cYAML_handler_error yaml_entry_token(yaml_token_t *token,
+                                       struct cYAML_tree_node *tree);
+
+/* dispatch table */
+static yaml_token_handler dispatch_tbl[] = {
+       [YAML_NO_TOKEN] = yaml_parse_error,
+       [YAML_STREAM_START_TOKEN] = yaml_stream_start,
+       [YAML_STREAM_END_TOKEN] = yaml_stream_end,
+       [YAML_VERSION_DIRECTIVE_TOKEN] = yaml_not_supported,
+       [YAML_TAG_DIRECTIVE_TOKEN] = yaml_not_supported,
+       [YAML_DOCUMENT_START_TOKEN] = yaml_document_start,
+       [YAML_DOCUMENT_END_TOKEN] = yaml_document_end,
+       [YAML_BLOCK_SEQUENCE_START_TOKEN] = yaml_blk_seq_start,
+       [YAML_BLOCK_MAPPING_START_TOKEN] = yaml_blk_mapping_start,
+       [YAML_BLOCK_END_TOKEN] = yaml_block_end,
+       [YAML_FLOW_SEQUENCE_START_TOKEN] = yaml_not_supported,
+       [YAML_FLOW_SEQUENCE_END_TOKEN] = yaml_not_supported,
+       [YAML_FLOW_MAPPING_START_TOKEN] = yaml_not_supported,
+       [YAML_FLOW_MAPPING_END_TOKEN] = yaml_not_supported,
+       [YAML_BLOCK_ENTRY_TOKEN] = yaml_entry_token,
+       [YAML_FLOW_ENTRY_TOKEN] = yaml_not_supported,
+       [YAML_KEY_TOKEN] = yaml_key,
+       [YAML_VALUE_TOKEN] = yaml_value,
+       [YAML_ALIAS_TOKEN] = yaml_not_supported,
+       [YAML_ANCHOR_TOKEN] = yaml_not_supported,
+       [YAML_TAG_TOKEN] = yaml_not_supported,
+       [YAML_SCALAR_TOKEN] = yaml_scalar,
+};
+
+static void cYAML_ll_free(struct list_head *ll)
+{
+       struct cYAML_ll *node, *tmp;
+
+       list_for_each_entry_safe(node, tmp, ll, list) {
+               free(node->print_info);
+               free(node);
+       }
+}
+
+static int cYAML_ll_push(struct cYAML *obj,
+                        const struct cYAML_print_info *print_info,
+                        struct list_head *list)
+{
+       struct cYAML_ll *node = calloc(1, sizeof(*node));
+       if (node == NULL)
+               return -1;
+
+       INIT_LIST_HEAD(&node->list);
+
+       if (print_info) {
+               node->print_info = calloc(1, sizeof(*print_info));
+               if (node->print_info == NULL) {
+                       free(node);
+                       return -1;
+               }
+               *node->print_info = *print_info;
+       }
+       node->obj = obj;
+
+       list_add(&node->list, list);
+
+       return 0;
+}
+
+static struct cYAML *cYAML_ll_pop(struct list_head *list,
+                                 struct cYAML_print_info **print_info)
+{
+       struct cYAML_ll *pop;
+       struct cYAML *obj = NULL;
+
+       if (!list_empty(list)) {
+               pop = list_entry(list->next, struct cYAML_ll, list);
+
+               obj = pop->obj;
+               if (print_info != NULL)
+                       *print_info = pop->print_info;
+               list_del(&pop->list);
+
+               if (print_info == NULL)
+                       free(pop->print_info);
+
+               free(pop);
+       }
+       return obj;
+}
+
+static int cYAML_ll_count(struct list_head *ll)
+{
+       int i = 0;
+       struct list_head *node;
+
+       list_for_each(node, ll)
+               i++;
+
+       return i;
+}
+
+static int cYAML_tree_init(struct cYAML_tree_node *tree)
+{
+       struct cYAML *obj = NULL, *cur = NULL;
+
+       if (tree == NULL)
+               return -1;
+
+       obj = calloc(1, sizeof(*obj));
+       if (obj == NULL)
+               return -1;
+
+       if (tree->root) {
+               /* append the node */
+               cur = tree->root;
+               while (cur->cy_next != NULL)
+                       cur = cur->cy_next;
+               cur->cy_next = obj;
+       } else {
+               tree->root = obj;
+       }
+
+       obj->cy_type = CYAML_TYPE_OBJECT;
+
+       tree->cur = obj;
+       tree->state = TREE_STATE_COMPLETE;
+
+       /* free it and start anew */
+       if (!list_empty(&tree->ll))
+               cYAML_ll_free(&tree->ll);
+
+       return 0;
+}
+
+static struct cYAML *create_child(struct cYAML *parent)
+{
+       struct cYAML *obj;
+
+       if (parent == NULL)
+               return NULL;
+
+       obj = calloc(1, sizeof(*obj));
+       if (obj == NULL)
+               return NULL;
+
+       /* set the type to OBJECT and let the value change that */
+       obj->cy_type = CYAML_TYPE_OBJECT;
+
+       parent->cy_child = obj;
+
+       return obj;
+}
+
+static struct cYAML *create_sibling(struct cYAML *sibling)
+{
+       struct cYAML *obj;
+
+       if (sibling == NULL)
+               return NULL;
+
+       obj = calloc(1, sizeof(*obj));
+       if (obj == NULL)
+               return NULL;
+
+       /* set the type to OBJECT and let the value change that */
+       obj->cy_type = CYAML_TYPE_OBJECT;
+
+       sibling->cy_next = obj;
+       obj->cy_prev = sibling;
+
+       return obj;
+}
+
+/* Parse the input text to generate a number,
+ * and populate the result into item. */
+static bool parse_number(struct cYAML *item, const char *input)
+{
+       double n = 0, sign = 1, scale = 0;
+       int subscale = 0, signsubscale = 1;
+       const char *num = input;
+
+       if (*num == '-') {
+               sign = -1;
+               num++;
+       }
+
+       if (*num == '0')
+               num++;
+
+       if (*num >= '1' && *num <= '9') {
+               do {
+                       n = (n * 10.0) + (*num++ - '0');
+               } while (*num >= '0' && *num <= '9');
+       }
+
+       if (*num == '.' && num[1] >= '0' && num[1] <= '9') {
+               num++;
+               do {
+                       n = (n * 10.0) + (*num++ - '0');
+                       scale--;
+               } while (*num >= '0' && *num <= '9');
+       }
+
+       if (*num == 'e' || *num == 'E') {
+               num++;
+               if (*num == '+') {
+                       num++;
+               } else if (*num == '-') {
+                       signsubscale = -1;
+                       num++;
+               }
+               while (*num >= '0' && *num <= '9')
+                       subscale = (subscale * 10) + (*num++ - '0');
+       }
+
+       /* check to see if the entire string is consumed.  If not then
+        * that means this is a string with a number in it */
+       if (num != (input + strlen(input)))
+               return false;
+
+       /* number = +/- number.fraction * 10^+/- exponent */
+       n = sign * n * pow(10.0, (scale + subscale * signsubscale));
+
+       item->cy_valuedouble = n;
+       item->cy_valueint = (int)n;
+       item->cy_type = CYAML_TYPE_NUMBER;
+
+       return true;
+}
+
+static int assign_type_value(struct cYAML *obj, const char *value)
+{
+       if (value == NULL)
+               return -1;
+
+       if (strcmp(value, "null") == 0)
+               obj->cy_type = CYAML_TYPE_NULL;
+       else if (strcmp(value, "false") == 0) {
+               obj->cy_type = CYAML_TYPE_FALSE;
+               obj->cy_valueint = 0;
+       } else if (strcmp(value, "true") == 0) {
+               obj->cy_type = CYAML_TYPE_TRUE;
+               obj->cy_valueint = 1;
+       } else if (*value == '-' || (*value >= '0' && *value <= '9')) {
+               if (parse_number(obj, value) == 0) {
+                       obj->cy_valuestring = strdup(value);
+                       obj->cy_type = CYAML_TYPE_STRING;
+               }
+       } else {
+               obj->cy_valuestring = strdup(value);
+               obj->cy_type = CYAML_TYPE_STRING;
+       }
+
+       return 0;
+}
+
+/*
+ * yaml_handle_token
+ *  Builds the YAML tree rpresentation as the tokens are passed in
+ *
+ *  if token == STREAM_START && tree_state != COMPLETE
+ *    something wrong. fail.
+ *  else tree_state = INITIED
+ *  if token == DOCUMENT_START && tree_state != COMPLETE || INITED
+ *    something wrong, fail.
+ *  else tree_state = TREE_STARTED
+ *  if token == DOCUMENT_END
+ *    tree_state = INITED if no STREAM START, else tree_state = COMPLETE
+ *    erase everything on ll
+ *  if token == STREAM_END && tree_state != INITED
+ *    something wrong fail.
+ *  else tree_state = COMPLETED
+ *  if token == YAML_KEY_TOKEN && state != TREE_STARTED
+ *    something wrong, fail.
+ *  if token == YAML_SCALAR_TOKEN && state != KEY || VALUE
+ *    fail.
+ *  else if tree_state == KEY
+ *     create a new sibling under the current head of the ll (if ll is
+ *     empty insert the new node there and it becomes the root.)
+ *    add the scalar value in the "string"
+ *    tree_state = KEY_FILLED
+ *  else if tree_state == VALUE
+ *    try and figure out whether this is a double, int or string and store
+ *    it appropriately
+ *    state = TREE_STARTED
+ * else if token == YAML_BLOCK_MAPPING_START_TOKEN && tree_state != VALUE
+ *   fail
+ * else push the current node on the ll && state = TREE_STARTED
+ * if token == YAML_BLOCK_END_TOKEN && state != TREE_STARTED
+ *   fail.
+ * else pop the current token off the ll and make it the cur
+ * if token == YAML_VALUE_TOKEN && state != KEY_FILLED
+ *   fail.
+ * else state = VALUE
+ *
+ */
+static enum cYAML_handler_error yaml_parse_error(yaml_token_t *token,
+                                                struct cYAML_tree_node *tree)
+{
+       return CYAML_ERROR_PARSE;
+}
+
+static enum cYAML_handler_error yaml_stream_start(yaml_token_t *token,
+                                                 struct cYAML_tree_node *tree)
+{
+       enum cYAML_handler_error rc;
+
+       /* with each new stream initialize a new tree */
+       rc = cYAML_tree_init(tree);
+
+       if (rc != CYAML_ERROR_NONE)
+               return rc;
+
+       tree->state = TREE_STATE_INITED;
+
+       return CYAML_ERROR_NONE;
+}
+
+static enum cYAML_handler_error yaml_stream_end(yaml_token_t *token,
+                                               struct cYAML_tree_node *tree)
+{
+       if (tree->state != TREE_STATE_TREE_STARTED)
+               return CYAML_ERROR_UNEXPECTED_STATE;
+
+       tree->state = TREE_STATE_INITED;
+
+       return CYAML_ERROR_NONE;
+}
+
+static enum cYAML_handler_error
+yaml_document_start(yaml_token_t *token, struct cYAML_tree_node *tree)
+{
+       if (tree->state != TREE_STATE_INITED)
+               return CYAML_ERROR_UNEXPECTED_STATE;
+
+       /* go to started state since we're expecting more tokens to come */
+       tree->state = TREE_STATE_TREE_STARTED;
+
+       return CYAML_ERROR_NONE;
+}
+
+static enum cYAML_handler_error yaml_document_end(yaml_token_t *token,
+                                                 struct cYAML_tree_node *tree)
+{
+       if (tree->state != TREE_STATE_COMPLETE)
+               return CYAML_ERROR_UNEXPECTED_STATE;
+
+       tree->state = TREE_STATE_TREE_STARTED;
+
+       return CYAML_ERROR_NONE;
+}
+
+static enum cYAML_handler_error yaml_key(yaml_token_t *token,
+                                        struct cYAML_tree_node *tree)
+{
+       if (tree->state != TREE_STATE_BLK_STARTED &&
+           tree->state != TREE_STATE_VALUE)
+               return CYAML_ERROR_UNEXPECTED_STATE;
+
+       if (tree->from_blk_map_start == 0 ||
+           tree->state == TREE_STATE_VALUE)
+               tree->cur = create_sibling(tree->cur);
+
+       tree->from_blk_map_start = 0;
+
+       tree->state = TREE_STATE_KEY;
+
+       return CYAML_ERROR_NONE;
+}
+
+static enum cYAML_handler_error yaml_scalar(yaml_token_t *token,
+                                           struct cYAML_tree_node *tree)
+{
+       if (tree->state == TREE_STATE_KEY) {
+               /* assign the scalar value to the key that was created */
+               tree->cur->cy_string =
+                 strdup((const char *)token->data.scalar.value);
+
+               tree->state = TREE_STATE_KEY_FILLED;
+       } else if (tree->state == TREE_STATE_VALUE) {
+               if (assign_type_value(tree->cur,
+                                     (char *)token->data.scalar.value))
+                       /* failed to assign a value */
+                       return CYAML_ERROR_BAD_VALUE;
+               tree->state = TREE_STATE_BLK_STARTED;
+       } else {
+               return CYAML_ERROR_UNEXPECTED_STATE;
+       }
+
+       return CYAML_ERROR_NONE;
+}
+
+static enum cYAML_handler_error yaml_value(yaml_token_t *token,
+                                          struct cYAML_tree_node *tree)
+{
+       if (tree->state != TREE_STATE_KEY_FILLED)
+               return CYAML_ERROR_UNEXPECTED_STATE;
+
+       tree->state = TREE_STATE_VALUE;
+
+       return CYAML_ERROR_NONE;
+}
+
+static enum cYAML_handler_error yaml_blk_seq_start(yaml_token_t *token,
+                                                  struct cYAML_tree_node *tree)
+{
+       if (tree->state != TREE_STATE_VALUE)
+               return CYAML_ERROR_UNEXPECTED_STATE;
+
+       /* Since a sequenc start event determines that this is the start
+        * of an array, then that means the current node we're at is an
+        * array and we need to flag it as such */
+       tree->cur->cy_type = CYAML_TYPE_ARRAY;
+       tree->state = TREE_STATE_SEQ_START;
+
+       return CYAML_ERROR_NONE;
+}
+
+static enum cYAML_handler_error yaml_entry_token(yaml_token_t *token,
+                                                struct cYAML_tree_node *tree)
+{
+       struct cYAML *obj;
+
+       if (tree->state != TREE_STATE_SEQ_START &&
+           tree->state != TREE_STATE_BLK_STARTED)
+               return CYAML_ERROR_UNEXPECTED_STATE;
+
+       if (tree->state == TREE_STATE_SEQ_START) {
+               obj = create_child(tree->cur);
+
+               if (cYAML_ll_push(tree->cur, NULL, &tree->ll))
+                       return CYAML_ERROR_OUT_OF_MEM;
+
+               tree->cur = obj;
+       } else {
+               tree->cur = create_sibling(tree->cur);
+               tree->state = TREE_STATE_SEQ_START;
+       }
+
+       return CYAML_ERROR_NONE;
+}
+
+static enum cYAML_handler_error
+yaml_blk_mapping_start(yaml_token_t *token,
+                      struct cYAML_tree_node *tree)
+{
+       struct cYAML *obj;
+
+       if (tree->state != TREE_STATE_VALUE &&
+           tree->state != TREE_STATE_INITED &&
+           tree->state != TREE_STATE_SEQ_START &&
+           tree->state != TREE_STATE_TREE_STARTED)
+               return CYAML_ERROR_UNEXPECTED_STATE;
+
+       /* block_mapping_start means we're entering another block
+        * indentation, so we need to go one level deeper
+        * create a child of cur */
+       obj = create_child(tree->cur);
+
+       /* push cur on the stack */
+       if (cYAML_ll_push(tree->cur, NULL, &tree->ll))
+               return CYAML_ERROR_OUT_OF_MEM;
+
+       /* adding the new child to cur */
+       tree->cur = obj;
+
+       tree->state = TREE_STATE_BLK_STARTED;
+
+       tree->from_blk_map_start = 1;
+
+       return CYAML_ERROR_NONE;
+}
+
+static enum cYAML_handler_error yaml_block_end(yaml_token_t *token,
+                                              struct cYAML_tree_node *tree)
+{
+       if (tree->state != TREE_STATE_BLK_STARTED &&
+           tree->state != TREE_STATE_VALUE)
+               return CYAML_ERROR_UNEXPECTED_STATE;
+
+       tree->cur = cYAML_ll_pop(&tree->ll, NULL);
+
+       /* if you have popped all the way to the top level, then move to
+        * the complete state. */
+       if (cYAML_ll_count(&tree->ll) == 0)
+               tree->state = TREE_STATE_COMPLETE;
+       else if (tree->state == TREE_STATE_VALUE)
+               tree->state = TREE_STATE_BLK_STARTED;
+
+       return CYAML_ERROR_NONE;
+}
+
+static enum cYAML_handler_error yaml_not_supported(yaml_token_t *token,
+                                                  struct cYAML_tree_node *tree)
+{
+       return CYAML_ERROR_NOT_SUPPORTED;
+}
+
+static bool clean_usr_data(struct cYAML *node, void *usr_data, void **out)
+{
+       cYAML_user_data_free_cb free_cb = usr_data;
+
+       if (free_cb && node && node->cy_user_data) {
+               free_cb(node->cy_user_data);
+               node->cy_user_data = NULL;
+       }
+
+       return true;
+}
+
+static bool free_node(struct cYAML *node, void *user_data, void **out)
+{
+       if (node)
+               free(node);
+
+       return true;
+}
+
+static bool find_obj_iter(struct cYAML *node, void *usr_data, void **out)
+{
+       char *name = usr_data;
+
+       if (node != NULL && node->cy_string != NULL &&
+           strcmp(node->cy_string, name) == 0) {
+               *out = node;
+               return false;
+       }
+
+       return true;
+}
+
+struct cYAML *cYAML_get_object_item(struct cYAML *parent, const char *name)
+{
+       struct cYAML *node;
+
+       if (parent == NULL || parent->cy_child == NULL || name == NULL)
+               return NULL;
+
+       node = parent->cy_child;
+
+       while (node != NULL &&
+               strcmp(node->cy_string, name) != 0) {
+               node = node->cy_next;
+       }
+
+       return node;
+}
+
+struct cYAML *cYAML_get_next_seq_item(struct cYAML *seq, struct cYAML **itm)
+{
+       if (*itm != NULL && (*itm)->cy_next != NULL) {
+               *itm = (*itm)->cy_next;
+               return *itm;
+       }
+
+       if (*itm == NULL && seq->cy_type == CYAML_TYPE_ARRAY) {
+               *itm = seq->cy_child;
+               return *itm;
+       }
+
+       return NULL;
+}
+
+bool cYAML_is_sequence(struct cYAML *node)
+{
+       return (node != NULL ? node->cy_type == CYAML_TYPE_ARRAY : 0);
+}
+
+void cYAML_tree_recursive_walk(struct cYAML *node, cYAML_walk_cb cb,
+                                     bool cb_first,
+                                     void *usr_data,
+                                     void **out)
+{
+       if (node == NULL)
+               return;
+
+       if (cb_first) {
+               if (!cb(node, usr_data, out))
+                       return;
+       }
+
+       if (node->cy_child)
+               cYAML_tree_recursive_walk(node->cy_child, cb,
+                                         cb_first, usr_data, out);
+
+       if (node->cy_next)
+               cYAML_tree_recursive_walk(node->cy_next, cb,
+                                         cb_first, usr_data, out);
+
+       if (!cb_first) {
+               if (!cb(node, usr_data, out))
+                       return;
+       }
+}
+
+struct cYAML *cYAML_find_object(struct cYAML *root, const char *name)
+{
+       struct cYAML *found = NULL;
+
+       cYAML_tree_recursive_walk(root, find_obj_iter, true,
+                                 (void *)name, (void **)&found);
+
+       return found;
+}
+
+void cYAML_clean_usr_data(struct cYAML *node, cYAML_user_data_free_cb free_cb)
+{
+       cYAML_tree_recursive_walk(node, clean_usr_data, false, free_cb, NULL);
+}
+
+void cYAML_free_tree(struct cYAML *node)
+{
+       cYAML_tree_recursive_walk(node, free_node, false, NULL, NULL);
+}
+
+static inline void print_simple(FILE *f, struct cYAML *node,
+                               struct cYAML_print_info *cpi)
+{
+       int level = cpi->level;
+       int ind = cpi->extra_ind;
+
+       if (cpi->array_first_elem)
+               fprintf(f, "%*s- ", INDENT * level, "");
+
+       fprintf(f, "%*s""%s: %d\n", (cpi->array_first_elem) ? 0 :
+               INDENT * level + ind, "", node->cy_string,
+               node->cy_valueint);
+}
+
+static void print_string(FILE *f, struct cYAML *node,
+                        struct cYAML_print_info *cpi)
+{
+       char *new_line;
+       int level = cpi->level;
+       int ind = cpi->extra_ind;
+
+       if (cpi->array_first_elem)
+               fprintf(f, "%*s- ", INDENT * level, "");
+
+       new_line = strchr(node->cy_valuestring, '\n');
+       if (new_line == NULL)
+               fprintf(f, "%*s""%s: %s\n", (cpi->array_first_elem) ?
+                       0 : INDENT * level + ind, "",
+                       node->cy_string, node->cy_valuestring);
+       else {
+               int indent = 0;
+               fprintf(f, "%*s""%s: ", (cpi->array_first_elem) ?
+                       0 : INDENT * level + ind, "",
+                       node->cy_string);
+               char *l = node->cy_valuestring;
+               while (new_line) {
+                       *new_line = '\0';
+                       fprintf(f, "%*s""%s\n", indent, "", l);
+                       indent = INDENT * level + ind +
+                                 strlen(node->cy_string) + 2;
+                       *new_line = '\n';
+                       l = new_line+1;
+                       new_line = strchr(l, '\n');
+               }
+               fprintf(f, "%*s""%s\n", indent, "", l);
+       }
+}
+
+static void print_number(FILE *f, struct cYAML *node,
+                        struct cYAML_print_info *cpi)
+{
+       double d = node->cy_valuedouble;
+       int level = cpi->level;
+       int ind = cpi->extra_ind;
+
+       if (cpi->array_first_elem)
+               fprintf(f, "%*s- ", INDENT * level, "");
+
+       if ((fabs(((double)node->cy_valueint) - d) <= DBL_EPSILON) &&
+           (d <= INT_MAX) && (d >= INT_MIN))
+               fprintf(f, "%*s""%s: %d\n", (cpi->array_first_elem) ? 0 :
+                       INDENT * level + ind, "",
+                       node->cy_string, node->cy_valueint);
+       else {
+               if ((fabs(floor(d) - d) <= DBL_EPSILON) &&
+                   (fabs(d) < 1.0e60))
+                       fprintf(f, "%*s""%s: %.0f\n",
+                               (cpi->array_first_elem) ? 0 :
+                               INDENT * level + ind, "",
+                               node->cy_string, d);
+               else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9))
+                       fprintf(f, "%*s""%s: %e\n",
+                               (cpi->array_first_elem) ? 0 :
+                               INDENT * level + ind, "",
+                               node->cy_string, d);
+               else
+                       fprintf(f, "%*s""%s: %f\n",
+                               (cpi->array_first_elem) ? 0 :
+                               INDENT * level + ind, "",
+                               node->cy_string, d);
+       }
+}
+
+static void print_object(FILE *f, struct cYAML *node,
+                        struct list_head *stack,
+                        struct cYAML_print_info *cpi)
+{
+       struct cYAML_print_info print_info;
+       struct cYAML *child = node->cy_child;
+
+       if (node->cy_string != NULL)
+               fprintf(f, "%*s""%s%s:\n", (cpi->array_first_elem) ?
+                       INDENT * cpi->level :
+                       INDENT * cpi->level + cpi->extra_ind,
+                       "", (cpi->array_first_elem) ? "- " : "",
+                       node->cy_string);
+
+       print_info.level = (node->cy_string != NULL) ? cpi->level + 1 :
+         cpi->level;
+       print_info.array_first_elem = (node->cy_string == NULL) ?
+         cpi->array_first_elem : 0;
+       print_info.extra_ind = (cpi->array_first_elem) ? EXTRA_IND :
+         cpi->extra_ind;
+
+       while (child) {
+               if (cYAML_ll_push(child, &print_info, stack) != 0)
+                       return;
+               print_value(f, stack);
+               print_info.array_first_elem = 0;
+               child = child->cy_next;
+       }
+}
+
+static void print_array(FILE *f, struct cYAML *node,
+                       struct list_head *stack,
+                       struct cYAML_print_info *cpi)
+{
+       struct cYAML_print_info print_info;
+       struct cYAML *child = node->cy_child;
+
+       if (node->cy_string != NULL) {
+               fprintf(f, "%*s""%s:\n", INDENT * cpi->level + cpi->extra_ind,
+                       "", node->cy_string);
+       }
+
+       print_info.level = (node->cy_string != NULL) ? cpi->level + 1 :
+         cpi->level;
+       print_info.array_first_elem =  1;
+       print_info.extra_ind = EXTRA_IND;
+
+       while (child) {
+               if (cYAML_ll_push(child, &print_info, stack) != 0)
+                       return;
+               print_value(f, stack);
+               child = child->cy_next;
+       }
+}
+
+static void print_value(FILE *f, struct list_head *stack)
+{
+       struct cYAML_print_info *cpi = NULL;
+       struct cYAML *node = cYAML_ll_pop(stack, &cpi);
+
+       switch (node->cy_type) {
+       case CYAML_TYPE_FALSE:
+       case CYAML_TYPE_TRUE:
+       case CYAML_TYPE_NULL:
+               print_simple(f, node, cpi);
+               break;
+       case CYAML_TYPE_STRING:
+               print_string(f, node, cpi);
+               break;
+       case CYAML_TYPE_NUMBER:
+               print_number(f, node, cpi);
+               break;
+       case CYAML_TYPE_ARRAY:
+               print_array(f, node, stack, cpi);
+               break;
+       case CYAML_TYPE_OBJECT:
+               print_object(f, node, stack, cpi);
+               break;
+       default:
+       break;
+       }
+
+       if (cpi != NULL)
+               free(cpi);
+}
+
+void cYAML_print_tree(struct cYAML *node)
+{
+       struct cYAML_print_info print_info;
+       struct list_head list;
+
+       INIT_LIST_HEAD(&list);
+
+       if (node == NULL)
+               return;
+
+       memset(&print_info, 0, sizeof(struct cYAML_print_info));
+
+       if (cYAML_ll_push(node, &print_info, &list) == 0)
+               print_value(stdout, &list);
+}
+
+void cYAML_print_tree2file(FILE *f, struct cYAML *node)
+{
+       struct cYAML_print_info print_info;
+       struct list_head list;
+
+       INIT_LIST_HEAD(&list);
+
+       if (node == NULL)
+               return;
+
+       memset(&print_info, 0, sizeof(struct cYAML_print_info));
+
+       if (cYAML_ll_push(node, &print_info, &list) == 0)
+               print_value(f, &list);
+}
+
+static struct cYAML *insert_item(struct cYAML *parent, char *key,
+                                enum cYAML_object_type type)
+{
+       struct cYAML *node = calloc(1, sizeof(*node));
+
+       if (node == NULL)
+               return NULL;
+
+       if (key != NULL)
+               node->cy_string = strdup(key);
+
+       node->cy_type = type;
+
+       cYAML_insert_child(parent, node);
+
+       return node;
+}
+
+struct cYAML *cYAML_create_seq(struct cYAML *parent, char *key)
+{
+       return insert_item(parent, key, CYAML_TYPE_ARRAY);
+}
+
+struct cYAML *cYAML_create_seq_item(struct cYAML *seq)
+{
+       return insert_item(seq, NULL, CYAML_TYPE_OBJECT);
+}
+
+struct cYAML *cYAML_create_object(struct cYAML *parent, char *key)
+{
+       return insert_item(parent, key, CYAML_TYPE_OBJECT);
+}
+
+struct cYAML *cYAML_create_string(struct cYAML *parent, char *key, char *value)
+{
+       struct cYAML *node = calloc(1, sizeof(*node));
+       if (node == NULL)
+               return NULL;
+
+       node->cy_string = strdup(key);
+       node->cy_valuestring = strdup(value);
+       node->cy_type = CYAML_TYPE_STRING;
+
+       cYAML_insert_child(parent, node);
+
+       return node;
+}
+
+struct cYAML *cYAML_create_number(struct cYAML *parent, char *key, double value)
+{
+       struct cYAML *node = calloc(1, sizeof(*node));
+       if (node == NULL)
+               return NULL;
+
+       node->cy_string = strdup(key);
+       node->cy_valuedouble = value;
+       node->cy_valueint = (int)value;
+       node->cy_type = CYAML_TYPE_NUMBER;
+
+       cYAML_insert_child(parent, node);
+
+       return node;
+}
+
+void cYAML_insert_child(struct cYAML *parent, struct cYAML *node)
+{
+       struct cYAML *cur;
+
+       if (parent && node) {
+               if (parent->cy_child == NULL) {
+                       parent->cy_child = node;
+                       return;
+               }
+
+               cur = parent->cy_child;
+
+               while (cur->cy_next)
+                       cur = cur->cy_next;
+
+               cur->cy_next = node;
+               node->cy_prev = cur;
+       }
+}
+
+void cYAML_insert_sibling(struct cYAML *root, struct cYAML *sibling)
+{
+       struct cYAML *last = NULL;
+       if (root == NULL || sibling == NULL)
+               return;
+
+       last = root;
+       while (last->cy_next != NULL)
+               last = last->cy_next;
+
+       last->cy_next = sibling;
+}
+
+void cYAML_build_error(int rc, int seq_no, char *cmd,
+                      char *entity, char *err_str,
+                      struct cYAML **root)
+{
+       struct cYAML *r = NULL, *err, *s, *itm, *cmd_obj;
+       if (root == NULL)
+               return;
+
+       /* add to the tail of the root that's passed in */
+       if ((*root) == NULL) {
+               *root = cYAML_create_object(NULL, NULL);
+               if ((*root) == NULL)
+                       goto failed;
+       }
+
+       r = *root;
+
+       /* look for the command */
+       cmd_obj = cYAML_get_object_item(r, (const char *)cmd);
+       if (cmd_obj != NULL && cmd_obj->cy_type == CYAML_TYPE_ARRAY)
+               itm = cYAML_create_seq_item(cmd_obj);
+       else if (cmd_obj == NULL) {
+               s = cYAML_create_seq(r, cmd);
+               itm = cYAML_create_seq_item(s);
+       } else if (cmd_obj != NULL && cmd_obj->cy_type != CYAML_TYPE_ARRAY)
+               goto failed;
+
+       err = cYAML_create_object(itm, entity);
+       if (err == NULL)
+               goto failed;
+
+       if (seq_no >= 0 &&
+           cYAML_create_number(err, "seqno", seq_no) == NULL)
+               goto failed;
+
+       if (cYAML_create_number(err, "errno", rc) == NULL)
+               goto failed;
+
+       if (cYAML_create_string(err, "descr", err_str) == NULL)
+               goto failed;
+
+       return;
+
+failed:
+       cYAML_free_tree(r);
+       r = NULL;
+}
+
+struct cYAML *cYAML_build_tree(char *yaml_file,
+                              const char *yaml_blk,
+                              size_t yaml_blk_size,
+                              struct cYAML **err_rc)
+{
+       yaml_parser_t parser;
+       yaml_token_t token;
+       struct cYAML_tree_node tree;
+       enum cYAML_handler_error rc;
+       yaml_token_type_t token_type;
+       char err_str[256];
+       FILE *input = NULL;
+       int done = 0;
+
+       memset(&tree, 0, sizeof(struct cYAML_tree_node));
+
+       INIT_LIST_HEAD(&tree.ll);
+
+       /* Create the Parser object. */
+       yaml_parser_initialize(&parser);
+
+       /* file alwyas takes precedence */
+       if (yaml_file != NULL) {
+               /* Set a file input. */
+               input = fopen(yaml_file, "rb");
+               if (input == NULL) {
+                       snprintf(err_str, sizeof(err_str),
+                               "Failed to open file: %s", yaml_file);
+                       cYAML_build_error(-1, -1, "yaml", "builder",
+                                         err_str,
+                                         err_rc);
+                       return NULL;
+               }
+
+               yaml_parser_set_input_file(&parser, input);
+       } else if (yaml_blk != NULL) {
+               yaml_parser_set_input_string(&parser,
+                                            (const unsigned char *) yaml_blk,
+                                            yaml_blk_size);
+       } else
+               /* assume that we're getting our input froms stdin */
+               yaml_parser_set_input_file(&parser, stdin);
+
+       /* Read the event sequence. */
+       while (!done) {
+               /*
+               * Go through the parser and build a cYAML representation
+               * of the passed in YAML text
+               */
+               yaml_parser_scan(&parser, &token);
+
+               rc = dispatch_tbl[token.type](&token, &tree);
+               if (rc != CYAML_ERROR_NONE) {
+                       snprintf(err_str, sizeof(err_str),
+                               "Failed to handle token:%d "
+                               "[state=%d, rc=%d]",
+                               token.type, tree.state, rc);
+                       cYAML_build_error(-1, -1, "yaml", "builder",
+                                         err_str,
+                                         err_rc);
+               }
+               /* Are we finished? */
+               done = (rc != CYAML_ERROR_NONE ||
+                       token.type == YAML_STREAM_END_TOKEN ||
+                       token.type == YAML_NO_TOKEN);
+
+               token_type = token.type;
+
+               yaml_token_delete(&token);
+       }
+
+       /* Destroy the Parser object. */
+       yaml_parser_delete(&parser);
+
+       if (input != NULL)
+               fclose(input);
+
+       if (token_type == YAML_STREAM_END_TOKEN &&
+           rc == CYAML_ERROR_NONE)
+               return tree.root;
+
+       cYAML_free_tree(tree.root);
+
+       return NULL;
+}
diff --git a/lnet/utils/cyaml/cyaml.h b/lnet/utils/cyaml/cyaml.h
new file mode 100644 (file)
index 0000000..f0b7993
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * LGPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * LGPL HEADER END
+ *
+ * Copyright (c) 2013, Intel Corporation.
+ *
+ * Author:
+ *   Amir Shehata <amir.shehata@intel.com>
+ */
+
+#ifndef CYAML_H
+#define CYAML_H
+
+#include <stdbool.h>
+
+enum cYAML_object_type {
+       CYAML_TYPE_FALSE = 0,
+       CYAML_TYPE_TRUE,
+       CYAML_TYPE_NULL,
+       CYAML_TYPE_NUMBER,
+       CYAML_TYPE_STRING,
+       CYAML_TYPE_ARRAY,
+       CYAML_TYPE_OBJECT
+};
+
+struct cYAML {
+       /* next/prev allow you to walk array/object chains. */
+       struct cYAML *cy_next, *cy_prev;
+       /* An array or object item will have a child pointer pointing
+          to a chain of the items in the array/object. */
+       struct cYAML *cy_child;
+       /* The type of the item, as above. */
+       enum cYAML_object_type cy_type;
+
+       /* The item's string, if type==CYAML_TYPE_STRING */
+       char *cy_valuestring;
+       /* The item's number, if type==CYAML_TYPE_NUMBER */
+       int cy_valueint;
+       /* The item's number, if type==CYAML_TYPE_NUMBER */
+       double cy_valuedouble;
+       /* The item's name string, if this item is the child of,
+          or is in the list of subitems of an object. */
+       char *cy_string;
+       /* user data which might need to be tracked per object */
+       void *cy_user_data;
+};
+
+typedef void (*cYAML_user_data_free_cb)(void *);
+
+/*
+ * cYAML_walk_cb
+ *   Callback called when recursing through the tree
+ *
+ *   cYAML* - pointer to the node currently being visitied
+ *   void* - user data passed to the callback.
+ *   void** - output value from the callback
+ *
+ * Returns true to continue recursing.  false to stop recursing
+ */
+typedef bool (*cYAML_walk_cb)(struct cYAML *, void *, void**);
+
+/*
+ * cYAML_build_tree
+ *   Build a tree representation of the YAML formated text passed in.
+ *
+ *   yaml_file - YAML file to parse and build tree representation
+ *   yaml_blk - blk of YAML.  yaml_file takes precedence if both
+ *   are defined.
+ *   yaml_blk_size - length of the yaml block (obtained via strlen)
+ */
+struct cYAML *cYAML_build_tree(char *yaml_file, const char *yaml_blk,
+                               size_t yaml_blk_size,
+                               struct cYAML **err_str);
+
+/*
+ * cYAML_print_tree
+ *   Print the textual representation of a YAML tree to stderr
+ *
+ *   node - Node where you want to start printing
+ */
+void cYAML_print_tree(struct cYAML *node);
+
+/*
+ * cYAML_print_tree2file
+ *   Print the textual representation of a YAML tree to file
+ *
+ *   f - file to print to
+ *   node - Node where you want to start printing
+ */
+void cYAML_print_tree2file(FILE *f, struct cYAML *node);
+
+/*
+ * cYAML_free_tree
+ *   Free the cYAML tree returned as part of the cYAML_build_tree
+ *
+ *   node - root of the tree to be freed
+ */
+void cYAML_free_tree(struct cYAML *node);
+
+/*
+ * cYAML_get_object_item
+ *   Returns the cYAML object which key correspods to the name passed in
+ *   This function searches only through the current level.
+ *
+ *   parent - is the parent object on which you want to conduct the search
+ *   name - key name of the object you want to find.
+ */
+struct cYAML *cYAML_get_object_item(struct cYAML *parent,
+                                   const char *name);
+
+/*
+ * cYAML_get_next_seq_item
+ *   Returns the next item in the YAML sequence.  This function uses the
+ *   itm parameter to keep track of its position in the sequence.  If the
+ *   itm parameter is reset to NULL between calls that resets and returns
+ *   the first item in the sequence.
+ *   This function returns NULL when there are no more items in the
+ *   sequence.
+ *
+ *   seq - is the head node of the YAML sequence
+ *   itm - [OUT] next sequence item to continue looking from next time.
+ *
+ */
+struct cYAML *cYAML_get_next_seq_item(struct cYAML *seq,
+                                     struct cYAML **itm);
+
+/*
+ * cYAML_is_seq
+ *   Returns 1 if the node provided is an ARRAY 0 otherwise
+ *
+ *   node - the node to examine
+ *
+ */
+bool cYAML_is_sequence(struct cYAML *node);
+
+/*
+ * cYAML_find_object
+ *   Returns the cYAML object which key correspods to the name passed in
+ *   this function searches the entire tree.
+ *
+ *   root - is the root of the tree on which you want to conduct the search
+ *   name - key name of the object you want to find.
+ */
+struct cYAML *cYAML_find_object(struct cYAML *root, const char *key);
+
+/*
+ * cYAML_clean_usr_data
+ *   walks the tree and for each node with some user data it calls the
+ *   free_cb with the user data as a parameter.
+ *
+ *   node: node to start the walk from
+ *   free_cb: cb to call to cleanup the user data
+ */
+void cYAML_clean_usr_data(struct cYAML *node,
+                         cYAML_user_data_free_cb free_cb);
+
+/*
+ * cYAML_create_object
+ *  Creates a CYAML of type OBJECT
+ *
+ *  parent - parent node
+ *  key - node key
+ */
+struct cYAML *cYAML_create_object(struct cYAML *parent, char *key);
+
+/*
+ * cYAML_create_seq
+ *  Creates a CYAML of type ARRAY
+ *  Once this is created, more sequence items can be added.
+ *
+ *  parent - parent node
+ *  key - node key
+ */
+struct cYAML *cYAML_create_seq(struct cYAML *parent, char *key);
+
+/*
+ * cYAML_create_object
+ *  Create a sequence item, which can have more entites added underneath
+ *  it
+ *
+ *  parent - parent node
+ */
+struct cYAML *cYAML_create_seq_item(struct cYAML *seq);
+
+/*
+ * cYAML_create_string
+ *   Creates a cYAML node of type STRING
+ *
+ *   parent - parent node
+ *   key - node key
+ *   value - value of node
+ */
+struct cYAML *cYAML_create_string(struct cYAML *parent, char *key,
+                                 char *value);
+
+/*
+ * cYAML_create_string
+ *   Creates a cYAML node of type STRING
+ *
+ *   parent - parent node
+ *   key - node key
+ *   value - value of node
+ */
+struct cYAML *cYAML_create_number(struct cYAML *parent, char *key,
+                                 double value);
+
+/*
+ * cYAML_insert_sibling
+ *   inserts one cYAML object as a sibling to another
+ *
+ *   root - root node to have a sibling added to
+ *   sibling - sibling to be added
+ */
+void cYAML_insert_sibling(struct cYAML *root, struct cYAML *sibling);
+
+/*
+ * cYAML_insert_child
+ *   inserts one cYAML object as a child to another
+ *
+ *   parent - parent node to have a child added to
+ *   child - child to be added
+ */
+void cYAML_insert_child(struct cYAML *parent, struct cYAML *node);
+
+/*
+ * cYAML_build_error
+ *   Build a YAML error message given:
+ *
+ *   rc - return code to add in the error
+ *   seq_no - a sequence number to add in the error
+ *   cmd - the command that failed.
+ *   entity - command entity that failed.
+ *   err_str - error string to add in the error
+ *   root - the root to which to add the YAML error
+ */
+void cYAML_build_error(int rc, int seq_no, char *cmd,
+                       char *entity, char *err_str,
+                       struct cYAML **root);
+
+
+#endif /* CYAML_H */
diff --git a/lnet/utils/lnetconfig/.gitignore b/lnet/utils/lnetconfig/.gitignore
new file mode 100644 (file)
index 0000000..10a7e8d
--- /dev/null
@@ -0,0 +1 @@
+/Makefile.in
diff --git a/lnet/utils/lnetconfig/Makefile.am b/lnet/utils/lnetconfig/Makefile.am
new file mode 100644 (file)
index 0000000..8cc3a4f
--- /dev/null
@@ -0,0 +1,54 @@
+#
+# LGPL HEADER START
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of the
+# License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library. If not, see <http://www.gnu.org/licenses/>.
+#
+# LGPL HEADER END
+
+#
+# Copyright (c) 2013, Intel Corporation.
+#
+
+# Author:
+#   Amir Shehata <amir.shehata@intel.com>
+#
+
+SUBDIRS =
+
+AM_CFLAGS=$(LLCFLAGS)
+AM_CPPFLAGS=$(LLCPPFLAGS) -I$(top_builddir)/lnet/utils \
+                         -I$(top_builddir)/lnet/utils/cyaml \
+                         -DLUSTRE_UTILS=1
+AM_LDFLAGS := -L$(top_builddir)/libcfs/libcfs
+
+lib_LIBRARIES = liblnetconfig.a
+noinst_LIBRARIES = liblnetconfigtmp.a
+
+CYAML := $(top_builddir)/lnet/utils/cyaml/cyaml.c \
+        $(top_builddir)/lnet/utils/cyaml/cyaml.h
+liblnetconfigtmp_a_SOURCES := liblnetconfig.c liblnetconfig.h $(CYAML)
+liblnetconfigtmp_a_CPPFLAGS := $(AM_CPPFLAGS)
+
+# build static and share lib lnet config library
+liblnetconfig.a : liblnetconfigtmp.a
+       rm -f liblnetconfig.a liblnetconfig.so
+       $(CC) $(LDFLAGS) $(AM_LDFLAGS) -shared -o liblnetconfig.so `$(AR) -t liblnetconfigtmp.a`
+       mv liblnetconfigtmp.a liblnetconfig.a
+
+install-exec-hook:
+       cp liblnetconfig.so  $(DESTDIR)$(libdir)/
+
+EXTRA_DIST =
diff --git a/lnet/utils/lnetconfig/liblnetconfig.c b/lnet/utils/lnetconfig/liblnetconfig.c
new file mode 100644 (file)
index 0000000..f96db1b
--- /dev/null
@@ -0,0 +1,1549 @@
+/*
+ * LGPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * LGPL HEADER END
+ *
+ * Copyright (c) 2013, Intel Corporation.
+ *
+ * Author:
+ *   Amir Shehata <amir.shehata@intel.com>
+ */
+
+/*
+ * There are two APIs:
+ *  1. APIs that take the actual parameters expanded.  This is for other
+ *  entities that would like to link against the library and call the APIs
+ *  directly without having to form an intermediate representation.
+ *  2. APIs that take a YAML file and parses out the information there and
+ *  calls the APIs mentioned in 1
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libcfs/libcfsutil.h>
+#include <lnet/lnetctl.h>
+#include <lnet/socklnd.h>
+#include <lnet/lib-dlc.h>
+#include <lnet/nidstr.h>
+#include "liblnetconfig.h"
+#include "cyaml.h"
+
+#define CONFIG_CMD             "configure"
+#define UNCONFIG_CMD           "unconfigure"
+#define ADD_CMD                        "add"
+#define DEL_CMD                        "del"
+#define SHOW_CMD               "show"
+
+int lustre_lnet_config_lib_init(void)
+{
+       return register_ioc_dev(LNET_DEV_ID, LNET_DEV_PATH,
+                               LNET_DEV_MAJOR, LNET_DEV_MINOR);
+}
+
+int lustre_lnet_config_ni_system(bool up, bool load_ni_from_mod,
+                                int seq_no, struct cYAML **err_rc)
+{
+       struct libcfs_ioctl_data data;
+       unsigned int opc;
+       int rc;
+       char err_str[LNET_MAX_STR_LEN];
+
+       snprintf(err_str, sizeof(err_str), "\"Success\"");
+
+       LIBCFS_IOC_INIT(data);
+
+       /* Reverse logic is used here in order not to change
+        * the lctl utility */
+       data.ioc_flags = load_ni_from_mod ? 0 : 1;
+
+       opc = up ? IOC_LIBCFS_CONFIGURE : IOC_LIBCFS_UNCONFIGURE;
+
+       rc = l_ioctl(LNET_DEV_ID, opc, &data);
+
+       if (rc != 0) {
+               snprintf(err_str,
+                       sizeof(err_str),
+                       "\"LNet %s error: %s\"", (up) ? "configure" :
+                       "unconfigure", strerror(errno));
+               rc = -errno;
+       }
+
+       cYAML_build_error(rc, seq_no, (up) ? CONFIG_CMD : UNCONFIG_CMD,
+                         "lnet", err_str, err_rc);
+
+       return rc;
+}
+
+int lustre_lnet_config_route(char *nw, char *gw, int hops, int prio,
+                            int seq_no, struct cYAML **err_rc)
+{
+       struct lnet_ioctl_config_data data;
+       lnet_nid_t gateway_nid;
+       int rc = LUSTRE_CFG_RC_NO_ERR;
+       __u32 net = LNET_NIDNET(LNET_NID_ANY);
+       char err_str[LNET_MAX_STR_LEN];
+
+       snprintf(err_str, sizeof(err_str), "\"Success\"");
+
+       if (nw == NULL || gw == NULL) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"missing mandatory parameter(s): '%s'\"",
+                        (nw == NULL && gw == NULL) ? "network, gateway" :
+                        (nw == NULL) ? "network" : "gateway");
+               rc = LUSTRE_CFG_RC_MISSING_PARAM;
+               goto out;
+       }
+
+       net = libcfs_str2net(nw);
+       if (net == LNET_NIDNET(LNET_NID_ANY)) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"cannot parse net %s\"", nw);
+               rc = LUSTRE_CFG_RC_BAD_PARAM;
+               goto out;
+       }
+
+       if (LNET_NETTYP(net) == CIBLND    ||
+           LNET_NETTYP(net) == OPENIBLND ||
+           LNET_NETTYP(net) == IIBLND    ||
+           LNET_NETTYP(net) == VIBLND) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"obselete LNet type '%s'\"", libcfs_lnd2str(net));
+               rc = LUSTRE_CFG_RC_BAD_PARAM;
+               goto out;
+       }
+
+       gateway_nid = libcfs_str2nid(gw);
+       if (gateway_nid == LNET_NID_ANY) {
+               snprintf(err_str,
+                       sizeof(err_str),
+                       "\"cannot parse gateway NID '%s'\"", gw);
+               rc = LUSTRE_CFG_RC_BAD_PARAM;
+               goto out;
+       }
+
+       if (hops == -1) {
+               /* -1 indicates to use the default hop value */
+               hops = 1;
+       } else if (hops < 1 || hops > 255) {
+               snprintf(err_str,
+                       sizeof(err_str),
+                       "\"invalid hop count %d, must be between 0 and 256\"",
+                       hops);
+               rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
+               goto out;
+       }
+
+       if (prio == -1) {
+               prio = 0;
+       } else if (prio < 0) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                       "\"invalid priority %d, must be greater than 0\"",
+                       prio);
+               rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
+               goto out;
+       }
+
+       LIBCFS_IOC_INIT_V2(data, cfg_hdr);
+       data.cfg_net = net;
+       data.cfg_config_u.cfg_route.rtr_hop = hops;
+       data.cfg_config_u.cfg_route.rtr_priority = prio;
+       data.cfg_nid = gateway_nid;
+
+       rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_ROUTE, &data);
+       if (rc != 0) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"cannot add route: %s\"", strerror(errno));
+               rc = -errno;
+               goto out;
+       }
+
+out:
+       cYAML_build_error(rc, seq_no, ADD_CMD, "route", err_str, err_rc);
+
+       return rc;
+}
+
+int lustre_lnet_del_route(char *nw, char *gw,
+                         int seq_no, struct cYAML **err_rc)
+{
+       struct lnet_ioctl_config_data data;
+       lnet_nid_t gateway_nid;
+       int rc = LUSTRE_CFG_RC_NO_ERR;
+       __u32 net = LNET_NIDNET(LNET_NID_ANY);
+       char err_str[LNET_MAX_STR_LEN];
+
+       snprintf(err_str, sizeof(err_str), "\"Success\"");
+
+       if (nw == NULL || gw == NULL) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"missing mandatory parameter(s): '%s'\"",
+                        (nw == NULL && gw == NULL) ? "network, gateway" :
+                        (nw == NULL) ? "network" : "gateway");
+               rc = LUSTRE_CFG_RC_MISSING_PARAM;
+               goto out;
+       }
+
+       net = libcfs_str2net(nw);
+       if (net == LNET_NIDNET(LNET_NID_ANY)) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"cannot parse net '%s'\"", nw);
+               rc = LUSTRE_CFG_RC_BAD_PARAM;
+               goto out;
+       }
+
+       if (LNET_NETTYP(net) == CIBLND    ||
+           LNET_NETTYP(net) == OPENIBLND ||
+           LNET_NETTYP(net) == IIBLND    ||
+           LNET_NETTYP(net) == VIBLND) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"obselete LNet type '%s'\"", libcfs_lnd2str(net));
+               rc = LUSTRE_CFG_RC_BAD_PARAM;
+               goto out;
+       }
+
+       gateway_nid = libcfs_str2nid(gw);
+       if (gateway_nid == LNET_NID_ANY) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"cannot parse gateway NID '%s'\"", gw);
+               rc = LUSTRE_CFG_RC_BAD_PARAM;
+               goto out;
+       }
+
+       LIBCFS_IOC_INIT_V2(data, cfg_hdr);
+       data.cfg_net = net;
+       data.cfg_nid = gateway_nid;
+
+       rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DEL_ROUTE, &data);
+       if (rc != 0) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"cannot delete route: %s\"", strerror(errno));
+               rc = -errno;
+               goto out;
+       }
+
+out:
+       cYAML_build_error(rc, seq_no, DEL_CMD, "route", err_str, err_rc);
+
+       return rc;
+}
+
+int lustre_lnet_show_route(char *nw, char *gw, int hops, int prio, int detail,
+                          int seq_no, struct cYAML **show_rc,
+                          struct cYAML **err_rc)
+{
+       struct lnet_ioctl_config_data data;
+       lnet_nid_t gateway_nid;
+       int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
+       __u32 net = LNET_NIDNET(LNET_NID_ANY);
+       int i;
+       struct cYAML *root = NULL, *route = NULL, *item = NULL;
+       struct cYAML *first_seq = NULL;
+       char err_str[LNET_MAX_STR_LEN];
+
+       snprintf(err_str, sizeof(err_str),
+                "\"out of memory\"");
+
+       if (nw != NULL) {
+               net = libcfs_str2net(nw);
+               if (net == LNET_NIDNET(LNET_NID_ANY)) {
+                       snprintf(err_str,
+                                sizeof(err_str),
+                                "\"cannot parse net '%s'\"", nw);
+                       rc = LUSTRE_CFG_RC_BAD_PARAM;
+                       goto out;
+               }
+
+               if (LNET_NETTYP(net) == CIBLND    ||
+                   LNET_NETTYP(net) == OPENIBLND ||
+                   LNET_NETTYP(net) == IIBLND    ||
+                   LNET_NETTYP(net) == VIBLND) {
+                       snprintf(err_str,
+                                sizeof(err_str),
+                                "\"obsolete LNet type '%s'\"",
+                                libcfs_lnd2str(net));
+                       rc = LUSTRE_CFG_RC_BAD_PARAM;
+                       goto out;
+               }
+       } else {
+               /* show all routes without filtering on net */
+               net = LNET_NIDNET(LNET_NID_ANY);
+       }
+
+       if (gw != NULL) {
+               gateway_nid = libcfs_str2nid(gw);
+               if (gateway_nid == LNET_NID_ANY) {
+                       snprintf(err_str,
+                                sizeof(err_str),
+                                "\"cannot parse gateway NID '%s'\"", gw);
+                       rc = LUSTRE_CFG_RC_BAD_PARAM;
+                       goto out;
+               }
+       } else
+               /* show all routes with out filtering on gateway */
+               gateway_nid = LNET_NID_ANY;
+
+       if ((hops < 1 && hops != -1) || hops > 255) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"invalid hop count %d, must be between 0 and 256\"",
+                        hops);
+               rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
+               goto out;
+       }
+
+       /* create struct cYAML root object */
+       root = cYAML_create_object(NULL, NULL);
+       if (root == NULL)
+               goto out;
+
+       route = cYAML_create_seq(root, "route");
+       if (route == NULL)
+               goto out;
+
+       for (i = 0;; i++) {
+               LIBCFS_IOC_INIT_V2(data, cfg_hdr);
+               data.cfg_count = i;
+
+               rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_ROUTE, &data);
+               if (rc != 0)
+                       break;
+
+               /* filter on provided data */
+               if (net != LNET_NIDNET(LNET_NID_ANY) &&
+                   net != data.cfg_net)
+                       continue;
+
+               if (gateway_nid != LNET_NID_ANY &&
+                   gateway_nid != data.cfg_nid)
+                       continue;
+
+               if (hops != -1 &&
+                   hops != data.cfg_config_u.cfg_route.rtr_hop)
+                       continue;
+
+               if (prio != -1 &&
+                   prio != data.cfg_config_u.cfg_route.rtr_priority)
+                       continue;
+
+               /* default rc to -1 incase we hit the goto */
+               rc = -1;
+
+               item = cYAML_create_seq_item(route);
+               if (item == NULL)
+                       goto out;
+
+               if (first_seq == NULL)
+                       first_seq = item;
+
+               if (cYAML_create_string(item, "net",
+                                       libcfs_net2str(data.cfg_net)) == NULL)
+                       goto out;
+
+               if (cYAML_create_string(item, "gateway",
+                                       libcfs_nid2str(data.cfg_nid)) == NULL)
+                       goto out;
+
+               if (detail) {
+                       if (cYAML_create_number(item, "hop",
+                                               data.cfg_config_u.cfg_route.
+                                                       rtr_hop) ==
+                           NULL)
+                               goto out;
+
+                       if (cYAML_create_number(item, "priority",
+                                               data.cfg_config_u.
+                                               cfg_route.rtr_priority) == NULL)
+                               goto out;
+
+                       if (cYAML_create_string(item, "state",
+                                               data.cfg_config_u.cfg_route.
+                                                       rtr_flags ?
+                                               "up" : "down") == NULL)
+                               goto out;
+               }
+       }
+
+       /* print output iff show_rc is not provided */
+       if (show_rc == NULL)
+               cYAML_print_tree(root);
+
+       if (errno != ENOENT) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"cannot get routes: %s\"",
+                        strerror(errno));
+               rc = -errno;
+               goto out;
+       } else
+               rc = LUSTRE_CFG_RC_NO_ERR;
+
+       snprintf(err_str, sizeof(err_str), "\"success\"");
+out:
+       if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
+               cYAML_free_tree(root);
+       } else if (show_rc != NULL && *show_rc != NULL) {
+               struct cYAML *show_node;
+               /* find the route node, if one doesn't exist then
+                * insert one.  Otherwise add to the one there
+                */
+               show_node = cYAML_get_object_item(*show_rc, "route");
+               if (show_node != NULL && cYAML_is_sequence(show_node)) {
+                       cYAML_insert_child(show_node, first_seq);
+                       free(route);
+                       free(root);
+               } else if (show_node == NULL) {
+                       cYAML_insert_sibling((*show_rc)->cy_child,
+                                               route);
+                       free(root);
+               } else {
+                       cYAML_free_tree(root);
+               }
+       } else {
+               *show_rc = root;
+       }
+
+       cYAML_build_error(rc, seq_no, SHOW_CMD, "route", err_str, err_rc);
+
+       return rc;
+}
+
+int lustre_lnet_config_net(char *net, char *intf, char *ip2net,
+                          int peer_to, int peer_cr, int peer_buf_cr,
+                          int credits, char *smp, int seq_no,
+                          struct cYAML **err_rc)
+{
+       struct lnet_ioctl_config_data data;
+       char buf[LNET_MAX_STR_LEN];
+       int rc = LUSTRE_CFG_RC_NO_ERR, num_of_nets = 0;
+       char err_str[LNET_MAX_STR_LEN];
+
+       snprintf(err_str, sizeof(err_str), "\"success\"");
+
+       if (ip2net == NULL && (intf == NULL || net == NULL)) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"mandatory parameter '%s' not specified."
+                        " Optionally specify ip2net parameter\"",
+                        (intf == NULL && net == NULL) ? "net, if" :
+                        (intf == NULL) ? "if" : "net");
+               rc = LUSTRE_CFG_RC_MISSING_PARAM;
+               goto out;
+       }
+
+       if (peer_to != -1 && peer_to <= 0) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"peer timeout %d, must be greater than 0\"",
+                        peer_to);
+               rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
+               goto out;
+       }
+
+       if (ip2net != NULL && strlen(ip2net) >= sizeof(buf)) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"ip2net string too long %d\"",
+                               (int)strlen(ip2net));
+               rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
+               goto out;
+       }
+
+       if (ip2net == NULL)
+               snprintf(buf, sizeof(buf) - 1, "%s(%s)%s",
+                       net, intf,
+                       (smp) ? smp : "");
+
+       LIBCFS_IOC_INIT_V2(data, cfg_hdr);
+       strncpy(data.cfg_config_u.cfg_net.net_intf,
+               (ip2net != NULL) ? ip2net : buf, sizeof(buf));
+       data.cfg_config_u.cfg_net.net_peer_timeout = peer_to;
+       data.cfg_config_u.cfg_net.net_peer_tx_credits = peer_cr;
+       data.cfg_config_u.cfg_net.net_peer_rtr_credits = peer_buf_cr;
+       data.cfg_config_u.cfg_net.net_max_tx_credits = credits;
+
+       num_of_nets = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_NET, &data);
+       if (num_of_nets < 0) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"cannot add network: %s\"", strerror(errno));
+               rc = -errno;
+       }
+
+out:
+       cYAML_build_error((num_of_nets > 0) ? num_of_nets : rc,
+                        seq_no, ADD_CMD, "net", err_str, err_rc);
+
+       return rc;
+}
+
+int lustre_lnet_del_net(char *nw, int seq_no, struct cYAML **err_rc)
+{
+       struct lnet_ioctl_config_data data;
+       __u32 net = LNET_NIDNET(LNET_NID_ANY);
+       int rc = LUSTRE_CFG_RC_NO_ERR;
+       char err_str[LNET_MAX_STR_LEN];
+
+       snprintf(err_str, sizeof(err_str), "\"success\"");
+
+       if (nw == NULL) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"missing mandatory parameter\"");
+               rc = LUSTRE_CFG_RC_MISSING_PARAM;
+               goto out;
+       }
+
+       net = libcfs_str2net(nw);
+       if (net == LNET_NIDNET(LNET_NID_ANY)) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"cannot parse net '%s'\"", nw);
+               rc = LUSTRE_CFG_RC_BAD_PARAM;
+               goto out;
+       }
+
+       LIBCFS_IOC_INIT_V2(data, cfg_hdr);
+       data.cfg_net = net;
+
+       rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DEL_NET, &data);
+       if (rc != 0) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"cannot delete network: %s\"", strerror(errno));
+               rc = -errno;
+               goto out;
+       }
+
+out:
+       cYAML_build_error(rc, seq_no, DEL_CMD, "net", err_str, err_rc);
+
+       return rc;
+}
+
+int lustre_lnet_show_net(char *nw, int detail, int seq_no,
+                        struct cYAML **show_rc, struct cYAML **err_rc)
+{
+       char *buf;
+       struct lnet_ioctl_config_data *data;
+       struct lnet_ioctl_net_config *net_config;
+       __u32 net = LNET_NIDNET(LNET_NID_ANY);
+       int rc = LUSTRE_CFG_RC_OUT_OF_MEM, i, j;
+       struct cYAML *root = NULL, *tunables = NULL,
+               *net_node = NULL, *interfaces = NULL,
+               *item = NULL, *first_seq = NULL;
+       int str_buf_len = LNET_MAX_SHOW_NUM_CPT * 2;
+       char str_buf[str_buf_len];
+       char *pos = str_buf;
+       char err_str[LNET_MAX_STR_LEN];
+
+       snprintf(err_str, sizeof(err_str), "\"out of memory\"");
+
+       buf = calloc(1, sizeof(*data) + sizeof(*net_config));
+       if (buf == NULL)
+               goto out;
+
+       data = (struct lnet_ioctl_config_data *)buf;
+
+       if (nw != NULL) {
+               net = libcfs_str2net(nw);
+               if (net == LNET_NIDNET(LNET_NID_ANY)) {
+                       snprintf(err_str,
+                                sizeof(err_str),
+                                "\"cannot parse net '%s'\"", nw);
+                       rc = LUSTRE_CFG_RC_BAD_PARAM;
+                       goto out;
+               }
+       }
+
+       root = cYAML_create_object(NULL, NULL);
+       if (root == NULL)
+               goto out;
+
+       net_node = cYAML_create_seq(root, "net");
+       if (net_node == NULL)
+               goto out;
+
+       for (i = 0;; i++) {
+               LIBCFS_IOC_INIT_V2(*data, cfg_hdr);
+               /*
+                * set the ioc_len to the proper value since INIT assumes
+                * size of data
+                */
+               data->cfg_hdr.ioc_len = sizeof(struct lnet_ioctl_config_data) +
+                 sizeof(struct lnet_ioctl_net_config);
+               data->cfg_count = i;
+
+               rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_NET, data);
+               if (rc != 0)
+                       break;
+
+               /* filter on provided data */
+               if (net != LNET_NIDNET(LNET_NID_ANY) &&
+                   net != LNET_NIDNET(data->cfg_nid))
+                       continue;
+
+               /* default rc to -1 in case we hit the goto */
+               rc = -1;
+
+               net_config = (struct lnet_ioctl_net_config *)data->cfg_bulk;
+
+               /* create the tree to be printed. */
+               item = cYAML_create_seq_item(net_node);
+               if (item == NULL)
+                       goto out;
+
+               if (first_seq == NULL)
+                       first_seq = item;
+
+               if (cYAML_create_string(item,
+                                       "nid",
+                                       libcfs_nid2str(data->cfg_nid)) == NULL)
+                       goto out;
+
+               if (cYAML_create_string(item,
+                                       "status",
+                                       (net_config->ni_status ==
+                                         LNET_NI_STATUS_UP) ?
+                                           "up" : "down") == NULL)
+                       goto out;
+
+               /* don't add interfaces unless there is at least one
+                * interface */
+               if (strlen(net_config->ni_interfaces[0]) > 0) {
+                       interfaces = cYAML_create_object(item, "interfaces");
+                       if (interfaces == NULL)
+                               goto out;
+
+                       for (j = 0; j < LNET_MAX_INTERFACES; j++) {
+                               if (strlen(net_config->ni_interfaces[j]) > 0) {
+                                       snprintf(str_buf,
+                                                sizeof(str_buf), "%d", j);
+                                       if (cYAML_create_string(interfaces,
+                                               str_buf,
+                                               net_config->ni_interfaces[j]) ==
+                                           NULL)
+                                               goto out;
+                               }
+                       }
+               }
+
+               if (detail) {
+                       tunables = cYAML_create_object(item, "tunables");
+                       if (tunables == NULL)
+                               goto out;
+
+                       if (cYAML_create_number(tunables, "peer_timeout",
+                                               data->cfg_config_u.cfg_net.
+                                                net_peer_timeout) == NULL)
+                               goto out;
+
+                       if (cYAML_create_number(tunables, "peer_credits",
+                                               data->cfg_config_u.cfg_net.
+                                                 net_peer_tx_credits) == NULL)
+                               goto out;
+
+                       if (cYAML_create_number(tunables,
+                                               "peer_buffer_credits",
+                                               data->cfg_config_u.cfg_net.
+                                                 net_peer_rtr_credits) == NULL)
+                               goto out;
+
+                       if (cYAML_create_number(tunables, "credits",
+                                               data->cfg_config_u.cfg_net.
+                                                 net_max_tx_credits) == NULL)
+                               goto out;
+
+                       for (j = 0 ; data->cfg_ncpts > 1 &&
+                            j < data->cfg_ncpts; j++) {
+                               pos += snprintf(str_buf,
+                                               str_buf + str_buf_len - pos,
+                                               " %d", net_config->ni_cpts[j]);
+                       }
+
+                       if (data->cfg_ncpts > 1 &&
+                           cYAML_create_string(tunables, "CPTs",
+                                               str_buf) == NULL)
+                               goto out;
+               }
+       }
+
+       /* Print out the net information only if show_rc is not provided */
+       if (show_rc == NULL)
+               cYAML_print_tree(root);
+
+       if (errno != ENOENT) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"cannot get networks: %s\"",
+                        strerror(errno));
+               rc = -errno;
+               goto out;
+       } else
+               rc = LUSTRE_CFG_RC_NO_ERR;
+
+       snprintf(err_str, sizeof(err_str), "\"success\"");
+out:
+       if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
+               cYAML_free_tree(root);
+       } else if (show_rc != NULL && *show_rc != NULL) {
+               struct cYAML *show_node;
+               /* find the net node, if one doesn't exist
+                * then insert one.  Otherwise add to the one there
+                */
+               show_node = cYAML_get_object_item(*show_rc, "net");
+               if (show_node != NULL && cYAML_is_sequence(show_node)) {
+                       cYAML_insert_child(show_node, first_seq);
+                       free(net_node);
+                       free(root);
+               } else if (show_node == NULL) {
+                       cYAML_insert_sibling((*show_rc)->cy_child,
+                                               net_node);
+                       free(root);
+               } else {
+                       cYAML_free_tree(root);
+               }
+       } else {
+               *show_rc = root;
+       }
+
+       cYAML_build_error(rc, seq_no, SHOW_CMD, "net", err_str, err_rc);
+
+       return rc;
+}
+
+int lustre_lnet_enable_routing(int enable, int seq_no, struct cYAML **err_rc)
+{
+       struct lnet_ioctl_config_data data;
+       int rc = LUSTRE_CFG_RC_NO_ERR;
+       char err_str[LNET_MAX_STR_LEN];
+
+       snprintf(err_str, sizeof(err_str), "\"success\"");
+
+       LIBCFS_IOC_INIT_V2(data, cfg_hdr);
+       data.cfg_config_u.cfg_buffers.buf_enable = (enable) ? 1 : 0;
+
+       rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_CONFIG_RTR, &data);
+       if (rc != 0) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"cannot %s routing %s\"",
+                        (enable) ? "enable" : "disable", strerror(errno));
+               rc = -errno;
+               goto out;
+       }
+
+out:
+       cYAML_build_error(rc, seq_no,
+                        (enable) ? ADD_CMD : DEL_CMD,
+                        "routing", err_str, err_rc);
+
+       return rc;
+}
+
+int lustre_lnet_config_buffers(int tiny, int small, int large, int seq_no,
+                              struct cYAML **err_rc)
+{
+       struct lnet_ioctl_config_data data;
+       int rc = LUSTRE_CFG_RC_NO_ERR;
+       char err_str[LNET_MAX_STR_LEN];
+
+       snprintf(err_str, sizeof(err_str), "\"success\"");
+
+       /* -1 indicates to ignore changes to this field */
+       if (tiny < -1 || small < -1 || large < -1) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"tiny, small and large must be >= 0\"");
+               rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
+               goto out;
+       }
+
+       LIBCFS_IOC_INIT_V2(data, cfg_hdr);
+       data.cfg_config_u.cfg_buffers.buf_tiny = tiny;
+       data.cfg_config_u.cfg_buffers.buf_small = small;
+       data.cfg_config_u.cfg_buffers.buf_large = large;
+
+       rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_BUF, &data);
+       if (rc != 0) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"cannot configure buffers: %s\"", strerror(errno));
+               rc = -errno;
+               goto out;
+       }
+
+out:
+       cYAML_build_error(rc, seq_no, DEL_CMD, "buf", err_str, err_rc);
+
+       return rc;
+}
+
+int lustre_lnet_show_routing(int seq_no, struct cYAML **show_rc,
+                            struct cYAML **err_rc)
+{
+       struct lnet_ioctl_config_data *data;
+       struct lnet_ioctl_pool_cfg *pool_cfg = NULL;
+       int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
+       char *buf;
+       char *pools[LNET_NRBPOOLS] = {"tiny", "small", "large"};
+       struct cYAML *root = NULL, *pools_node = NULL,
+                    *type_node = NULL, *item = NULL, *cpt = NULL,
+                    *first_seq = NULL;
+       int i;
+       char err_str[LNET_MAX_STR_LEN];
+       char node_name[LNET_MAX_STR_LEN];
+
+       snprintf(err_str, sizeof(err_str), "\"out of memory\"");
+
+       buf = calloc(1, sizeof(*data) + sizeof(*pool_cfg));
+       if (buf == NULL)
+               goto out;
+
+       data = (struct lnet_ioctl_config_data *)buf;
+
+       root = cYAML_create_object(NULL, NULL);
+       if (root == NULL)
+               goto out;
+
+       pools_node = cYAML_create_seq(root, "routing");
+       if (pools_node == NULL)
+               goto out;
+
+       for (i = 0;; i++) {
+               LIBCFS_IOC_INIT_V2(*data, cfg_hdr);
+               data->cfg_hdr.ioc_len = sizeof(struct lnet_ioctl_config_data) +
+                                       sizeof(struct lnet_ioctl_pool_cfg);
+               data->cfg_count = i;
+
+               rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_BUF, data);
+               if (rc != 0)
+                       break;
+
+               pool_cfg = (struct lnet_ioctl_pool_cfg *)data->cfg_bulk;
+
+               snprintf(node_name, sizeof(node_name), "cpt[%d]", i);
+               item = cYAML_create_seq_item(pools_node);
+               if (item == NULL)
+                       goto out;
+
+               if (first_seq == NULL)
+                       first_seq = item;
+
+               cpt = cYAML_create_object(item, node_name);
+               if (cpt == NULL)
+                       goto out;
+
+               /* create the tree  and print */
+               for (i = 0; i < LNET_NRBPOOLS; i++) {
+                       type_node = cYAML_create_object(cpt, pools[i]);
+                       if (type_node == NULL)
+                               goto out;
+                       if (cYAML_create_number(type_node, "npages",
+                                               pool_cfg->pl_pools[i].pl_npages)
+                           == NULL)
+                               goto out;
+                       if (cYAML_create_number(type_node, "nbuffers",
+                                               pool_cfg->pl_pools[i].
+                                                 pl_nbuffers) == NULL)
+                               goto out;
+                       if (cYAML_create_number(type_node, "credits",
+                                               pool_cfg->pl_pools[i].
+                                                  pl_credits) == NULL)
+                               goto out;
+                       if (cYAML_create_number(type_node, "mincredits",
+                                               pool_cfg->pl_pools[i].
+                                                  pl_mincredits) == NULL)
+                               goto out;
+               }
+       }
+
+       if (pool_cfg != NULL) {
+               item = cYAML_create_seq_item(pools_node);
+               if (item == NULL)
+                       goto out;
+
+               if (cYAML_create_number(item, "enable", pool_cfg->pl_routing) ==
+                   NULL)
+                       goto out;
+       }
+
+       if (show_rc == NULL)
+               cYAML_print_tree(root);
+
+       if (errno != ENOENT) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"cannot get routing information: %s\"",
+                        strerror(errno));
+               rc = -errno;
+               goto out;
+       } else
+               rc = LUSTRE_CFG_RC_NO_ERR;
+
+       snprintf(err_str, sizeof(err_str), "\"success\"");
+       rc = LUSTRE_CFG_RC_NO_ERR;
+
+out:
+       free(buf);
+       if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
+               cYAML_free_tree(root);
+       } else if (show_rc != NULL && *show_rc != NULL) {
+               struct cYAML *show_node;
+               /* find the routing node, if one doesn't exist then
+                * insert one.  Otherwise add to the one there
+                */
+               show_node = cYAML_get_object_item(*show_rc, "routing");
+               if (show_node != NULL && cYAML_is_sequence(show_node)) {
+                       cYAML_insert_child(show_node, first_seq);
+                       free(pools_node);
+                       free(root);
+               } else if (show_node == NULL) {
+                       cYAML_insert_sibling((*show_rc)->cy_child,
+                                               pools_node);
+                       free(root);
+               } else {
+                       cYAML_free_tree(root);
+               }
+       } else {
+               *show_rc = root;
+       }
+
+       cYAML_build_error(rc, seq_no, SHOW_CMD, "routing", err_str, err_rc);
+
+       return rc;
+}
+
+int lustre_lnet_show_peer_credits(int seq_no, struct cYAML **show_rc,
+                                 struct cYAML **err_rc)
+{
+       struct lnet_ioctl_peer peer_info;
+       int rc = LUSTRE_CFG_RC_OUT_OF_MEM, ncpt = 0, i = 0, j = 0;
+       struct cYAML *root = NULL, *peer = NULL, *first_seq = NULL,
+                    *peer_root = NULL;
+       char err_str[LNET_MAX_STR_LEN];
+       bool ncpt_set = false;
+
+       snprintf(err_str, sizeof(err_str),
+                "\"out of memory\"");
+
+       /* create struct cYAML root object */
+       root = cYAML_create_object(NULL, NULL);
+       if (root == NULL)
+               goto out;
+
+       peer_root = cYAML_create_seq(root, "peer");
+               if (peer_root == NULL)
+                       goto out;
+
+       do {
+               for (i = 0;; i++) {
+                       LIBCFS_IOC_INIT_V2(peer_info, pr_hdr);
+                       peer_info.pr_count = i;
+                       peer_info.pr_lnd_u.pr_peer_credits.cr_ncpt = j;
+                       rc = l_ioctl(LNET_DEV_ID,
+                                    IOC_LIBCFS_GET_PEER_INFO, &peer_info);
+                       if (rc != 0)
+                               break;
+
+                       if (ncpt_set != 0) {
+                               ncpt = peer_info.pr_lnd_u.pr_peer_credits.
+                                       cr_ncpt;
+                               ncpt_set = true;
+                       }
+
+                       peer = cYAML_create_seq_item(peer_root);
+                       if (peer == NULL)
+                               goto out;
+
+                       if (first_seq == NULL)
+                               first_seq = peer;
+
+                       if (cYAML_create_string(peer, "nid",
+                                               libcfs_nid2str
+                                                (peer_info.pr_nid)) == NULL)
+                               goto out;
+
+                       if (cYAML_create_string(peer, "state",
+                                               peer_info.pr_lnd_u.
+                                                 pr_peer_credits.
+                                                       cr_aliveness) ==
+                           NULL)
+                               goto out;
+
+                       if (cYAML_create_number(peer, "refcount",
+                                               peer_info.pr_lnd_u.
+                                                 pr_peer_credits.
+                                                       cr_refcount) == NULL)
+                               goto out;
+
+                       if (cYAML_create_number(peer, "max_ni_tx_credits",
+                                               peer_info.pr_lnd_u.
+                                                 pr_peer_credits.
+                                                   cr_ni_peer_tx_credits)
+                           == NULL)
+                               goto out;
+
+                       if (cYAML_create_number(peer, "available_tx_credits",
+                                               peer_info.pr_lnd_u.
+                                                 pr_peer_credits.
+                                                   cr_peer_tx_credits)
+                           == NULL)
+                               goto out;
+
+                       if (cYAML_create_number(peer, "available_rtr_credits",
+                                               peer_info.pr_lnd_u.
+                                                 pr_peer_credits.
+                                                   cr_peer_rtr_credits)
+                           == NULL)
+                               goto out;
+
+                       if (cYAML_create_number(peer, "min_rtr_credits",
+                                               peer_info.pr_lnd_u.
+                                                 pr_peer_credits.
+                                                   cr_peer_min_rtr_credits)
+                           == NULL)
+                               goto out;
+
+                       if (cYAML_create_number(peer, "tx_q_num_of_buf",
+                                               peer_info.pr_lnd_u.
+                                                 pr_peer_credits.
+                                                   cr_peer_tx_qnob)
+                           == NULL)
+                               goto out;
+               }
+
+               if (errno != ENOENT) {
+                       snprintf(err_str,
+                               sizeof(err_str),
+                               "\"cannot get peer information: %s\"",
+                               strerror(errno));
+                       rc = -errno;
+                       goto out;
+               }
+
+               j++;
+       } while (j < ncpt);
+
+       /* print output iff show_rc is not provided */
+       if (show_rc == NULL)
+               cYAML_print_tree(root);
+
+       snprintf(err_str, sizeof(err_str), "\"success\"");
+       rc = LUSTRE_CFG_RC_NO_ERR;
+
+out:
+       if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
+               cYAML_free_tree(root);
+       } else if (show_rc != NULL && *show_rc != NULL) {
+               struct cYAML *show_node;
+               /* find the peer node, if one doesn't exist then
+                * insert one.  Otherwise add to the one there
+                */
+               show_node = cYAML_get_object_item(*show_rc,
+                                                 "peer_credits");
+               if (show_node != NULL && cYAML_is_sequence(show_node)) {
+                       cYAML_insert_child(show_node, first_seq);
+                       free(peer_root);
+                       free(root);
+               } else if (show_node == NULL) {
+                       cYAML_insert_sibling((*show_rc)->cy_child,
+                                            peer_root);
+                       free(root);
+               } else {
+                       cYAML_free_tree(root);
+               }
+       } else {
+               *show_rc = root;
+       }
+
+       cYAML_build_error(rc, seq_no, SHOW_CMD, "peer_credits", err_str,
+                         err_rc);
+
+       return rc;
+}
+
+int lustre_lnet_show_stats(int seq_no, struct cYAML **show_rc,
+                          struct cYAML **err_rc)
+{
+       struct lnet_ioctl_lnet_stats data;
+       int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
+       char err_str[LNET_MAX_STR_LEN];
+       struct cYAML *root = NULL, *stats = NULL;
+
+       snprintf(err_str, sizeof(err_str), "\"out of memory\"");
+
+       LIBCFS_IOC_INIT_V2(data, st_hdr);
+
+       rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_LNET_STATS, &data);
+       if (rc != 0) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"cannot get lnet statistics: %s\"",
+                        strerror(errno));
+               rc = -errno;
+               goto out;
+       }
+
+       root = cYAML_create_object(NULL, NULL);
+       if (root == NULL)
+               goto out;
+
+       stats = cYAML_create_object(root, "statistics");
+       if (stats == NULL)
+               goto out;
+
+       if (cYAML_create_number(stats, "msgs_alloc",
+                               data.st_cntrs.msgs_alloc) == NULL)
+               goto out;
+
+       if (cYAML_create_number(stats, "msgs_max",
+                               data.st_cntrs.msgs_max) == NULL)
+               goto out;
+
+       if (cYAML_create_number(stats, "errors",
+                               data.st_cntrs.errors) == NULL)
+               goto out;
+
+       if (cYAML_create_number(stats, "send_count",
+                               data.st_cntrs.send_count) == NULL)
+               goto out;
+
+       if (cYAML_create_number(stats, "recv_count",
+                               data.st_cntrs.recv_count) == NULL)
+               goto out;
+
+       if (cYAML_create_number(stats, "route_count",
+                               data.st_cntrs.route_count) == NULL)
+               goto out;
+
+       if (cYAML_create_number(stats, "drop_count",
+                               data.st_cntrs.drop_count) == NULL)
+               goto out;
+
+       if (cYAML_create_number(stats, "send_length",
+                               data.st_cntrs.send_length) == NULL)
+               goto out;
+
+       if (cYAML_create_number(stats, "recv_length",
+                               data.st_cntrs.recv_length) == NULL)
+               goto out;
+
+       if (cYAML_create_number(stats, "route_length",
+                               data.st_cntrs.route_length) == NULL)
+               goto out;
+
+       if (cYAML_create_number(stats, "drop_length",
+                               data.st_cntrs.drop_length) == NULL)
+               goto out;
+
+       if (show_rc == NULL)
+               cYAML_print_tree(root);
+
+       snprintf(err_str, sizeof(err_str), "\"success\"");
+out:
+       if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR) {
+               cYAML_free_tree(root);
+       } else if (show_rc != NULL && *show_rc != NULL) {
+               cYAML_insert_sibling((*show_rc)->cy_child,
+                                       root->cy_child);
+               free(root);
+       } else {
+               *show_rc = root;
+       }
+
+       cYAML_build_error(rc, seq_no, SHOW_CMD, "statistics", err_str, err_rc);
+
+       return rc;
+}
+
+typedef int (*cmd_handler_t)(struct cYAML *tree,
+                            struct cYAML **show_rc,
+                            struct cYAML **err_rc);
+
+static int handle_yaml_config_route(struct cYAML *tree, struct cYAML **show_rc,
+                                   struct cYAML **err_rc)
+{
+       struct cYAML *net, *gw, *hop, *prio, *seq_no;
+
+       net = cYAML_get_object_item(tree, "net");
+       gw = cYAML_get_object_item(tree, "gateway");
+       hop = cYAML_get_object_item(tree, "hop");
+       prio = cYAML_get_object_item(tree, "priority");
+       seq_no = cYAML_get_object_item(tree, "seq_no");
+
+       return lustre_lnet_config_route((net) ? net->cy_valuestring : NULL,
+                                       (gw) ? gw->cy_valuestring : NULL,
+                                       (hop) ? hop->cy_valueint : -1,
+                                       (prio) ? prio->cy_valueint : -1,
+                                       (seq_no) ? seq_no->cy_valueint : -1,
+                                       err_rc);
+}
+
+static int handle_yaml_config_net(struct cYAML *tree, struct cYAML **show_rc,
+                                 struct cYAML **err_rc)
+{
+       struct cYAML *net, *intf, *tunables, *seq_no,
+             *peer_to = NULL, *peer_buf_cr = NULL, *peer_cr = NULL,
+             *credits = NULL, *ip2net = NULL, *smp = NULL, *child;
+       char devs[LNET_MAX_STR_LEN];
+       char *loc = devs;
+       int size = LNET_MAX_STR_LEN;
+       int num;
+       bool intf_found = false;
+
+       ip2net = cYAML_get_object_item(tree, "ip2net");
+       net = cYAML_get_object_item(tree, "net");
+       intf = cYAML_get_object_item(tree, "interfaces");
+       if (intf != NULL) {
+               /* grab all the interfaces */
+               child = intf->cy_child;
+               while (child != NULL && size > 0) {
+                       if (loc > devs)
+                               num  = snprintf(loc, size, ",%s",
+                                               child->cy_valuestring);
+                       else
+                               num = snprintf(loc, size, "%s",
+                                              child->cy_valuestring);
+                       size -= num;
+                       loc += num;
+                       intf_found = true;
+                       child = child->cy_next;
+               }
+       }
+
+       tunables = cYAML_get_object_item(tree, "tunables");
+       if (tunables != NULL) {
+               peer_to = cYAML_get_object_item(tunables, "peer_timeout");
+               peer_cr = cYAML_get_object_item(tunables, "peer_credits");
+               peer_buf_cr = cYAML_get_object_item(tunables,
+                                                   "peer_buffer_credits");
+               credits = cYAML_get_object_item(tunables, "credits");
+               smp = cYAML_get_object_item(tunables, "SMP");
+       }
+       seq_no = cYAML_get_object_item(tree, "seq_no");
+
+       return lustre_lnet_config_net((net) ? net->cy_valuestring : NULL,
+                                     (intf_found) ? devs : NULL,
+                                     (ip2net) ? ip2net->cy_valuestring : NULL,
+                                     (peer_to) ? peer_to->cy_valueint : -1,
+                                     (peer_cr) ? peer_cr->cy_valueint : -1,
+                                     (peer_buf_cr) ?
+                                       peer_buf_cr->cy_valueint : -1,
+                                     (credits) ? credits->cy_valueint : -1,
+                                     (smp) ? smp->cy_valuestring : NULL,
+                                     (seq_no) ? seq_no->cy_valueint : -1,
+                                     err_rc);
+}
+
+static int handle_yaml_config_buffers(struct cYAML *tree,
+                                     struct cYAML **show_rc,
+                                     struct cYAML **err_rc)
+{
+       int rc;
+       struct cYAML *tiny, *small, *large, *seq_no;
+
+       tiny = cYAML_get_object_item(tree, "tiny");
+       small = cYAML_get_object_item(tree, "small");
+       large = cYAML_get_object_item(tree, "large");
+       seq_no = cYAML_get_object_item(tree, "seq_no");
+
+       rc = lustre_lnet_config_buffers((tiny) ? tiny->cy_valueint : -1,
+                                       (small) ? small->cy_valueint : -1,
+                                       (large) ? large->cy_valueint : -1,
+                                       (seq_no) ? seq_no->cy_valueint : -1,
+                                       err_rc);
+
+       return rc;
+}
+
+static int handle_yaml_config_routing(struct cYAML *tree,
+                                     struct cYAML **show_rc,
+                                     struct cYAML **err_rc)
+{
+       int rc = LUSTRE_CFG_RC_NO_ERR;
+       struct cYAML *seq_no, *enable;
+
+       seq_no = cYAML_get_object_item(tree, "seq_no");
+       enable = cYAML_get_object_item(tree, "enable");
+
+       if (enable) {
+               rc = lustre_lnet_enable_routing(enable->cy_valueint,
+                                               (seq_no) ?
+                                                   seq_no->cy_valueint : -1,
+                                               err_rc);
+       }
+
+       return rc;
+}
+
+static int handle_yaml_del_route(struct cYAML *tree, struct cYAML **show_rc,
+                                struct cYAML **err_rc)
+{
+       struct cYAML *net;
+       struct cYAML *gw;
+       struct cYAML *seq_no;
+
+       net = cYAML_get_object_item(tree, "net");
+       gw = cYAML_get_object_item(tree, "gateway");
+       seq_no = cYAML_get_object_item(tree, "seq_no");
+
+       return lustre_lnet_del_route((net) ? net->cy_valuestring : NULL,
+                                    (gw) ? gw->cy_valuestring : NULL,
+                                    (seq_no) ? seq_no->cy_valueint : -1,
+                                    err_rc);
+}
+
+static int handle_yaml_del_net(struct cYAML *tree, struct cYAML **show_rc,
+                              struct cYAML **err_rc)
+{
+       struct cYAML *net, *seq_no;
+
+       net = cYAML_get_object_item(tree, "net");
+       seq_no = cYAML_get_object_item(tree, "seq_no");
+
+       return lustre_lnet_del_net((net) ? net->cy_valuestring : NULL,
+                                  (seq_no) ? seq_no->cy_valueint : -1,
+                                  err_rc);
+}
+
+static int handle_yaml_del_routing(struct cYAML *tree, struct cYAML **show_rc,
+                                  struct cYAML **err_rc)
+{
+       struct cYAML *seq_no;
+
+       seq_no = cYAML_get_object_item(tree, "seq_no");
+
+       return lustre_lnet_enable_routing(0, (seq_no) ?
+                                               seq_no->cy_valueint : -1,
+                                       err_rc);
+}
+
+static int handle_yaml_show_route(struct cYAML *tree, struct cYAML **show_rc,
+                                 struct cYAML **err_rc)
+{
+       struct cYAML *net;
+       struct cYAML *gw;
+       struct cYAML *hop;
+       struct cYAML *prio;
+       struct cYAML *detail;
+       struct cYAML *seq_no;
+
+       net = cYAML_get_object_item(tree, "net");
+       gw = cYAML_get_object_item(tree, "gateway");
+       hop = cYAML_get_object_item(tree, "hop");
+       prio = cYAML_get_object_item(tree, "priority");
+       detail = cYAML_get_object_item(tree, "detail");
+       seq_no = cYAML_get_object_item(tree, "seq_no");
+
+       return lustre_lnet_show_route((net) ? net->cy_valuestring : NULL,
+                                     (gw) ? gw->cy_valuestring : NULL,
+                                     (hop) ? hop->cy_valueint : -1,
+                                     (prio) ? prio->cy_valueint : -1,
+                                     (detail) ? detail->cy_valueint : 0,
+                                     (seq_no) ? seq_no->cy_valueint : -1,
+                                     show_rc,
+                                     err_rc);
+}
+
+static int handle_yaml_show_net(struct cYAML *tree, struct cYAML **show_rc,
+                               struct cYAML **err_rc)
+{
+       struct cYAML *net, *detail, *seq_no;
+
+       net = cYAML_get_object_item(tree, "net");
+       detail = cYAML_get_object_item(tree, "detail");
+       seq_no = cYAML_get_object_item(tree, "seq_no");
+
+       return lustre_lnet_show_net((net) ? net->cy_valuestring : NULL,
+                                   (detail) ? detail->cy_valueint : 0,
+                                   (seq_no) ? seq_no->cy_valueint : -1,
+                                   show_rc,
+                                   err_rc);
+}
+
+static int handle_yaml_show_routing(struct cYAML *tree, struct cYAML **show_rc,
+                                   struct cYAML **err_rc)
+{
+       struct cYAML *seq_no;
+
+       seq_no = cYAML_get_object_item(tree, "seq_no");
+
+       return lustre_lnet_show_routing((seq_no) ? seq_no->cy_valueint : -1,
+                                       show_rc, err_rc);
+}
+
+static int handle_yaml_show_credits(struct cYAML *tree, struct cYAML **show_rc,
+                                   struct cYAML **err_rc)
+{
+       struct cYAML *seq_no;
+
+       seq_no = cYAML_get_object_item(tree, "seq_no");
+
+       return lustre_lnet_show_peer_credits((seq_no) ?
+                                               seq_no->cy_valueint : -1,
+                                            show_rc, err_rc);
+}
+
+static int handle_yaml_show_stats(struct cYAML *tree, struct cYAML **show_rc,
+                                 struct cYAML **err_rc)
+{
+       struct cYAML *seq_no;
+
+       seq_no = cYAML_get_object_item(tree, "seq_no");
+
+       return lustre_lnet_show_stats((seq_no) ? seq_no->cy_valueint : -1,
+                                     show_rc, err_rc);
+}
+
+struct lookup_cmd_hdlr_tbl {
+       char *name;
+       cmd_handler_t cb;
+};
+
+static struct lookup_cmd_hdlr_tbl lookup_config_tbl[] = {
+       {"route", handle_yaml_config_route},
+       {"net", handle_yaml_config_net},
+       {"routing", handle_yaml_config_routing},
+       {"buffers", handle_yaml_config_buffers},
+       {NULL, NULL}
+};
+
+static struct lookup_cmd_hdlr_tbl lookup_del_tbl[] = {
+       {"route", handle_yaml_del_route},
+       {"net", handle_yaml_del_net},
+       {"routing", handle_yaml_del_routing},
+       {NULL, NULL}
+};
+
+static struct lookup_cmd_hdlr_tbl lookup_show_tbl[] = {
+       {"route", handle_yaml_show_route},
+       {"net", handle_yaml_show_net},
+       {"buffers", handle_yaml_show_routing},
+       {"routing", handle_yaml_show_routing},
+       {"credits", handle_yaml_show_credits},
+       {"statistics", handle_yaml_show_stats},
+       {NULL, NULL}
+};
+
+static cmd_handler_t lookup_fn(char *key,
+                              struct lookup_cmd_hdlr_tbl *tbl)
+{
+       int i;
+       if (key == NULL)
+               return NULL;
+
+       for (i = 0; tbl[i].name != NULL; i++) {
+               if (strncmp(key, tbl[i].name, strlen(tbl[i].name)) == 0)
+                       return tbl[i].cb;
+       }
+
+       return NULL;
+}
+
+static int lustre_yaml_cb_helper(char *f, struct lookup_cmd_hdlr_tbl *table,
+                                struct cYAML **show_rc, struct cYAML **err_rc)
+{
+       struct cYAML *tree, *item = NULL, *head, *child;
+       cmd_handler_t cb;
+       char err_str[LNET_MAX_STR_LEN];
+       int rc = LUSTRE_CFG_RC_NO_ERR, return_rc = LUSTRE_CFG_RC_NO_ERR;
+
+       tree = cYAML_build_tree(f, NULL, 0, err_rc);
+       if (tree == NULL)
+               return LUSTRE_CFG_RC_BAD_PARAM;
+
+       child = tree->cy_child;
+       while (child != NULL) {
+               cb = lookup_fn(child->cy_string, table);
+               if (cb == NULL) {
+                       snprintf(err_str, sizeof(err_str),
+                               "\"call back for '%s' not found\"",
+                               child->cy_string);
+                       cYAML_build_error(LUSTRE_CFG_RC_BAD_PARAM, -1,
+                                       "yaml", "helper", err_str, err_rc);
+                       goto out;
+               }
+
+               if (cYAML_is_sequence(child)) {
+                       while ((head = cYAML_get_next_seq_item(child, &item))
+                              != NULL) {
+                               rc = cb(head, show_rc, err_rc);
+                               /* if processing fails or no cb is found
+                                * then fail */
+                               if (rc != LUSTRE_CFG_RC_NO_ERR) {
+                                       snprintf(err_str, sizeof(err_str),
+                                               "\"Failed to process request:  "
+                                               "'%s' [%d, %p]\"",
+                                               head->cy_string, rc, cb);
+                                       cYAML_build_error(
+                                               LUSTRE_CFG_RC_BAD_PARAM, -1,
+                                               "yaml", "helper", err_str,
+                                               err_rc);
+                                       return_rc = rc;
+                               }
+                       }
+               } else {
+                       rc = cb(child, show_rc, err_rc);
+                       /* if processing fails or no cb is found then fail */
+                       if (rc != LUSTRE_CFG_RC_NO_ERR) {
+                               snprintf(err_str, sizeof(err_str),
+                                       "\"Failed to process request: '%s'"
+                                       " [%d, %p]\"",
+                                       child->cy_string, rc, cb);
+                               cYAML_build_error(LUSTRE_CFG_RC_BAD_PARAM, -1,
+                                       "yaml", "helper", err_str, err_rc);
+                               return_rc = rc;
+                       }
+               }
+               item = NULL;
+               child = child->cy_next;
+       }
+
+out:
+       cYAML_free_tree(tree);
+
+       return return_rc;
+}
+
+int lustre_yaml_config(char *f, struct cYAML **err_rc)
+{
+       return lustre_yaml_cb_helper(f, lookup_config_tbl,
+                                    NULL, err_rc);
+}
+
+int lustre_yaml_del(char *f, struct cYAML **err_rc)
+{
+       return lustre_yaml_cb_helper(f, lookup_del_tbl,
+                                    NULL, err_rc);
+}
+
+int lustre_yaml_show(char *f, struct cYAML **show_rc, struct cYAML **err_rc)
+{
+       return lustre_yaml_cb_helper(f, lookup_show_tbl,
+                                    show_rc, err_rc);
+}
diff --git a/lnet/utils/lnetconfig/liblnetconfig.h b/lnet/utils/lnetconfig/liblnetconfig.h
new file mode 100644 (file)
index 0000000..a87ce31
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * LGPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * LGPL HEADER END
+ *
+ * Copyright (c) 2013, Intel Corporation.
+ *
+ * Author:
+ *   Amir Shehata <amir.shehata@intel.com>
+ */
+
+#ifndef LIB_LUSTRE_CONFIG_API_H
+#define LIB_LUSTRE_CONFIG_API_H
+
+#define LUSTRE_CFG_RC_NO_ERR                    0
+#define LUSTRE_CFG_RC_BAD_PARAM                        -1
+#define LUSTRE_CFG_RC_MISSING_PARAM            -2
+#define LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM       -3
+#define LUSTRE_CFG_RC_OUT_OF_MEM               -4
+#define LUSTRE_CFG_RC_GENERIC_ERR              -5
+
+/* forward declaration of the cYAML structure. */
+struct cYAML;
+
+/*
+ * lustre_lnet_config_lib_init()
+ *   Initialize the Library to enable communication with the LNET kernel
+ *   module.  Returns the device ID or -EINVAL if there is an error
+ */
+int lustre_lnet_config_lib_init();
+
+/*
+ * lustre_lnet_config_ni_system
+ *   Initialize/Uninitialize the lnet NI system.
+ *
+ *   up - whehter to init or uninit the system
+ *   load_ni_from_mod - load NI from mod params.
+ *   seq_no - sequence number of the request
+ *   err_rc - [OUT] struct cYAML tree describing the error. Freed by
+ *            caller
+ */
+int lustre_lnet_config_ni_system(bool up, bool load_ni_from_mod,
+                                int seq_no, struct cYAML **err_rc);
+
+/*
+ * lustre_lnet_config_route
+ *   Send down an IOCTL to the kernel to configure the route
+ *
+ *   nw - network
+ *   gw - gateway
+ *   hops - number of hops passed down by the user
+ *   prio - priority of the route
+ *   seq_no - sequence number of the request
+ *   err_rc - [OUT] struct cYAML tree describing the error. Freed by caller
+ */
+int lustre_lnet_config_route(char *nw, char *gw, int hops, int prio,
+                            int seq_no, struct cYAML **err_rc);
+
+/*
+ * lustre_lnet_del_route
+ *   Send down an IOCTL to the kernel to delete a route
+ *
+ *   nw - network
+ *   gw - gateway
+ *   seq_no - sequence number of the request
+ *   err_rc - [OUT] struct cYAML tree describing the error. Freed by caller
+ */
+int lustre_lnet_del_route(char *nw, char *gw, int seq_no,
+                         struct cYAML **err_rc);
+
+/*
+ * lustre_lnet_show_route
+ *   Send down an IOCTL to the kernel to show routes
+ *   This function will get one route at a time and filter according to
+ *   provided parameters. If no routes are available then it will dump all
+ *   routes that are in the system.
+ *
+ *   nw - network.  Optional.  Used to filter output
+ *   gw - gateway. Optional. Used to filter ouptut
+ *   hops - number of hops passed down by the user
+ *          Optional.  Used to filter output.
+ *   prio - priority of the route.  Optional.  Used to filter output.
+ *   detail - flag to indicate whether detail output is required
+ *   seq_no - sequence number of the request
+ *   show_rc - [OUT] The show output in YAML.  Must be freed by caller.
+ *   err_rc - [OUT] struct cYAML tree describing the error. Freed by caller
+ */
+int lustre_lnet_show_route(char *nw, char *gw,
+                          int hops, int prio, int detail,
+                          int seq_no, struct cYAML **show_rc,
+                          struct cYAML **err_rc);
+
+/*
+ * lustre_lnet_config_net
+ *   Send down an IOCTL to configure a network.
+ *
+ *   net - the network name
+ *   intf - the interface of the network of the form net_name(intf)
+ *   ip2net - this parameter allows configuring multiple networks.
+ *     it takes precedence over the net and intf parameters
+ *   peer_to - peer timeout
+ *   peer_cr - peer credit
+ *   peer_buf_cr - peer buffer credits
+ *       - the above are LND tunable parameters and are optional
+ *   credits - network interface credits
+ *   smp - cpu affinity
+ *   seq_no - sequence number of the request
+ *   err_rc - [OUT] struct cYAML tree describing the error. Freed by caller
+ */
+int lustre_lnet_config_net(char *net, char *intf, char *ip2net,
+                          int peer_to, int peer_cr, int peer_buf_cr,
+                          int credits, char *smp, int seq_no,
+                          struct cYAML **err_rc);
+
+/*
+ * lustre_lnet_del_net
+ *   Send down an IOCTL to delete a network.
+ *
+ *   nw - network to delete.
+ *   seq_no - sequence number of the request
+ *   err_rc - [OUT] struct cYAML tree describing the error. Freed by caller
+ */
+int lustre_lnet_del_net(char *nw, int seq_no,
+                       struct cYAML **err_rc);
+
+/*
+ * lustre_lnet_show_net
+ *   Send down an IOCTL to show networks.
+ *   This function will use the nw paramter to filter the output.  If it's
+ *   not provided then all networks are listed.
+ *
+ *   nw - network to show.  Optional.  Used to filter output.
+ *   detail - flag to indicate if we require detail output.
+ *   seq_no - sequence number of the request
+ *   show_rc - [OUT] The show output in YAML.  Must be freed by caller.
+ *   err_rc - [OUT] struct cYAML tree describing the error. Freed by caller
+ */
+int lustre_lnet_show_net(char *nw, int detail, int seq_no,
+                        struct cYAML **show_rc, struct cYAML **err_rc);
+
+/*
+ * lustre_lnet_enable_routing
+ *   Send down an IOCTL to enable or diable routing
+ *
+ *   enable - 1 to enable routing, 0 to disable routing
+ *   seq_no - sequence number of the request
+ *   err_rc - [OUT] struct cYAML tree describing the error. Freed by caller
+ */
+int lustre_lnet_enable_routing(int enable, int seq_no,
+                              struct cYAML **err_rc);
+
+/*
+ * lustre_lnet_config_buffers
+ *   Send down an IOCTL to configure routing buffer sizes.  A value of 0 means
+ *   default that particular buffer to default size. A value of -1 means
+ *   leave the value of the buffer un changed.
+ *
+ *   tiny - tiny buffers
+ *   small - small buffers
+ *   large - large buffers.
+ *   seq_no - sequence number of the request
+ *   err_rc - [OUT] struct cYAML tree describing the error. Freed by caller
+ */
+int lustre_lnet_config_buffers(int tiny, int small, int large,
+                              int seq_no, struct cYAML **err_rc);
+
+/*
+ * lustre_lnet_show_routing
+ *   Send down an IOCTL to dump buffers and routing status
+ *   This function is used to dump buffers for all CPU partitions.
+ *
+ *   seq_no - sequence number of the request
+ *   show_rc - [OUT] The show output in YAML.  Must be freed by caller.
+ *   err_rc - [OUT] struct cYAML tree describing the error. Freed by caller
+ */
+int lustre_lnet_show_routing(int seq_no, struct cYAML **show_rc,
+                            struct cYAML **err_rc);
+
+/*
+ * lustre_lnet_show_peer_credits
+ *   Shows credit details on the peers in the system
+ *
+ *     seq_no - sequence number of the command
+ *     show_rc - YAML structure of the resultant show
+ *     err_rc - YAML strucutre of the resultant return code.
+ */
+int lustre_lnet_show_peer_credits(int seq_no, struct cYAML **show_rc,
+                                 struct cYAML **err_rc);
+
+/*
+ * lustre_lnet_show_stats
+ *   Shows internal LNET statistics.  This is useful to display the
+ *   current LNET activity, such as number of messages route, etc
+ *
+ *     seq_no - sequence number of the command
+ *     show_rc - YAML structure of the resultant show
+ *     err_rc - YAML strucutre of the resultant return code.
+ */
+int lustre_lnet_show_stats(int seq_no, struct cYAML **show_rc,
+                          struct cYAML **err_rc);
+
+/*
+ * lustre_yaml_config
+ *   Parses the provided YAML file and then calls the specific APIs
+ *   to configure the entities identified in the file
+ *
+ *   f - YAML file
+ *   err_rc - [OUT] struct cYAML tree describing the error. Freed by caller
+ */
+int lustre_yaml_config(char *f, struct cYAML **err_rc);
+
+/*
+ * lustre_yaml_del
+ *   Parses the provided YAML file and then calls the specific APIs
+ *   to delete the entities identified in the file
+ *
+ *   f - YAML file
+ *   err_rc - [OUT] struct cYAML tree describing the error. Freed by caller
+ */
+int lustre_yaml_del(char *f, struct cYAML **err_rc);
+
+/*
+ * lustre_yaml_show
+ *   Parses the provided YAML file and then calls the specific APIs
+ *   to show the entities identified in the file
+ *
+ *   f - YAML file
+ *   show_rc - [OUT] The show output in YAML.  Must be freed by caller.
+ *   err_rc - [OUT] struct cYAML tree describing the error. Freed by caller
+ */
+int lustre_yaml_show(char *f, struct cYAML **show_rc,
+                    struct cYAML **err_rc);
+
+#endif /* LIB_LUSTRE_CONFIG_API_H */
index 23dea92..ebebe8f 100644 (file)
@@ -8,6 +8,7 @@
 %bcond_without lustre_utils
 %bcond_without lustre_iokit
 %bcond_without lustre_modules
+%bcond_with lnet_dlc
 
 %if %{without servers}
     # --without servers overrides --with {ldiskfs|zfs}
@@ -134,6 +135,10 @@ AutoReqProv: no
 # for RHEL we need to require the specific kernel still since weak-modules
 # support on RH is, well, weak, to be punny about it
 Requires: kernel = %{krequires}
+%if %{with lnet_dlc}
+Requires: libyaml
+BuildRequires: libyaml-devel
+%endif
 %endif
 %endif
 Group: Development/Kernel
@@ -373,6 +378,16 @@ chmod -R go-w lustre-source/lustre-%{version}
 # fc18 needs 'x' permission for library files
 find $RPM_BUILD_ROOT -name \*.so -type f -exec chmod +x {} \;
 
+if [ -f $RPM_BUILD_ROOT%{_libdir}/liblnetconfig.a ] ; then
+  echo '%attr(-, root, root) %{_libdir}/liblnetconfig.a' >>lustre.files
+  echo '%attr(-, root, root) %{_libdir}/liblnetconfig.so' >>lustre.files
+fi
+
+if [ -f $RPM_BUILD_ROOT%{_libdir}/liblustre.so ] ; then
+  echo '%{_libdir}/liblustre.a' >>lustre.files
+  echo '%{_libdir}/liblustre.so' >>lustre.files
+fi
+
 if [ -f $RPM_BUILD_ROOT%{_libdir}/libiam.a ] ; then
   echo '%{_libdir}/libiam.a' >>lustre.files
 fi