From f021094bc821d68f3ecdca3b627e3e17bfc94fe6 Mon Sep 17 00:00:00 2001 From: Amir Shehata Date: Tue, 2 Apr 2019 16:16:59 -0700 Subject: [PATCH] LU-9121 lnet: add show udsp command Add the show udsp command in liblnetconfig and lnetctl Test-Parameters: trivial testlist=lnet-selftest,sanity-lnet Signed-off-by: Amir Shehata Signed-off-by: Serguei Smirnov Change-Id: Ibddfa60a7b257b136a6be403e94d6f73fb444222 Reviewed-on: https://review.whamcloud.com/34580 Reviewed-by: Sebastien Buisson Tested-by: jenkins Tested-by: Maloo --- libcfs/include/libcfs/util/string.h | 1 + libcfs/libcfs/util/nidstrings.c | 71 +++++++++ lnet/utils/lnetconfig/liblnetconfig.c | 167 ++++++++++++++++++++ lnet/utils/lnetconfig/liblnetconfig.h | 11 ++ lnet/utils/lnetconfig/liblnetconfig_udsp.c | 243 +++++++++++++++++++++++++++++ lnet/utils/lnetctl.c | 52 ++++++ 6 files changed, 545 insertions(+) diff --git a/libcfs/include/libcfs/util/string.h b/libcfs/include/libcfs/util/string.h index f73fd79..1b6e819 100644 --- a/libcfs/include/libcfs/util/string.h +++ b/libcfs/include/libcfs/util/string.h @@ -106,6 +106,7 @@ int cfs_expr_list_values(struct cfs_expr_list *expr_list, int max, __u32 **valpp int cfs_gettok(struct cfs_lstr *next, char delim, struct cfs_lstr *res); int cfs_str2num_check(char *str, int nob, unsigned *num, unsigned min, unsigned max); +int cfs_expr2str(struct list_head *list, char *str, size_t size); int cfs_expr_list_match(__u32 value, struct cfs_expr_list *expr_list); int cfs_expr_list_print(char *buffer, int count, struct cfs_expr_list *expr_list); diff --git a/libcfs/libcfs/util/nidstrings.c b/libcfs/libcfs/util/nidstrings.c index dc996a4..7d13e47 100644 --- a/libcfs/libcfs/util/nidstrings.c +++ b/libcfs/libcfs/util/nidstrings.c @@ -189,6 +189,77 @@ out: return rc; } +int +cfs_expr2str(struct list_head *list, char *str, size_t size) +{ + struct cfs_expr_list *expr; + struct cfs_range_expr *range; + char tmp[LNET_NIDSTR_SIZE]; + size_t len; + bool first; + bool bracket = false; + char *format; + char *tmpc; + + list_for_each_entry(expr, list, el_link) { + first = true; + list_for_each_entry(range, &expr->el_exprs, re_link) { + if (range->re_lo == range->re_hi) { + snprintf(tmp, + LNET_NIDSTR_SIZE, + "%u.", range->re_lo); + } else if (range->re_lo < range->re_hi) { + if (range->re_stride > 1) { + if (first) + format = "[%u-%u/%u,"; + else + format = "%u-%u/%u,"; + snprintf(tmp, LNET_NIDSTR_SIZE, + format, range->re_lo, + range->re_hi, range->re_stride); + bracket = true; + } else { + if (first) + format = "[%u-%u,"; + else + format = "%u-%u,"; + snprintf(tmp, LNET_NIDSTR_SIZE, + format, range->re_lo, + range->re_hi); + bracket = true; + } + } else { + return -EINVAL; + } + len = strlen(tmp); + size -= (len + 1); + if (size < 0) + return -ENOBUFS; + + strncat(str, tmp, size + len); + first = false; + } + if (bracket) { + tmpc = str + (strlen(str) - 1); + size -= 1; + if (size < 0) + return -ENOBUFS; + *tmpc = ']'; + *(tmpc+1) = '.'; + bracket = false; + } + } + + /* + * get rid of the trailing '.' at the end of the string + * only if we actually had something on the list passed in. + * otherwise we could write outside the array + */ + if (!list_empty(list)) + str[strlen(str)-1] = '\0'; + return size; +} + static int libcfs_num_addr_range_expand(struct list_head *addrranges, __u32 *addrs, int max_addrs) diff --git a/lnet/utils/lnetconfig/liblnetconfig.c b/lnet/utils/lnetconfig/liblnetconfig.c index 22bb91a..a4e446a 100644 --- a/lnet/utils/lnetconfig/liblnetconfig.c +++ b/lnet/utils/lnetconfig/liblnetconfig.c @@ -1879,6 +1879,114 @@ get_counts(struct lnet_ioctl_element_msg_stats *msg_stats, int idx) return NULL; } +static int +create_local_udsp_info(struct lnet_ioctl_construct_udsp_info *udsp_info, + struct cYAML *net_node) +{ + char tmp[LNET_MAX_STR_LEN]; + struct cYAML *udsp_net; + bool created = false; + struct cYAML *pref; + int i; + + /* add the UDSP info */ + udsp_net = cYAML_create_object(net_node, "udsp info"); + if (!udsp_net) + return LUSTRE_CFG_RC_OUT_OF_MEM; + + if (!cYAML_create_number(udsp_net, "net priority", + (int) udsp_info->cud_net_priority)) + return LUSTRE_CFG_RC_OUT_OF_MEM; + + if (!cYAML_create_number(udsp_net, "nid priority", + (int)udsp_info->cud_nid_priority)) + return LUSTRE_CFG_RC_OUT_OF_MEM; + + pref = udsp_net; + + for (i = 0; i < LNET_MAX_SHOW_NUM_NID; i++) { + memset(tmp, 0, LNET_MAX_STR_LEN); + if (udsp_info->cud_pref_rtr_nid[i] == 0) + break; + if (!created) { + pref = cYAML_create_object(udsp_net, + "Preferred gateway NIDs"); + if (!pref) + return LUSTRE_CFG_RC_OUT_OF_MEM; + created = true; + } + snprintf(tmp, sizeof(tmp), "NID-%d", i); + if (!cYAML_create_string(pref, tmp, + libcfs_nid2str(udsp_info->cud_pref_rtr_nid[i]))) + return LUSTRE_CFG_RC_OUT_OF_MEM; + } + + return LUSTRE_CFG_RC_NO_ERR; +} + +static int +create_remote_udsp_info(struct lnet_ioctl_construct_udsp_info *udsp_info, + struct cYAML *nid_node) +{ + char tmp[LNET_MAX_STR_LEN]; + struct cYAML *udsp_nid; + bool created = false; + struct cYAML *pref; + int i; + + /* add the UDSP info */ + udsp_nid = cYAML_create_object(nid_node, "udsp info"); + if (!udsp_nid) + return LUSTRE_CFG_RC_OUT_OF_MEM; + + if (!cYAML_create_number(udsp_nid, "net priority", + (int) udsp_info->cud_net_priority)) + return LUSTRE_CFG_RC_OUT_OF_MEM; + + if (!cYAML_create_number(udsp_nid, "nid priority", + (int) udsp_info->cud_nid_priority)) + return LUSTRE_CFG_RC_OUT_OF_MEM; + + pref = udsp_nid; + for (i = 0; i < LNET_MAX_SHOW_NUM_NID; i++) { + memset(tmp, 0, LNET_MAX_STR_LEN); + if (udsp_info->cud_pref_rtr_nid[i] == 0) + break; + if (!created) { + pref = cYAML_create_object(udsp_nid, + "Preferred gateway NIDs"); + if (!pref) + return LUSTRE_CFG_RC_OUT_OF_MEM; + created = true; + } + snprintf(tmp, sizeof(tmp), "NID-%d", i); + if (!cYAML_create_string(pref, tmp, + libcfs_nid2str(udsp_info->cud_pref_rtr_nid[i]))) + return LUSTRE_CFG_RC_OUT_OF_MEM; + } + + pref = udsp_nid; + created = false; + for (i = 0; i < LNET_MAX_SHOW_NUM_NID; i++) { + memset(tmp, 0, LNET_MAX_STR_LEN); + if (udsp_info->cud_pref_nid[i] == 0) + break; + if (!created) { + pref = cYAML_create_object(udsp_nid, + "Preferred source NIDs"); + if (!pref) + return LUSTRE_CFG_RC_OUT_OF_MEM; + created = true; + } + snprintf(tmp, sizeof(tmp), "NID-%d", i); + if (!cYAML_create_string(pref, tmp, + libcfs_nid2str(udsp_info->cud_pref_nid[i]))) + return LUSTRE_CFG_RC_OUT_OF_MEM; + } + + return LUSTRE_CFG_RC_NO_ERR; +} + int lustre_lnet_show_net(char *nw, int detail, int seq_no, struct cYAML **show_rc, struct cYAML **err_rc, bool backup) @@ -1889,6 +1997,7 @@ int lustre_lnet_show_net(char *nw, int detail, int seq_no, struct lnet_ioctl_element_stats *stats; struct lnet_ioctl_element_msg_stats msg_stats; struct lnet_ioctl_local_ni_hstats hstats; + struct lnet_ioctl_construct_udsp_info udsp_info; __u32 net = LNET_NET_ANY; __u32 prev_net = LNET_NET_ANY; int rc = LUSTRE_CFG_RC_OUT_OF_MEM, i, j; @@ -2053,6 +2162,27 @@ int lustre_lnet_show_net(char *nw, int detail, int seq_no, == NULL) goto out; + if (detail < 4) + goto continue_without_udsp_info; + + LIBCFS_IOC_INIT_V2(udsp_info, cud_hdr); + udsp_info.cud_nid = ni_data->lic_nid; + udsp_info.cud_peer = false; + rc = l_ioctl(LNET_DEV_ID, + IOC_LIBCFS_GET_CONST_UDSP_INFO, + &udsp_info); + if (rc != 0) { + l_errno = errno; + goto continue_without_udsp_info; + } + + rc = create_local_udsp_info(&udsp_info, item); + if (rc) { + l_errno = errno; + goto out; + } + +continue_without_udsp_info: if (detail < 2) goto continue_without_msg_stats; @@ -2730,6 +2860,7 @@ int lustre_lnet_show_peer(char *knid, int detail, int seq_no, struct lnet_ioctl_element_stats *lpni_stats; struct lnet_ioctl_element_msg_stats *msg_stats; struct lnet_ioctl_peer_ni_hstats *hstats; + struct lnet_ioctl_construct_udsp_info udsp_info; lnet_nid_t *nidp; int rc = LUSTRE_CFG_RC_OUT_OF_MEM; int i, j, k; @@ -2891,6 +3022,27 @@ int lustre_lnet_show_peer(char *knid, int detail, int seq_no, if (backup) continue; + if (detail < 4) + goto continue_without_udsp_info; + + LIBCFS_IOC_INIT_V2(udsp_info, cud_hdr); + udsp_info.cud_nid = *nidp; + udsp_info.cud_peer = true; + rc = l_ioctl(LNET_DEV_ID, + IOC_LIBCFS_GET_CONST_UDSP_INFO, + &udsp_info); + if (rc != 0) { + l_errno = errno; + goto continue_without_udsp_info; + } + + rc = create_remote_udsp_info(&udsp_info, peer_ni); + if (rc) { + l_errno = errno; + goto out; + } + +continue_without_udsp_info: if (cYAML_create_string(peer_ni, "state", lpni_cri->cr_aliveness) == NULL) @@ -4572,6 +4724,20 @@ static int handle_yaml_config_udsp(struct cYAML *tree, struct cYAML **show_rc, err_rc); } +static int handle_yaml_show_udsp(struct cYAML *tree, struct cYAML **show_rc, + struct cYAML **err_rc) +{ + struct cYAML *seq_no; + struct cYAML *idx; + + seq_no = cYAML_get_object_item(tree, "seq_no"); + idx = cYAML_get_object_item(tree, "idx"); + + return lustre_lnet_show_udsp(idx ? idx->cy_valueint : -1, + seq_no ? seq_no->cy_valueint : -1, + show_rc, err_rc); +} + static int handle_yaml_config_global_settings(struct cYAML *tree, struct cYAML **show_rc, struct cYAML **err_rc) @@ -4864,6 +5030,7 @@ static struct lookup_cmd_hdlr_tbl lookup_show_tbl[] = { { .name = "numa", .cb = handle_yaml_show_numa }, { .name = "ping", .cb = handle_yaml_no_op }, { .name = "discover", .cb = handle_yaml_no_op }, + { .name = "udsp", .cb = handle_yaml_show_udsp }, { .name = NULL } }; static struct lookup_cmd_hdlr_tbl lookup_exec_tbl[] = { diff --git a/lnet/utils/lnetconfig/liblnetconfig.h b/lnet/utils/lnetconfig/liblnetconfig.h index 3f4ab15..3124c74 100644 --- a/lnet/utils/lnetconfig/liblnetconfig.h +++ b/lnet/utils/lnetconfig/liblnetconfig.h @@ -795,4 +795,15 @@ int lustre_lnet_add_udsp(char *src, char *dst, char *rte, char *type, */ int lustre_lnet_del_udsp(unsigned int idx, int seq_no, struct cYAML **err_rc); +/* lustre_lnet_show_udsp + * show selection policy. + * idx - the index to show. -1 to show all policies + * seq_no - sequence number of the request + * err_rc - [IN/OUT] struct cYAML tree containing udsp info + * err_rc - [OUT] struct cYAML tree describing the error. Freed by + * caller + */ +int lustre_lnet_show_udsp(int idx, int seq_no, struct cYAML **show_rc, + struct cYAML **err_rc); + #endif /* LIB_LNET_CONFIG_API_H */ diff --git a/lnet/utils/lnetconfig/liblnetconfig_udsp.c b/lnet/utils/lnetconfig/liblnetconfig_udsp.c index 6193c98..045c056 100644 --- a/lnet/utils/lnetconfig/liblnetconfig_udsp.c +++ b/lnet/utils/lnetconfig/liblnetconfig_udsp.c @@ -614,3 +614,246 @@ int lustre_lnet_del_udsp(unsigned int idx, int seq_no, struct cYAML **err_rc) cYAML_build_error(rc, seq_no, ADD_CMD, "udsp", err_str, err_rc); return rc; } + +int lustre_lnet_nid_descr2str(struct lnet_ud_nid_descr *d, + char *str, size_t size) +{ + int left = size; + int len; + char *net; + bool addr_found = false; + + /* criteria not defined */ + if (d->ud_net_id.udn_net_type == 0) { + strncat(str, "NA", left - 1); + return 0; + } + + left = cfs_expr2str(&d->ud_addr_range, str, left); + if (left < 0) + return left; + net = libcfs_net2str(LNET_MKNET(d->ud_net_id.udn_net_type, 0)); + if (left < size) { + len = strlen(net) + 2; /* account for @ and NULL termination */ + addr_found = true; + } else { + len = strlen(net) + 1; /* account for NULL termination */ + } + + if (left - len < 0) + return -ENOBUFS; + + if (addr_found) { + strncat(str, "@", left); + left -= 1; + } + + strncat(str, net, left); + + left -= strlen(net) + 1; + + left = cfs_expr2str(&d->ud_net_id.udn_net_num_range, str, left); + if (left < 0) + return left; + + return 0; +} + +int yaml_add_udsp_action(struct cYAML *y, struct lnet_udsp *udsp) +{ + struct cYAML *action; + + switch (udsp->udsp_action_type) { + case EN_LNET_UDSP_ACTION_PRIORITY: + action = cYAML_create_object(y, "action"); + if (!action) + return -ENOMEM; + if (!cYAML_create_number(action, "priority", + udsp->udsp_action.udsp_priority)) + return -ENOMEM; + + default: + return 0; + } + + return 0; +} + +int lustre_lnet_show_udsp(int idx, int seq_no, struct cYAML **show_rc, + struct cYAML **err_rc) +{ + struct lnet_ioctl_udsp *data = NULL; + char *ioctl_buf = NULL; + struct lnet_ioctl_udsp get_size; + int rc = LUSTRE_CFG_RC_OUT_OF_MEM, i; + int l_errno = 0; + int use_idx = 0; + struct cYAML *root = NULL, *udsp_node = NULL, + *first_seq = NULL; + struct cYAML *item = NULL; + char err_str[LNET_MAX_STR_LEN]; + char tmp[LNET_MAX_STR_LEN]; + struct lnet_udsp *udsp = NULL; + bool exist = false; + + snprintf(err_str, sizeof(err_str), "\"out of memory\""); + + root = cYAML_create_object(NULL, NULL); + if (!root) + goto out; + + udsp_node = cYAML_create_seq(root, "udsp"); + if (!udsp_node) + goto out; + + for (i = 0;; i++) { + data = NULL; + ioctl_buf = NULL; + udsp = NULL; + + LIBCFS_IOC_INIT_V2(get_size, iou_hdr); + if (idx != -1) + use_idx = idx; + else + use_idx = i; + + get_size.iou_idx = use_idx; + + rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_UDSP_SIZE, &get_size); + if (rc != 0) { + l_errno = errno; + break; + } + + ioctl_buf = calloc(get_size.iou_idx, 1); + if (!ioctl_buf) { + l_errno = errno; + break; + } + + data = (struct lnet_ioctl_udsp *)ioctl_buf; + + LIBCFS_IOC_INIT_V2(*data, iou_hdr); + data->iou_bulk_size = get_size.iou_idx - sizeof(*data); + data->iou_bulk = ioctl_buf + sizeof(*data); + data->iou_idx = use_idx; + + rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_UDSP, ioctl_buf); + if (rc != 0) { + l_errno = errno; + break; + } + + udsp = lnet_udsp_demarshal(ioctl_buf, + data->iou_hdr.ioc_len + data->iou_bulk_size); + if (!udsp) { + l_errno = -EFAULT; + break; + } + + rc = -EINVAL; + exist = true; + + /* create the tree to be printed. */ + item = cYAML_create_seq_item(udsp_node); + if (item == NULL) + goto out; + + if (!first_seq) + first_seq = item; + + if (cYAML_create_number(item, "idx", + udsp->udsp_idx) == NULL) + goto out; + + memset(tmp, 0, LNET_MAX_STR_LEN); + rc = lustre_lnet_nid_descr2str(&udsp->udsp_src, tmp, + LNET_MAX_STR_LEN); + + if (rc) + goto out; + + if (cYAML_create_string(item, "src", tmp) == NULL) + goto out; + memset(tmp, 0, LNET_MAX_STR_LEN); + rc = lustre_lnet_nid_descr2str(&udsp->udsp_dst, tmp, + LNET_MAX_STR_LEN); + + if (rc) + goto out; + + if (cYAML_create_string(item, "dst", tmp) == NULL) + goto out; + + memset(tmp, 0, LNET_MAX_STR_LEN); + rc = lustre_lnet_nid_descr2str(&udsp->udsp_rte, tmp, + LNET_MAX_STR_LEN); + + if (rc) + goto out; + + if (cYAML_create_string(item, "rte", tmp) == NULL) + goto out; + + if (yaml_add_udsp_action(item, udsp)) + goto out; + + if (ioctl_buf) + free(ioctl_buf); + if (udsp) + lnet_udsp_free(udsp, true); + /* did we show the given index? */ + if (idx != -1) + break; + } + + /* 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 udsp: %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 (ioctl_buf) + free(ioctl_buf); + if (udsp) + lnet_udsp_free(udsp, true); + + 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, "udsp"); + if (show_node != NULL && cYAML_is_sequence(show_node)) { + cYAML_insert_child(show_node, first_seq); + free(udsp_node); + free(root); + } else if (show_node == NULL) { + cYAML_insert_sibling((*show_rc)->cy_child, + udsp_node); + free(root); + } else { + cYAML_free_tree(root); + } + } else { + *show_rc = root; + } + + cYAML_build_error(rc, seq_no, SHOW_CMD, "udsp", err_str, err_rc); + + return rc; +} + diff --git a/lnet/utils/lnetctl.c b/lnet/utils/lnetctl.c index 97515e1..13d9d19 100644 --- a/lnet/utils/lnetctl.c +++ b/lnet/utils/lnetctl.c @@ -50,6 +50,7 @@ static int jt_show_stats(int argc, char **argv); static int jt_show_peer(int argc, char **argv); static int jt_show_recovery(int argc, char **argv); static int jt_show_global(int argc, char **argv); +static int jt_show_udsp(int argc, char **argv); static int jt_set_tiny(int argc, char **argv); static int jt_set_small(int argc, char **argv); static int jt_set_large(int argc, char **argv); @@ -273,6 +274,8 @@ command_t udsp_cmds[] = { "\t By default, appends to the end of the rule list.\n"}, {"del", jt_del_udsp, 0, "delete a udsp\n" "\t--idx: index of the Policy.\n"}, + {"show", jt_show_udsp, 0, "show udsps\n" + "\t --idx: index of the policy to show.\n"}, { 0, 0, 0, NULL } }; @@ -1397,6 +1400,48 @@ static int jt_show_stats(int argc, char **argv) return rc; } +static int jt_show_udsp(int argc, char **argv) +{ + int idx = -1; + int rc, opt; + struct cYAML *err_rc = NULL, *show_rc = NULL; + + const char *const short_options = "i:"; + static const struct option long_options[] = { + { .name = "idx", .has_arg = required_argument, .val = 'i' }, + { .name = NULL } + }; + + rc = check_cmd(udsp_cmds, "udsp", "show", 0, argc, argv); + if (rc) + return rc; + + while ((opt = getopt_long(argc, argv, short_options, + long_options, NULL)) != -1) { + switch (opt) { + case 'i': + idx = atoi(optarg); + break; + case '?': + print_help(net_cmds, "net", "show"); + default: + return 0; + } + } + + rc = lustre_lnet_show_udsp(idx, -1, &show_rc, &err_rc); + + if (rc != LUSTRE_CFG_RC_NO_ERR) + cYAML_print_tree2file(stderr, err_rc); + else if (show_rc) + cYAML_print_tree(show_rc); + + cYAML_free_tree(err_rc); + cYAML_free_tree(show_rc); + + return rc; +} + static int jt_show_global(int argc, char **argv) { int rc; @@ -1832,6 +1877,13 @@ static int jt_export(int argc, char **argv) err_rc = NULL; } + rc = lustre_lnet_show_udsp(-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; + } + if (show_rc != NULL) { cYAML_print_tree2file(f, show_rc); cYAML_free_tree(show_rc); -- 1.8.3.1