1 // SPDX-License-Identifier: GPL-2.0
4 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
6 * Copyright (c) 2011, 2017, Intel Corporation.
8 * Copyright (c) 2018-2020 Data Direct Networks.
10 * Copyright (c) 2020, Whamcloud.
14 * This file is part of Lustre, http://www.lustre.org/
16 * Author: Sonia Sharma
27 #include <sys/ioctl.h>
28 #include <libcfs/util/ioctl.h>
29 #include <linux/lnet/lnetctl.h>
31 #include <sys/types.h>
34 #include <linux/lnet/lnet-dlc.h>
35 #include "liblnetconfig.h"
38 lnet_udsp_criteria_present(struct lnet_ud_nid_descr *descr)
40 return descr->ud_net_id.udn_net_type != 0;
43 static struct lnet_udsp *lnet_udsp_alloc(void)
45 struct lnet_udsp *udsp;
47 udsp = calloc(1, sizeof(*udsp));
52 INIT_LIST_HEAD(&udsp->udsp_on_list);
53 INIT_LIST_HEAD(&udsp->udsp_src.ud_addr_range);
54 INIT_LIST_HEAD(&udsp->udsp_src.ud_net_id.udn_net_num_range);
55 INIT_LIST_HEAD(&udsp->udsp_dst.ud_addr_range);
56 INIT_LIST_HEAD(&udsp->udsp_dst.ud_net_id.udn_net_num_range);
57 INIT_LIST_HEAD(&udsp->udsp_rte.ud_addr_range);
58 INIT_LIST_HEAD(&udsp->udsp_rte.ud_net_id.udn_net_num_range);
64 lnet_udsp_nid_descr_free(struct lnet_ud_nid_descr *nid_descr, bool blk)
66 struct list_head *net_range = &nid_descr->ud_net_id.udn_net_num_range;
68 if (!lnet_udsp_criteria_present(nid_descr))
71 /* memory management is a bit tricky here. When we allocate the
72 * memory to store the NID descriptor we allocate a large buffer
73 * for all the data, so we need to free the entire buffer at
74 * once. If the net is present the net_range->next points to that
75 * buffer otherwise if the ud_addr_range is present then it's the
79 if (!list_empty(net_range))
80 free(net_range->next);
81 else if (!list_empty(&nid_descr->ud_addr_range))
82 free(nid_descr->ud_addr_range.next);
84 cfs_expr_list_free_list(net_range);
85 cfs_expr_list_free_list(&nid_descr->ud_addr_range);
90 lnet_udsp_free(struct lnet_udsp *udsp, bool blk)
92 lnet_udsp_nid_descr_free(&udsp->udsp_src, blk);
93 lnet_udsp_nid_descr_free(&udsp->udsp_dst, blk);
94 lnet_udsp_nid_descr_free(&udsp->udsp_rte, blk);
100 copy_range_info(void __user **bulk, void **buf, struct list_head *list,
103 struct lnet_range_expr *range_expr;
104 struct cfs_range_expr *range;
105 struct cfs_expr_list *exprs;
106 int range_count = count;
109 if (range_count == 0)
112 if (range_count == -1) {
113 struct lnet_expressions *e;
116 range_count = e->le_count;
121 INIT_LIST_HEAD(&exprs->el_link);
122 INIT_LIST_HEAD(&exprs->el_exprs);
123 list_add_tail(&exprs->el_link, list);
124 *buf += sizeof(*exprs);
126 for (i = 0; i < range_count; i++) {
129 INIT_LIST_HEAD(&range->re_link);
130 range->re_lo = range_expr->re_lo;
131 range->re_hi = range_expr->re_hi;
132 range->re_stride = range_expr->re_stride;
133 list_add_tail(&range->re_link, &exprs->el_exprs);
134 *bulk += sizeof(*range_expr);
135 *buf += sizeof(*range);
140 copy_ioc_udsp_descr(struct lnet_ud_nid_descr *nid_descr, char *type,
141 void **bulk, __u32 *bulk_size)
143 struct lnet_ioctl_udsp_descr *ioc_nid = *bulk;
144 struct lnet_expressions *exprs;
150 int remaining_size = *bulk_size;
154 size_t range_expr_s = sizeof(struct lnet_range_expr);
155 size_t lnet_exprs_s = sizeof(struct lnet_expressions);
157 /* criteria not present, skip over the static part of the
158 * bulk, which is included for each NID descriptor
160 if (ioc_nid->iud_net.ud_net_type == 0) {
161 remaining_size -= sizeof(*ioc_nid);
162 if (remaining_size < 0)
164 *bulk += sizeof(*ioc_nid);
165 *bulk_size = remaining_size;
169 descr_type = ioc_nid->iud_src_hdr.ud_descr_type;
170 if (descr_type != *(__u32 *)type)
173 /* calculate the total size to verify we have enough buffer.
174 * Start of by finding how many ranges there are for the net
177 range_count = ioc_nid->iud_net.ud_net_num_expr.le_count;
178 size = sizeof(*ioc_nid) + (range_count * range_expr_s);
179 remaining_size -= size;
180 if (remaining_size < 0)
183 /* the number of expressions for the NID. IE 4 for IP, 1 for GNI */
184 expr_count = ioc_nid->iud_src_hdr.ud_descr_count;
185 /* point tmp to the beginning of the NID expressions */
187 for (i = 0; i < expr_count; i++) {
188 /* get the number of ranges per expression */
190 range_count += exprs->le_count;
191 size = (range_expr_s * exprs->le_count) + lnet_exprs_s;
192 remaining_size -= size;
193 if (remaining_size < 0)
198 *bulk_size = remaining_size;
200 /* copy over the net type */
201 nid_descr->ud_net_id.udn_net_type = ioc_nid->iud_net.ud_net_type;
203 /* allocate the total memory required to copy this NID descriptor */
204 alloc_size = (sizeof(struct cfs_expr_list) * (expr_count + 1)) +
205 (sizeof(struct cfs_range_expr) * (range_count));
206 buf = calloc(alloc_size, 1);
210 /* copy over the net number range */
211 range_count = ioc_nid->iud_net.ud_net_num_expr.le_count;
212 *bulk += sizeof(*ioc_nid);
213 copy_range_info(bulk, &buf, &nid_descr->ud_net_id.udn_net_num_range,
216 /* copy over the NID descriptor */
217 for (i = 0; i < expr_count; i++)
218 copy_range_info(bulk, &buf, &nid_descr->ud_addr_range, -1);
223 static struct lnet_udsp *
224 lnet_udsp_demarshal(void *bulk, __u32 bulk_size)
226 struct lnet_ioctl_udsp *ioc_udsp;
227 struct lnet_udsp *udsp;
230 if (bulk_size < sizeof(*ioc_udsp))
233 udsp = lnet_udsp_alloc();
239 udsp->udsp_action_type = ioc_udsp->iou_action_type;
240 udsp->udsp_action.udsp_priority = ioc_udsp->iou_action.priority;
241 udsp->udsp_idx = ioc_udsp->iou_idx;
243 bulk = ioc_udsp->iou_bulk;
244 bulk_size -= sizeof(*ioc_udsp);
246 if (bulk_size != ioc_udsp->iou_bulk_size)
249 rc = copy_ioc_udsp_descr(&udsp->udsp_src, "SRC", &bulk, &bulk_size);
253 rc = copy_ioc_udsp_descr(&udsp->udsp_dst, "DST", &bulk, &bulk_size);
257 rc = copy_ioc_udsp_descr(&udsp->udsp_rte, "RTE", &bulk, &bulk_size);
264 lnet_udsp_free(udsp, true);
269 lnet_get_list_len(struct list_head *list)
274 list_for_each(l, list)
281 lnet_size_marshaled_nid_descr(struct lnet_ud_nid_descr *descr)
283 struct cfs_expr_list *expr;
286 size_t size = sizeof(struct lnet_ioctl_udsp_descr);
288 if (!lnet_udsp_criteria_present(descr))
291 if (!list_empty(&descr->ud_net_id.udn_net_num_range)) {
292 expr = list_first_entry(&descr->ud_net_id.udn_net_num_range,
293 struct cfs_expr_list, el_link);
294 range_count = lnet_get_list_len(&expr->el_exprs);
297 /* count the number of cfs_range_expr in the address expressions */
298 list_for_each_entry(expr, &descr->ud_addr_range, el_link) {
300 range_count += lnet_get_list_len(&expr->el_exprs);
303 size += (sizeof(struct lnet_expressions) * expr_count);
304 size += (sizeof(struct lnet_range_expr) * range_count);
310 lnet_get_udsp_size(struct lnet_udsp *udsp)
312 size_t size = sizeof(struct lnet_ioctl_udsp);
314 size += lnet_size_marshaled_nid_descr(&udsp->udsp_src);
315 size += lnet_size_marshaled_nid_descr(&udsp->udsp_dst);
316 size += lnet_size_marshaled_nid_descr(&udsp->udsp_rte);
322 copy_exprs(struct cfs_expr_list *expr, void __user **bulk,
325 struct cfs_range_expr *range;
326 struct lnet_range_expr range_expr;
328 /* copy over the net range expressions to the bulk */
329 list_for_each_entry(range, &expr->el_exprs, re_link) {
330 range_expr.re_lo = range->re_lo;
331 range_expr.re_hi = range->re_hi;
332 range_expr.re_stride = range->re_stride;
333 memcpy(*bulk, &range_expr, sizeof(range_expr));
334 *bulk += sizeof(range_expr);
335 *bulk_size -= sizeof(range_expr);
340 copy_nid_range(struct lnet_ud_nid_descr *nid_descr, char *type,
341 void __user **bulk, __s32 *bulk_size)
343 struct lnet_ioctl_udsp_descr ioc_udsp_descr = { { 0 } };
344 struct cfs_expr_list *expr;
345 struct lnet_expressions ioc_expr;
347 int net_expr_count = 0;
349 ioc_udsp_descr.iud_src_hdr.ud_descr_type = *(__u32 *)type;
351 /* if criteria not present, copy over the static part of the NID
354 if (!lnet_udsp_criteria_present(nid_descr)) {
355 memcpy(*bulk, &ioc_udsp_descr,
356 sizeof(ioc_udsp_descr));
357 *bulk += sizeof(ioc_udsp_descr);
358 *bulk_size -= sizeof(ioc_udsp_descr);
362 expr_count = lnet_get_list_len(&nid_descr->ud_addr_range);
364 /* copy the net information */
365 if (!list_empty(&nid_descr->ud_net_id.udn_net_num_range)) {
366 expr = list_first_entry(&nid_descr->ud_net_id.udn_net_num_range,
367 struct cfs_expr_list, el_link);
368 net_expr_count = lnet_get_list_len(&expr->el_exprs);
373 /* set the total expression count */
374 ioc_udsp_descr.iud_src_hdr.ud_descr_count = expr_count;
375 ioc_udsp_descr.iud_net.ud_net_type =
376 nid_descr->ud_net_id.udn_net_type;
377 ioc_udsp_descr.iud_net.ud_net_num_expr.le_count = net_expr_count;
379 /* copy over the header info to the bulk */
380 memcpy(*bulk, &ioc_udsp_descr, sizeof(ioc_udsp_descr));
381 *bulk += sizeof(ioc_udsp_descr);
382 *bulk_size -= sizeof(ioc_udsp_descr);
384 /* copy over the net num expression if it exists */
386 copy_exprs(expr, bulk, bulk_size);
388 /* copy the address range */
389 list_for_each_entry(expr, &nid_descr->ud_addr_range, el_link) {
390 ioc_expr.le_count = lnet_get_list_len(&expr->el_exprs);
391 memcpy(*bulk, &ioc_expr, sizeof(ioc_expr));
392 *bulk += sizeof(ioc_expr);
393 *bulk_size -= sizeof(ioc_expr);
395 copy_exprs(expr, bulk, bulk_size);
402 lnet_udsp_marshal(struct lnet_udsp *udsp, void *bulk,
405 struct lnet_ioctl_udsp *ioc_udsp;
408 /* make sure user space allocated enough buffer to marshal the
411 if (bulk_size < lnet_get_udsp_size(udsp))
416 ioc_udsp->iou_idx = udsp->udsp_idx;
417 ioc_udsp->iou_action_type = udsp->udsp_action_type;
418 ioc_udsp->iou_action.priority = udsp->udsp_action.udsp_priority;
420 bulk += sizeof(*ioc_udsp);
421 bulk_size -= sizeof(*ioc_udsp);
423 rc = copy_nid_range(&udsp->udsp_src, "SRC", &bulk, &bulk_size);
427 rc = copy_nid_range(&udsp->udsp_dst, "DST", &bulk, &bulk_size);
431 rc = copy_nid_range(&udsp->udsp_rte, "RTE", &bulk, &bulk_size);
436 static enum lnet_udsp_action_type
437 lnet_str2udsp_action(char *type)
440 return EN_LNET_UDSP_ACTION_NONE;
442 if (!strncmp(type, "priority", strlen("priority")))
443 return EN_LNET_UDSP_ACTION_PRIORITY;
445 if (!strncmp(type, "pref", strlen("pref")))
446 return EN_LNET_UDSP_ACTION_PREFERRED_LIST;
448 return EN_LNET_UDSP_ACTION_NONE;
451 int lustre_lnet_add_udsp(char *src, char *dst, char *rte,
452 char *type, union lnet_udsp_action *action,
453 int idx, int seq_no, struct cYAML **err_rc)
455 struct lnet_udsp *udsp = NULL;
456 struct lnet_ioctl_udsp *udsp_bulk;
457 int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
460 char err_str[LNET_MAX_STR_LEN];
461 enum lnet_udsp_action_type action_type;
463 snprintf(err_str, sizeof(err_str), "\"success\"");
465 action_type = lnet_str2udsp_action(type);
466 if (action_type == EN_LNET_UDSP_ACTION_NONE) {
467 snprintf(err_str, sizeof(err_str),
468 "\"bad action type specified: %s\"", type);
469 rc = LUSTRE_CFG_RC_BAD_PARAM;
473 if (!(src || rte || dst)) {
474 snprintf(err_str, sizeof(err_str),
475 "\"Missing required argument(s)\"");
476 rc = LUSTRE_CFG_RC_BAD_PARAM;
480 /* sanitize parameters:
481 * src-dst can be simultaneously present
482 * dst-rte can be simultaneously present
484 if (src && rte && dst) {
485 snprintf(err_str, sizeof(err_str),
486 "\"The combination of src, dst and rte is not supported\"");
487 rc = LUSTRE_CFG_RC_BAD_PARAM;
492 snprintf(err_str, sizeof(err_str),
493 "\"src and rte cannot be combined\"");
494 rc = LUSTRE_CFG_RC_BAD_PARAM;
498 udsp = lnet_udsp_alloc();
500 snprintf(err_str, sizeof(err_str), "\"out of memory\"");
504 udsp->udsp_idx = idx;
505 udsp->udsp_action_type = action_type;
507 /* a priority of -1 will result in the lowest possible priority */
508 if (action_type == EN_LNET_UDSP_ACTION_PRIORITY)
509 udsp->udsp_action.udsp_priority = action->udsp_priority;
511 /* override with the default
512 * if priority is expected, but not specified
514 if (!rte && ((dst && !src) || (src && !dst)) &&
515 action_type != EN_LNET_UDSP_ACTION_PRIORITY) {
516 udsp->udsp_action_type = EN_LNET_UDSP_ACTION_PRIORITY;
517 udsp->udsp_action.udsp_priority = 0;
521 rc = cfs_parse_nid_parts(src, &udsp->udsp_src.ud_addr_range,
522 &udsp->udsp_src.ud_net_id.udn_net_num_range,
523 &udsp->udsp_src.ud_net_id.udn_net_type);
527 "\"failed to parse src parameter\"");
532 rc = cfs_parse_nid_parts(dst, &udsp->udsp_dst.ud_addr_range,
533 &udsp->udsp_dst.ud_net_id.udn_net_num_range,
534 &udsp->udsp_dst.ud_net_id.udn_net_type);
538 "\"failed to parse dst parameter\"");
543 rc = cfs_parse_nid_parts(rte, &udsp->udsp_rte.ud_addr_range,
544 &udsp->udsp_rte.ud_net_id.udn_net_num_range,
545 &udsp->udsp_rte.ud_net_id.udn_net_type);
549 "\"failed to parse rte parameter\"");
554 bulk_size = lnet_get_udsp_size(udsp);
555 bulk = calloc(1, bulk_size);
557 rc = LUSTRE_CFG_RC_OUT_OF_MEM;
558 snprintf(err_str, sizeof(err_str), "\"out of memory\"");
563 LIBCFS_IOC_INIT_V2(*udsp_bulk, iou_hdr);
564 udsp_bulk->iou_hdr.ioc_len = bulk_size;
565 udsp_bulk->iou_bulk_size = bulk_size - sizeof(*udsp_bulk);
567 rc = lnet_udsp_marshal(udsp, bulk, bulk_size);
568 if (rc != LUSTRE_CFG_RC_NO_ERR) {
569 rc = LUSTRE_CFG_RC_MARSHAL_FAIL;
572 "\"failed to marshal udsp\"");
576 udsp_bulk->iou_bulk = bulk + sizeof(*udsp_bulk);
578 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_UDSP, bulk);
581 snprintf(err_str, sizeof(err_str),
582 "\"cannot add udsp: %s\"", strerror(errno));
586 rc = LUSTRE_CFG_RC_NO_ERR;
592 lnet_udsp_free(udsp, false);
593 cYAML_build_error(rc, seq_no, ADD_CMD, "udsp", err_str, err_rc);
597 int lustre_lnet_del_udsp(unsigned int idx, int seq_no, struct cYAML **err_rc)
600 char err_str[LNET_MAX_STR_LEN];
601 struct lnet_ioctl_udsp udsp_bulk;
603 snprintf(err_str, sizeof(err_str), "\"success\"");
605 LIBCFS_IOC_INIT_V2(udsp_bulk, iou_hdr);
606 udsp_bulk.iou_idx = idx;
608 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DEL_UDSP, &udsp_bulk);
610 snprintf(err_str, sizeof(err_str),
611 "\"cannot del udsp: %s\"", strerror(errno));
613 cYAML_build_error(rc, seq_no, ADD_CMD, "udsp", err_str, err_rc);
617 static int lustre_lnet_nid_descr2str(struct lnet_ud_nid_descr *d,
618 char *str, size_t size)
623 bool addr_found = false;
625 /* criteria not defined */
626 if (d->ud_net_id.udn_net_type == 0) {
627 strncat(str, "NA", left - 1);
631 left = cfs_expr2str(&d->ud_addr_range, str, left);
634 net = libcfs_net2str(LNET_MKNET(d->ud_net_id.udn_net_type, 0));
636 len = strlen(net) + 2; /* account for @ and NULL termination */
639 len = strlen(net) + 1; /* account for NULL termination */
646 strncat(str, "@", left);
650 strncat(str, net, left);
652 left -= strlen(net) + 1;
654 left = cfs_expr2str(&d->ud_net_id.udn_net_num_range, str, left);
661 static int yaml_add_udsp_action(struct cYAML *y, struct lnet_udsp *udsp)
663 struct cYAML *action;
665 switch (udsp->udsp_action_type) {
666 case EN_LNET_UDSP_ACTION_PRIORITY:
667 action = cYAML_create_object(y, "action");
670 if (!cYAML_create_number(action, "priority",
671 udsp->udsp_action.udsp_priority))
681 int lustre_lnet_show_udsp(int idx, int seq_no, struct cYAML **show_rc,
682 struct cYAML **err_rc)
684 struct lnet_ioctl_udsp *data = NULL;
685 char *ioctl_buf = NULL;
686 struct lnet_ioctl_udsp get_size;
687 int rc = LUSTRE_CFG_RC_OUT_OF_MEM, i;
690 struct cYAML *root = NULL, *udsp_node = NULL,
692 struct cYAML *item = NULL;
693 char err_str[LNET_MAX_STR_LEN];
694 char tmp[LNET_MAX_STR_LEN];
695 struct lnet_udsp *udsp = NULL;
698 snprintf(err_str, sizeof(err_str), "\"out of memory\"");
700 root = cYAML_create_object(NULL, NULL);
704 udsp_node = cYAML_create_seq(root, "udsp");
713 LIBCFS_IOC_INIT_V2(get_size, iou_hdr);
719 get_size.iou_idx = use_idx;
721 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_UDSP_SIZE, &get_size);
727 ioctl_buf = calloc(get_size.iou_idx, 1);
733 data = (struct lnet_ioctl_udsp *)ioctl_buf;
735 LIBCFS_IOC_INIT_V2(*data, iou_hdr);
736 data->iou_bulk_size = get_size.iou_idx - sizeof(*data);
737 data->iou_bulk = ioctl_buf + sizeof(*data);
738 data->iou_idx = use_idx;
740 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_UDSP, ioctl_buf);
746 udsp = lnet_udsp_demarshal(ioctl_buf,
747 data->iou_hdr.ioc_len + data->iou_bulk_size);
756 /* create the tree to be printed. */
757 item = cYAML_create_seq_item(udsp_node);
764 if (cYAML_create_number(item, "idx",
765 udsp->udsp_idx) == NULL)
768 memset(tmp, 0, LNET_MAX_STR_LEN);
769 rc = lustre_lnet_nid_descr2str(&udsp->udsp_src, tmp,
775 if (cYAML_create_string(item, "src", tmp) == NULL)
777 memset(tmp, 0, LNET_MAX_STR_LEN);
778 rc = lustre_lnet_nid_descr2str(&udsp->udsp_dst, tmp,
784 if (cYAML_create_string(item, "dst", tmp) == NULL)
787 memset(tmp, 0, LNET_MAX_STR_LEN);
788 rc = lustre_lnet_nid_descr2str(&udsp->udsp_rte, tmp,
794 if (cYAML_create_string(item, "rte", tmp) == NULL)
797 if (yaml_add_udsp_action(item, udsp))
803 lnet_udsp_free(udsp, true);
804 /* did we show the given index? */
809 /* Print out the net information only if show_rc is not provided */
811 cYAML_print_tree(root);
813 if (l_errno != ENOENT) {
816 "\"cannot get udsp: %s\"",
821 rc = LUSTRE_CFG_RC_NO_ERR;
824 snprintf(err_str, sizeof(err_str), "\"success\"");
829 lnet_udsp_free(udsp, true);
831 if (show_rc == NULL || rc != LUSTRE_CFG_RC_NO_ERR || !exist) {
832 cYAML_free_tree(root);
833 } else if (show_rc != NULL && *show_rc != NULL) {
834 struct cYAML *show_node;
835 /* find the net node, if one doesn't exist
836 * then insert one. Otherwise add to the one there
838 show_node = cYAML_get_object_item(*show_rc, "udsp");
839 if (show_node != NULL && cYAML_is_sequence(show_node)) {
840 cYAML_insert_child(show_node, first_seq);
843 } else if (show_node == NULL) {
844 cYAML_insert_sibling((*show_rc)->cy_child,
848 cYAML_free_tree(root);
854 cYAML_build_error(rc, seq_no, SHOW_CMD, "udsp", err_str, err_rc);