+/*
+ * 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);
+}