From 02de152aeb458c55c017f3167cd1c9bab4282586 Mon Sep 17 00:00:00 2001 From: Sonia Sharma Date: Mon, 13 Feb 2017 12:40:19 -0800 Subject: [PATCH] LU-9480 lnet: add "lnetctl discover" Add a "discover" subcommand to lnetctl jt_discover() in lnetctl.c calls lustre_lnet_discover_nid() to implement "lnetctl discover". The output is similar to "lnetctl ping" command. This patch also does some clean up in linlnetconfig.c For parameters under global settings, the common code for them is pulled in funtions ioctl_set_value() and ioctl_show_global_values(). Test-Parameters: trivial Signed-off-by: Sonia Sharma Signed-off-by: Amir Shehata Signed-off-by: Olaf Weber Change-Id: I98ebb0b27de4b32ea07421f7dd71a4a1c96f3e05 Reviewed-on: https://review.whamcloud.com/25793 --- lnet/include/uapi/linux/lnet/libcfs_ioctl.h | 2 +- lnet/lnet/api-ni.c | 99 ++++++++++ lnet/utils/lnetconfig/liblnetconfig.c | 268 ++++++++++++++-------------- lnet/utils/lnetconfig/liblnetconfig.h | 13 ++ lnet/utils/lnetctl.c | 63 +++++++ 5 files changed, 307 insertions(+), 138 deletions(-) diff --git a/lnet/include/uapi/linux/lnet/libcfs_ioctl.h b/lnet/include/uapi/linux/lnet/libcfs_ioctl.h index fd24a9a..5e81123 100644 --- a/lnet/include/uapi/linux/lnet/libcfs_ioctl.h +++ b/lnet/include/uapi/linux/lnet/libcfs_ioctl.h @@ -113,7 +113,7 @@ struct libcfs_debug_ioctl_data { #define IOC_LIBCFS_DEL_PEER _IOWR('e', 74, IOCTL_LIBCFS_TYPE) #define IOC_LIBCFS_ADD_PEER _IOWR('e', 75, IOCTL_LIBCFS_TYPE) #define IOC_LIBCFS_GET_PEER _IOWR('e', 76, IOCTL_LIBCFS_TYPE) -/* ioctl 77 is free for use */ +#define IOC_LIBCFS_DISCOVER _IOWR('e', 77, IOCTL_LIBCFS_TYPE) #define IOC_LIBCFS_ADD_INTERFACE _IOWR('e', 78, IOCTL_LIBCFS_TYPE) #define IOC_LIBCFS_DEL_INTERFACE _IOWR('e', 79, IOCTL_LIBCFS_TYPE) #define IOC_LIBCFS_GET_INTERFACE _IOWR('e', 80, IOCTL_LIBCFS_TYPE) diff --git a/lnet/lnet/api-ni.c b/lnet/lnet/api-ni.c index c1a3398..ad39363 100644 --- a/lnet/lnet/api-ni.c +++ b/lnet/lnet/api-ni.c @@ -101,6 +101,9 @@ static atomic_t lnet_dlc_seq_no = ATOMIC_INIT(0); static int lnet_ping(struct lnet_process_id id, signed long timeout, struct lnet_process_id __user *ids, int n_ids); +static int lnet_discover(lnet_process_id_t id, __u32 force, + lnet_process_id_t __user *ids, int n_ids); + static int discovery_set(const char *val, struct kernel_param *kp) { @@ -3294,6 +3297,25 @@ LNetCtl(unsigned int cmd, void *arg) return 0; } + case IOC_LIBCFS_DISCOVER: { + struct lnet_ioctl_ping_data *discover = arg; + struct lnet_peer *lp; + + rc = lnet_discover(discover->ping_id, discover->op_param, + discover->ping_buf, + discover->ping_count); + if (rc < 0) + return rc; + lp = lnet_find_peer(discover->ping_id.nid); + if (lp) { + discover->ping_id.nid = lp->lp_primary_nid; + discover->mr_info = lnet_peer_is_multi_rail(lp); + } + + discover->ping_count = rc; + return 0; + } + default: ni = lnet_net2ni_addref(data->ioc_net); if (ni == NULL) @@ -3564,3 +3586,80 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, lnet_ping_buffer_decref(pbuf); return rc; } + +static int +lnet_discover(lnet_process_id_t id, __u32 force, lnet_process_id_t __user *ids, + int n_ids) +{ + struct lnet_peer_ni *lpni; + struct lnet_peer_ni *p; + struct lnet_peer *lp; + lnet_process_id_t *buf; + int cpt; + int i; + int rc; + int max_intf = lnet_interfaces_max; + + if (n_ids <= 0 || + id.nid == LNET_NID_ANY || + n_ids > max_intf) + return -EINVAL; + + if (id.pid == LNET_PID_ANY) + id.pid = LNET_PID_LUSTRE; + + LIBCFS_ALLOC(buf, n_ids * sizeof(*buf)); + if (!buf) + return -ENOMEM; + + cpt = lnet_net_lock_current(); + lpni = lnet_nid2peerni_locked(id.nid, LNET_NID_ANY, cpt); + if (IS_ERR(lpni)) { + rc = PTR_ERR(lpni); + goto out; + } + + /* + * Clearing the NIDS_UPTODATE flag ensures the peer will + * be discovered, provided discovery has not been disabled. + */ + lp = lpni->lpni_peer_net->lpn_peer; + spin_lock(&lp->lp_lock); + lp->lp_state &= ~LNET_PEER_NIDS_UPTODATE; + /* If the force flag is set, force a PING and PUSH as well. */ + if (force) + lp->lp_state |= LNET_PEER_FORCE_PING | LNET_PEER_FORCE_PUSH; + spin_unlock(&lp->lp_lock); + rc = lnet_discover_peer_locked(lpni, cpt, true); + if (rc) + goto out_decref; + + /* Peer may have changed. */ + lp = lpni->lpni_peer_net->lpn_peer; + if (lp->lp_nnis < n_ids) + n_ids = lp->lp_nnis; + + i = 0; + p = NULL; + while ((p = lnet_get_next_peer_ni_locked(lp, NULL, p)) != NULL) { + buf[i].pid = id.pid; + buf[i].nid = p->lpni_nid; + if (++i >= n_ids) + break; + } + + lnet_net_unlock(cpt); + + rc = -EFAULT; + if (copy_to_user(ids, buf, n_ids * sizeof(*buf))) + goto out_relock; + rc = n_ids; +out_relock: + lnet_net_lock(cpt); +out_decref: + lnet_peer_ni_decref_locked(lpni); +out: + lnet_net_unlock(cpt); + + return rc; +} diff --git a/lnet/utils/lnetconfig/liblnetconfig.c b/lnet/utils/lnetconfig/liblnetconfig.c index bc545d8..99ce6a8 100644 --- a/lnet/utils/lnetconfig/liblnetconfig.c +++ b/lnet/utils/lnetconfig/liblnetconfig.c @@ -604,8 +604,8 @@ static int infra_ping_nid(char *ping_nids, char *oper, int param, int ioc_call, libcfs_nid2str(ping.ping_id.nid)) == NULL) goto out; - if (cYAML_create_string(item, "Multi-Rail", ping.mr_info ? "True" : - "False") == NULL) + if (cYAML_create_string(item, "Multi-Rail", ping.mr_info ? + "True" : "False") == NULL) goto out; tmp = cYAML_create_seq(item, "peer ni"); @@ -669,6 +669,16 @@ int lustre_lnet_ping_nid(char *ping_nids, int timeout, int seq_no, return rc; } +int lustre_lnet_discover_nid(char *ping_nids, int force, int seq_no, + struct cYAML **show_rc, struct cYAML **err_rc) +{ + int rc; + + rc = infra_ping_nid(ping_nids, "discover", force, IOC_LIBCFS_DISCOVER, + seq_no, show_rc, err_rc); + return rc; +} + int lustre_lnet_config_peer_nid(char *pnid, char **nid, int num_nids, bool mr, int seq_no, struct cYAML **err_rc) { @@ -2020,6 +2030,32 @@ out: return rc; } +int ioctl_set_value(__u32 val, int ioc, char *name, + int seq_no, struct cYAML **err_rc) +{ + struct lnet_ioctl_set_value 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, sv_hdr); + data.sv_value = val; + + rc = l_ioctl(LNET_DEV_ID, ioc , &data); + if (rc != 0) { + rc = -errno; + snprintf(err_str, + sizeof(err_str), + "\"cannot configure %s to %d: %s\"", name, + val, strerror(errno)); + } + + cYAML_build_error(rc, seq_no, ADD_CMD, name, err_str, err_rc); + + return rc; +} + int lustre_lnet_config_max_intf(int max, int seq_no, struct cYAML **err_rc) { int rc = LUSTRE_CFG_RC_NO_ERR; @@ -2067,36 +2103,8 @@ int lustre_lnet_config_discovery(int enable, int seq_no, struct cYAML **err_rc) int lustre_lnet_config_numa_range(int range, int seq_no, struct cYAML **err_rc) { - struct lnet_ioctl_set_value data; - int rc = LUSTRE_CFG_RC_NO_ERR; - char err_str[LNET_MAX_STR_LEN]; - - snprintf(err_str, sizeof(err_str), "\"success\""); - - if (range < 0) { - snprintf(err_str, - sizeof(err_str), - "\"range must be >= 0\""); - rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM; - goto out; - } - - LIBCFS_IOC_INIT_V2(data, sv_hdr); - data.sv_value = range; - - rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_SET_NUMA_RANGE, &data); - if (rc != 0) { - rc = -errno; - snprintf(err_str, - sizeof(err_str), - "\"cannot configure numa_range: %s\"", strerror(errno)); - goto out; - } - -out: - cYAML_build_error(rc, seq_no, ADD_CMD, "numa_range", err_str, err_rc); - - return rc; + return ioctl_set_value(range, IOC_LIBCFS_SET_NUMA_RANGE, + "numa_range", seq_no, err_rc); } int lustre_lnet_config_buffers(int tiny, int small, int large, int seq_no, @@ -2669,27 +2677,19 @@ static void add_to_global(struct cYAML *show_rc, struct cYAML *node, free(root); } -int lustre_lnet_show_max_intf(int seq_no, struct cYAML **show_rc, - struct cYAML **err_rc) +static int build_global_yaml_entry(char *err_str, int err_len, int seq_no, + char *name, __u32 value, + struct cYAML **show_rc, + struct cYAML **err_rc, int err) { int rc = LUSTRE_CFG_RC_OUT_OF_MEM; - char val[LNET_MAX_STR_LEN]; - int max_intf; - char err_str[LNET_MAX_STR_LEN]; struct cYAML *root = NULL, *global = NULL; - snprintf(err_str, sizeof(err_str), "\"out of memory\""); - - rc = read_sysfs_file(modparam_path, "lnet_interfaces_max", val, - 1, LNET_MAX_STR_LEN); - if (rc) { - snprintf(err_str, sizeof(err_str), - "\"cannot get max interfaces: %d\"", rc); + if (err) { + rc = err; goto out; } - max_intf = atoi(val); - root = cYAML_create_object(NULL, NULL); if (root == NULL) goto out; @@ -2698,70 +2698,14 @@ int lustre_lnet_show_max_intf(int seq_no, struct cYAML **show_rc, if (global == NULL) goto out; - if (cYAML_create_number(global, "max_intf", - max_intf) == NULL) + if (cYAML_create_number(global, name, + value) == NULL) goto out; 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) - add_to_global(*show_rc, global, root); - else - *show_rc = root; - - cYAML_build_error(rc, seq_no, SHOW_CMD, "global", err_str, err_rc); - - return rc; -} - -int lustre_lnet_show_discovery(int seq_no, struct cYAML **show_rc, - struct cYAML **err_rc) -{ - int rc = LUSTRE_CFG_RC_OUT_OF_MEM; - char val[LNET_MAX_STR_LEN]; - __u32 discovery; - char err_str[LNET_MAX_STR_LEN]; - struct cYAML *root = NULL, *global = NULL; - - snprintf(err_str, sizeof(err_str), "\"out of memory\""); - - rc = read_sysfs_file(modparam_path, "lnet_peer_discovery_disabled", val, - 1, sizeof(val)); - if (rc) { - snprintf(err_str, sizeof(err_str), - "\"cannot get discovery value: %d\"", rc); - goto out; - } - - /* - * the sysfs parameter read indicates if discovery is disabled, - * but we report if discovery is enabled. - */ - discovery = !atoi(val); - - root = cYAML_create_object(NULL, NULL); - if (root == NULL) - goto out; - - global = cYAML_create_object(root, "global"); - if (global == NULL) - goto out; - - if (cYAML_create_number(global, "discovery", - discovery) == NULL) - goto out; - - if (show_rc == NULL) - cYAML_print_tree(root); - - snprintf(err_str, sizeof(err_str), "\"success\""); + snprintf(err_str, err_len, "\"success\""); rc = LUSTRE_CFG_RC_NO_ERR; @@ -2779,61 +2723,92 @@ out: return rc; } -int lustre_lnet_show_numa_range(int seq_no, struct cYAML **show_rc, - struct cYAML **err_rc) +static int ioctl_show_global_values(int ioc, int seq_no, char *name, + struct cYAML **show_rc, + struct cYAML **err_rc) { struct lnet_ioctl_set_value data; int rc; - int l_errno; + int l_errno = 0; char err_str[LNET_MAX_STR_LEN]; - struct cYAML *root = NULL, *global = NULL; snprintf(err_str, sizeof(err_str), "\"out of memory\""); LIBCFS_IOC_INIT_V2(data, sv_hdr); - rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_NUMA_RANGE, &data); + rc = l_ioctl(LNET_DEV_ID, ioc, &data); if (rc != 0) { - l_errno = errno; + l_errno = -errno; snprintf(err_str, sizeof(err_str), - "\"cannot get numa range: %s\"", - strerror(l_errno)); - rc = -l_errno; - goto out; + "\"cannot get %s: %s\"", + name, strerror(l_errno)); } - rc = LUSTRE_CFG_RC_OUT_OF_MEM; + return build_global_yaml_entry(err_str, sizeof(err_str), seq_no, name, + data.sv_value, show_rc, err_rc, l_errno); +} - root = cYAML_create_object(NULL, NULL); - if (root == NULL) - goto out; +int lustre_lnet_show_max_intf(int seq_no, struct cYAML **show_rc, + struct cYAML **err_rc) +{ + int rc = LUSTRE_CFG_RC_OUT_OF_MEM; + char val[LNET_MAX_STR_LEN]; + int max_intf = -1, l_errno = 0; + char err_str[LNET_MAX_STR_LEN]; - global = cYAML_create_object(root, "global"); - if (global == NULL) - goto out; + snprintf(err_str, sizeof(err_str), "\"out of memory\""); - if (cYAML_create_number(global, "numa_range", - data.sv_value) == NULL) - goto out; + rc = read_sysfs_file(modparam_path, "lnet_interfaces_max", val, + 1, sizeof(val)); + if (rc) { + l_errno = -errno; + snprintf(err_str, sizeof(err_str), + "\"cannot get max interfaces: %d\"", rc); + } else { + max_intf = atoi(val); + } - if (show_rc == NULL) - cYAML_print_tree(root); + return build_global_yaml_entry(err_str, sizeof(err_str), seq_no, + "max_intf", max_intf, show_rc, + err_rc, l_errno); +} - 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) { - add_to_global(*show_rc, global, root); +int lustre_lnet_show_discovery(int seq_no, struct cYAML **show_rc, + struct cYAML **err_rc) +{ + int rc = LUSTRE_CFG_RC_OUT_OF_MEM; + char val[LNET_MAX_STR_LEN]; + int discovery = -1, l_errno = 0; + char err_str[LNET_MAX_STR_LEN]; + + snprintf(err_str, sizeof(err_str), "\"out of memory\""); + + rc = read_sysfs_file(modparam_path, "lnet_peer_discovery_disabled", val, + 1, sizeof(val)); + if (rc) { + l_errno = -errno; + snprintf(err_str, sizeof(err_str), + "\"cannot get discovery setting: %d\"", rc); } else { - *show_rc = root; + /* + * The kernel stores a discovery disabled value. User space + * shows whether discovery is enabled. So the value must be + * inverted. + */ + discovery = !atoi(val); } - cYAML_build_error(rc, seq_no, SHOW_CMD, "global", err_str, err_rc); + return build_global_yaml_entry(err_str, sizeof(err_str), seq_no, + "discovery", discovery, show_rc, + err_rc, l_errno); +} - return rc; +int lustre_lnet_show_numa_range(int seq_no, struct cYAML **show_rc, + struct cYAML **err_rc) +{ + return ioctl_show_global_values(IOC_LIBCFS_GET_NUMA_RANGE, seq_no, + "numa_range", show_rc, err_rc); } int lustre_lnet_show_stats(int seq_no, struct cYAML **show_rc, @@ -3704,6 +3679,21 @@ static int handle_yaml_ping(struct cYAML *tree, struct cYAML **show_rc, show_rc, err_rc); } +static int handle_yaml_discover(struct cYAML *tree, struct cYAML **show_rc, + struct cYAML **err_rc) +{ + struct cYAML *seq_no, *nid, *force; + + seq_no = cYAML_get_object_item(tree, "seq_no"); + nid = cYAML_get_object_item(tree, "primary nid"); + force = cYAML_get_object_item(tree, "force"); + + return lustre_lnet_discover_nid((nid) ? nid->cy_valuestring : NULL, + (force) ? force->cy_valueint : 0, + (seq_no) ? seq_no->cy_valueint : -1, + show_rc, err_rc); +} + static int handle_yaml_no_op() { return LUSTRE_CFG_RC_NO_ERR; @@ -3724,6 +3714,7 @@ static struct lookup_cmd_hdlr_tbl lookup_config_tbl[] = { { .name = "statistics", .cb = handle_yaml_no_op }, { .name = "global", .cb = handle_yaml_config_global_settings}, { .name = "ping", .cb = handle_yaml_no_op }, + { .name = "discover", .cb = handle_yaml_no_op }, { .name = NULL } }; static struct lookup_cmd_hdlr_tbl lookup_del_tbl[] = { @@ -3736,6 +3727,7 @@ static struct lookup_cmd_hdlr_tbl lookup_del_tbl[] = { { .name = "statistics", .cb = handle_yaml_no_op }, { .name = "global", .cb = handle_yaml_del_global_settings}, { .name = "ping", .cb = handle_yaml_no_op }, + { .name = "discover", .cb = handle_yaml_no_op }, { .name = NULL } }; static struct lookup_cmd_hdlr_tbl lookup_show_tbl[] = { @@ -3748,6 +3740,7 @@ static struct lookup_cmd_hdlr_tbl lookup_show_tbl[] = { { .name = "statistics", .cb = handle_yaml_show_stats }, { .name = "global", .cb = handle_yaml_show_global_settings}, { .name = "ping", .cb = handle_yaml_no_op }, + { .name = "discover", .cb = handle_yaml_no_op }, { .name = NULL } }; static struct lookup_cmd_hdlr_tbl lookup_exec_tbl[] = { @@ -3760,6 +3753,7 @@ static struct lookup_cmd_hdlr_tbl lookup_exec_tbl[] = { { .name = "statistics", .cb = handle_yaml_no_op }, { .name = "global", .cb = handle_yaml_no_op }, { .name = "ping", .cb = handle_yaml_ping }, + { .name = "discover", .cb = handle_yaml_discover }, { .name = NULL } }; static cmd_handler_t lookup_fn(char *key, diff --git a/lnet/utils/lnetconfig/liblnetconfig.h b/lnet/utils/lnetconfig/liblnetconfig.h index 3909f3b..fad28b2 100644 --- a/lnet/utils/lnetconfig/liblnetconfig.h +++ b/lnet/utils/lnetconfig/liblnetconfig.h @@ -381,6 +381,19 @@ int lustre_lnet_list_peer(int seq_no, int lustre_lnet_ping_nid(char *pnid, int timeout, int seq_no, struct cYAML **show_rc, struct cYAML **err_rc); +/* lustre_lnet_discover_nid + * Discover the nid list, pnids. + * + * pnids - NID list to discover. + * force - force discovery. + * 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_discover_nid(char *pnid, int force, 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 diff --git a/lnet/utils/lnetctl.c b/lnet/utils/lnetctl.c index 969faed..252d8c4 100644 --- a/lnet/utils/lnetctl.c +++ b/lnet/utils/lnetctl.c @@ -1134,6 +1134,7 @@ static int jt_export(int argc, char **argv) if (rc != LUSTRE_CFG_RC_NO_ERR) { cYAML_print_tree2file(stderr, err_rc); cYAML_free_tree(err_rc); + err_rc = NULL; } rc = lustre_lnet_show_route(NULL, NULL, -1, -1, 1, -1, &show_rc, @@ -1141,30 +1142,42 @@ static int jt_export(int argc, char **argv) if (rc != LUSTRE_CFG_RC_NO_ERR) { cYAML_print_tree2file(stderr, err_rc); cYAML_free_tree(err_rc); + err_rc = NULL; } rc = lustre_lnet_show_routing(-1, &show_rc, &err_rc); if (rc != LUSTRE_CFG_RC_NO_ERR) { cYAML_print_tree2file(stderr, err_rc); cYAML_free_tree(err_rc); + err_rc = NULL; } rc = lustre_lnet_show_peer(NULL, 1, -1, &show_rc, &err_rc); if (rc != LUSTRE_CFG_RC_NO_ERR) { cYAML_print_tree2file(stderr, err_rc); cYAML_free_tree(err_rc); + err_rc = NULL; } rc = lustre_lnet_show_numa_range(-1, &show_rc, &err_rc); if (rc != LUSTRE_CFG_RC_NO_ERR) { cYAML_print_tree2file(stderr, err_rc); cYAML_free_tree(err_rc); + err_rc = NULL; } rc = lustre_lnet_show_max_intf(-1, &show_rc, &err_rc); if (rc != LUSTRE_CFG_RC_NO_ERR) { cYAML_print_tree2file(stderr, err_rc); cYAML_free_tree(err_rc); + err_rc = NULL; + } + + rc = lustre_lnet_show_discovery(-1, &show_rc, &err_rc); + if (rc != LUSTRE_CFG_RC_NO_ERR) { + cYAML_print_tree2file(stderr, err_rc); + cYAML_free_tree(err_rc); + err_rc = NULL; } if (show_rc != NULL) { @@ -1422,6 +1435,55 @@ static int jt_ping(int argc, char **argv) return rc; } +static int jt_discover(int argc, char **argv) +{ + struct cYAML *err_rc = NULL; + struct cYAML *show_rc = NULL; + int force = 0; + int rc = 0, opt; + + const char *const short_options = "fh"; + const struct option long_options[] = { + { "force", 0, NULL, 'f' }, + { "help", 0, NULL, 'h' }, + { NULL, 0, NULL, 0 }, + }; + + while ((opt = getopt_long(argc, argv, short_options, + long_options, NULL)) != -1) { + switch (opt) { + case 'f': + force = 1; + break; + case 'h': + printf("discover: nid1 nid2 .. nidN (e.g. 10.2.2.2@tcp)\n" + "\t--force\n" + "\t--help: display this help\n"); + return 0; + default: + return 0; + } + } + + if (argc < 2) + return CMD_HELP; + + for (; optind < argc; optind++) + rc = lustre_lnet_discover_nid(argv[optind], force, -1, &show_rc, + &err_rc); + + if (show_rc) + cYAML_print_tree(show_rc); + + if (err_rc) + cYAML_print_tree2file(stderr, err_rc); + + cYAML_free_tree(err_rc); + cYAML_free_tree(show_rc); + + return rc; +} + command_t list[] = { {"lnet", jt_lnet, 0, "lnet {configure | unconfigure} [--all]"}, {"route", jt_route, 0, "route {add | del | show | help}"}, @@ -1437,6 +1499,7 @@ command_t list[] = { {"global", jt_global, 0, "global {show | help}"}, {"peer", jt_peers, 0, "peer {add | del | show | help}"}, {"ping", jt_ping, 0, "ping {--help}"}, + {"discover", jt_discover, 0, "discover {--help}"}, {"help", Parser_help, 0, "help"}, {"exit", Parser_quit, 0, "quit"}, {"quit", Parser_quit, 0, "quit"}, -- 1.8.3.1