/* * 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 . * * LGPL HEADER END * * Copyright (c) 2014, 2015, Intel Corporation. * * Author: * Amir Shehata */ /* * 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 #include #include #include #include #include #include #include #include #include #include #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) { /* hops is undefined */ hops = LNET_UNDEFINED_HOPS; } else if (hops < 1 || hops > 255) { snprintf(err_str, sizeof(err_str), "\"invalid hop count %d, must be between 1 and 255\"", 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) { rc = -errno; snprintf(err_str, sizeof(err_str), "\"cannot add route: %s\"", strerror(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) { rc = -errno; snprintf(err_str, sizeof(err_str), "\"cannot delete route: %s\"", strerror(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; int l_errno = 0; __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]; bool exist = false; 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) { l_errno = errno; 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; exist = true; 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 (l_errno != ENOENT) { snprintf(err_str, sizeof(err_str), "\"cannot get routes: %s\"", strerror(l_errno)); rc = -l_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 || !exist) { 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; 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; rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_NET, &data); if (rc < 0) { rc = -errno; snprintf(err_str, sizeof(err_str), "\"cannot add network: %s\"", strerror(errno)); } out: cYAML_build_error(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) { rc = -errno; snprintf(err_str, sizeof(err_str), "\"cannot delete network: %s\"", strerror(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; int l_errno = 0; 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; char err_str[LNET_MAX_STR_LEN]; bool exist = false; 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++) { pos = str_buf; memset(buf, 0, sizeof(*data) + sizeof(*net_config)); 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) { l_errno = errno; 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; exist = true; 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, "net", libcfs_net2str( LNET_NIDNET(data->cfg_nid))) == NULL) goto out; 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) { char *limit; 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; /* out put the CPTs in the format: "[x,x,x,...]" */ limit = str_buf + str_buf_len - 3; pos += snprintf(pos, limit - pos, "\"["); for (j = 0 ; data->cfg_ncpts > 1 && j < data->cfg_ncpts && pos < limit; j++) { pos += snprintf(pos, limit - pos, "%d", net_config->ni_cpts[j]); if ((j + 1) < data->cfg_ncpts) pos += snprintf(pos, limit - pos, ","); } pos += snprintf(pos, 3, "]\""); if (data->cfg_ncpts > 1 && cYAML_create_string(tunables, "CPT", 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 (l_errno != ENOENT) { snprintf(err_str, sizeof(err_str), "\"cannot get networks: %s\"", strerror(l_errno)); rc = -l_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 || !exist) { 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) { rc = -errno; snprintf(err_str, sizeof(err_str), "\"cannot %s routing %s\"", (enable) ? "enable" : "disable", strerror(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) { rc = -errno; snprintf(err_str, sizeof(err_str), "\"cannot configure buffers: %s\"", strerror(errno)); goto out; } out: cYAML_build_error(rc, seq_no, ADD_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; int l_errno = 0; char *buf; char *pools[LNET_NRBPOOLS] = {"tiny", "small", "large"}; int buf_count[LNET_NRBPOOLS] = {0}; struct cYAML *root = NULL, *pools_node = NULL, *type_node = NULL, *item = NULL, *cpt = NULL, *first_seq = NULL, *buffers = NULL; int i, j; char err_str[LNET_MAX_STR_LEN]; char node_name[LNET_MAX_STR_LEN]; bool exist = false; 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) { l_errno = errno; break; } exist = true; 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 (j = 0; j < LNET_NRBPOOLS; j++) { type_node = cYAML_create_object(cpt, pools[j]); if (type_node == NULL) goto out; if (cYAML_create_number(type_node, "npages", pool_cfg->pl_pools[j].pl_npages) == NULL) goto out; if (cYAML_create_number(type_node, "nbuffers", pool_cfg->pl_pools[j]. pl_nbuffers) == NULL) goto out; if (cYAML_create_number(type_node, "credits", pool_cfg->pl_pools[j]. pl_credits) == NULL) goto out; if (cYAML_create_number(type_node, "mincredits", pool_cfg->pl_pools[j]. pl_mincredits) == NULL) goto out; /* keep track of the total count for each of the * tiny, small and large buffers */ buf_count[j] += pool_cfg->pl_pools[j].pl_nbuffers; } } 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; } /* create a buffers entry in the show. This is necessary so that * if the YAML output is used to configure a node, the buffer * configuration takes hold */ buffers = cYAML_create_object(root, "buffers"); if (buffers == NULL) goto out; for (i = 0; i < LNET_NRBPOOLS; i++) { if (cYAML_create_number(buffers, pools[i], buf_count[i]) == NULL) goto out; } if (show_rc == NULL) cYAML_print_tree(root); if (l_errno != ENOENT) { snprintf(err_str, sizeof(err_str), "\"cannot get routing information: %s\"", strerror(l_errno)); rc = -l_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 || !exist) { cYAML_free_tree(root); } else if (show_rc != NULL && *show_rc != NULL) { struct cYAML *routing_node; /* there should exist only one routing block and one * buffers block. If there already exists a previous one * then don't add another */ routing_node = cYAML_get_object_item(*show_rc, "routing"); if (routing_node == NULL) { cYAML_insert_sibling((*show_rc)->cy_child, root->cy_child); 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; int l_errno = 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) { l_errno = errno; 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 (l_errno != ENOENT) { snprintf(err_str, sizeof(err_str), "\"cannot get peer information: %s\"", strerror(l_errno)); rc = -l_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; int l_errno; 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) { l_errno = errno; snprintf(err_str, sizeof(err_str), "\"cannot get lnet statistics: %s\"", strerror(l_errno)); rc = -l_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, "CPT"); } 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 (rc != LUSTRE_CFG_RC_NO_ERR) return_rc = rc; } } else { rc = cb(child, show_rc, err_rc); if (rc != LUSTRE_CFG_RC_NO_ERR) 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); }