2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
4 * Copyright (c) 2011, 2017, Intel Corporation.
6 * Copyright (c) 2018-2020 Data Direct Networks.
8 * This file is part of Lustre, https://wiki.whamcloud.com/
10 * Portals is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU General Public
12 * License as published by the Free Software Foundation.
14 * Portals is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * version 2 along with this program; If not, see
21 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Author: Sonia Sharma
26 * Copyright (c) 2020, Whamcloud.
38 #include <sys/ioctl.h>
39 #include <libcfs/util/ioctl.h>
40 #include <linux/lnet/lnetctl.h>
42 #include <sys/types.h>
45 #include <linux/lnet/lnet-dlc.h>
46 #include "liblnetconfig.h"
49 lnet_udsp_criteria_present(struct lnet_ud_nid_descr *descr)
51 return descr->ud_net_id.udn_net_type != 0;
54 struct lnet_udsp *lnet_udsp_alloc(void)
56 struct lnet_udsp *udsp;
58 udsp = calloc(1, sizeof(*udsp));
63 INIT_LIST_HEAD(&udsp->udsp_on_list);
64 INIT_LIST_HEAD(&udsp->udsp_src.ud_addr_range);
65 INIT_LIST_HEAD(&udsp->udsp_src.ud_net_id.udn_net_num_range);
66 INIT_LIST_HEAD(&udsp->udsp_dst.ud_addr_range);
67 INIT_LIST_HEAD(&udsp->udsp_dst.ud_net_id.udn_net_num_range);
68 INIT_LIST_HEAD(&udsp->udsp_rte.ud_addr_range);
69 INIT_LIST_HEAD(&udsp->udsp_rte.ud_net_id.udn_net_num_range);
75 lnet_udsp_nid_descr_free(struct lnet_ud_nid_descr *nid_descr, bool blk)
77 struct list_head *net_range = &nid_descr->ud_net_id.udn_net_num_range;
79 if (!lnet_udsp_criteria_present(nid_descr))
82 /* memory management is a bit tricky here. When we allocate the
83 * memory to store the NID descriptor we allocate a large buffer
84 * for all the data, so we need to free the entire buffer at
85 * once. If the net is present the net_range->next points to that
86 * buffer otherwise if the ud_addr_range is present then it's the
90 if (!list_empty(net_range))
91 free(net_range->next);
92 else if (!list_empty(&nid_descr->ud_addr_range))
93 free(nid_descr->ud_addr_range.next);
95 cfs_expr_list_free_list(net_range);
96 cfs_expr_list_free_list(&nid_descr->ud_addr_range);
101 lnet_udsp_free(struct lnet_udsp *udsp, bool blk)
103 lnet_udsp_nid_descr_free(&udsp->udsp_src, blk);
104 lnet_udsp_nid_descr_free(&udsp->udsp_dst, blk);
105 lnet_udsp_nid_descr_free(&udsp->udsp_rte, blk);
111 copy_range_info(void __user **bulk, void **buf, struct list_head *list,
114 struct lnet_range_expr *range_expr;
115 struct cfs_range_expr *range;
116 struct cfs_expr_list *exprs;
117 int range_count = count;
120 if (range_count == 0)
123 if (range_count == -1) {
124 struct lnet_expressions *e;
127 range_count = e->le_count;
132 INIT_LIST_HEAD(&exprs->el_link);
133 INIT_LIST_HEAD(&exprs->el_exprs);
134 list_add_tail(&exprs->el_link, list);
135 *buf += sizeof(*exprs);
137 for (i = 0; i < range_count; i++) {
140 INIT_LIST_HEAD(&range->re_link);
141 range->re_lo = range_expr->re_lo;
142 range->re_hi = range_expr->re_hi;
143 range->re_stride = range_expr->re_stride;
144 list_add_tail(&range->re_link, &exprs->el_exprs);
145 *bulk += sizeof(*range_expr);
146 *buf += sizeof(*range);
151 copy_ioc_udsp_descr(struct lnet_ud_nid_descr *nid_descr, char *type,
152 void **bulk, __u32 *bulk_size)
154 struct lnet_ioctl_udsp_descr *ioc_nid = *bulk;
155 struct lnet_expressions *exprs;
161 int remaining_size = *bulk_size;
165 size_t range_expr_s = sizeof(struct lnet_range_expr);
166 size_t lnet_exprs_s = sizeof(struct lnet_expressions);
168 /* criteria not present, skip over the static part of the
169 * bulk, which is included for each NID descriptor
171 if (ioc_nid->iud_net.ud_net_type == 0) {
172 remaining_size -= sizeof(*ioc_nid);
173 if (remaining_size < 0)
175 *bulk += sizeof(*ioc_nid);
176 *bulk_size = remaining_size;
180 descr_type = ioc_nid->iud_src_hdr.ud_descr_type;
181 if (descr_type != *(__u32 *)type)
184 /* calculate the total size to verify we have enough buffer.
185 * Start of by finding how many ranges there are for the net
188 range_count = ioc_nid->iud_net.ud_net_num_expr.le_count;
189 size = sizeof(*ioc_nid) + (range_count * range_expr_s);
190 remaining_size -= size;
191 if (remaining_size < 0)
194 /* the number of expressions for the NID. IE 4 for IP, 1 for GNI */
195 expr_count = ioc_nid->iud_src_hdr.ud_descr_count;
196 /* point tmp to the beginning of the NID expressions */
198 for (i = 0; i < expr_count; i++) {
199 /* get the number of ranges per expression */
201 range_count += exprs->le_count;
202 size = (range_expr_s * exprs->le_count) + lnet_exprs_s;
203 remaining_size -= size;
204 if (remaining_size < 0)
209 *bulk_size = remaining_size;
211 /* copy over the net type */
212 nid_descr->ud_net_id.udn_net_type = ioc_nid->iud_net.ud_net_type;
214 /* allocate the total memory required to copy this NID descriptor */
215 alloc_size = (sizeof(struct cfs_expr_list) * (expr_count + 1)) +
216 (sizeof(struct cfs_range_expr) * (range_count));
217 buf = calloc(alloc_size, 1);
221 /* copy over the net number range */
222 range_count = ioc_nid->iud_net.ud_net_num_expr.le_count;
223 *bulk += sizeof(*ioc_nid);
224 copy_range_info(bulk, &buf, &nid_descr->ud_net_id.udn_net_num_range,
227 /* copy over the NID descriptor */
228 for (i = 0; i < expr_count; i++)
229 copy_range_info(bulk, &buf, &nid_descr->ud_addr_range, -1);
235 lnet_udsp_demarshal(void *bulk, __u32 bulk_size)
237 struct lnet_ioctl_udsp *ioc_udsp;
238 struct lnet_udsp *udsp;
241 if (bulk_size < sizeof(*ioc_udsp))
244 udsp = lnet_udsp_alloc();
250 udsp->udsp_action_type = ioc_udsp->iou_action_type;
251 udsp->udsp_action.udsp_priority = ioc_udsp->iou_action.priority;
252 udsp->udsp_idx = ioc_udsp->iou_idx;
254 bulk = ioc_udsp->iou_bulk;
255 bulk_size -= sizeof(*ioc_udsp);
257 if (bulk_size != ioc_udsp->iou_bulk_size)
260 rc = copy_ioc_udsp_descr(&udsp->udsp_src, "SRC", &bulk, &bulk_size);
264 rc = copy_ioc_udsp_descr(&udsp->udsp_dst, "DST", &bulk, &bulk_size);
268 rc = copy_ioc_udsp_descr(&udsp->udsp_rte, "RTE", &bulk, &bulk_size);
275 lnet_udsp_free(udsp, true);
280 lnet_get_list_len(struct list_head *list)
285 list_for_each(l, list)
292 lnet_size_marshaled_nid_descr(struct lnet_ud_nid_descr *descr)
294 struct cfs_expr_list *expr;
297 size_t size = sizeof(struct lnet_ioctl_udsp_descr);
299 if (!lnet_udsp_criteria_present(descr))
302 if (!list_empty(&descr->ud_net_id.udn_net_num_range)) {
303 expr = list_entry(descr->ud_net_id.udn_net_num_range.next,
304 struct cfs_expr_list, el_link);
305 range_count = lnet_get_list_len(&expr->el_exprs);
308 /* count the number of cfs_range_expr in the address expressions */
309 list_for_each_entry(expr, &descr->ud_addr_range, el_link) {
311 range_count += lnet_get_list_len(&expr->el_exprs);
314 size += (sizeof(struct lnet_expressions) * expr_count);
315 size += (sizeof(struct lnet_range_expr) * range_count);
321 lnet_get_udsp_size(struct lnet_udsp *udsp)
323 size_t size = sizeof(struct lnet_ioctl_udsp);
325 size += lnet_size_marshaled_nid_descr(&udsp->udsp_src);
326 size += lnet_size_marshaled_nid_descr(&udsp->udsp_dst);
327 size += lnet_size_marshaled_nid_descr(&udsp->udsp_rte);
333 copy_exprs(struct cfs_expr_list *expr, void __user **bulk,
336 struct cfs_range_expr *range;
337 struct lnet_range_expr range_expr;
339 /* copy over the net range expressions to the bulk */
340 list_for_each_entry(range, &expr->el_exprs, re_link) {
341 range_expr.re_lo = range->re_lo;
342 range_expr.re_hi = range->re_hi;
343 range_expr.re_stride = range->re_stride;
344 memcpy(*bulk, &range_expr, sizeof(range_expr));
345 *bulk += sizeof(range_expr);
346 *bulk_size -= sizeof(range_expr);
351 copy_nid_range(struct lnet_ud_nid_descr *nid_descr, char *type,
352 void __user **bulk, __s32 *bulk_size)
354 struct lnet_ioctl_udsp_descr ioc_udsp_descr = { { 0 } };
355 struct cfs_expr_list *expr;
356 struct lnet_expressions ioc_expr;
358 int net_expr_count = 0;
360 ioc_udsp_descr.iud_src_hdr.ud_descr_type = *(__u32 *)type;
362 /* if criteria not present, copy over the static part of the NID
365 if (!lnet_udsp_criteria_present(nid_descr)) {
366 memcpy(*bulk, &ioc_udsp_descr,
367 sizeof(ioc_udsp_descr));
368 *bulk += sizeof(ioc_udsp_descr);
369 *bulk_size -= sizeof(ioc_udsp_descr);
373 expr_count = lnet_get_list_len(&nid_descr->ud_addr_range);
375 /* copy the net information */
376 if (!list_empty(&nid_descr->ud_net_id.udn_net_num_range)) {
377 expr = list_entry(nid_descr->ud_net_id.udn_net_num_range.next,
378 struct cfs_expr_list, el_link);
379 net_expr_count = lnet_get_list_len(&expr->el_exprs);
384 /* set the total expression count */
385 ioc_udsp_descr.iud_src_hdr.ud_descr_count = expr_count;
386 ioc_udsp_descr.iud_net.ud_net_type =
387 nid_descr->ud_net_id.udn_net_type;
388 ioc_udsp_descr.iud_net.ud_net_num_expr.le_count = net_expr_count;
390 /* copy over the header info to the bulk */
391 memcpy(*bulk, &ioc_udsp_descr, sizeof(ioc_udsp_descr));
392 *bulk += sizeof(ioc_udsp_descr);
393 *bulk_size -= sizeof(ioc_udsp_descr);
395 /* copy over the net num expression if it exists */
397 copy_exprs(expr, bulk, bulk_size);
399 /* copy the address range */
400 list_for_each_entry(expr, &nid_descr->ud_addr_range, el_link) {
401 ioc_expr.le_count = lnet_get_list_len(&expr->el_exprs);
402 memcpy(*bulk, &ioc_expr, sizeof(ioc_expr));
403 *bulk += sizeof(ioc_expr);
404 *bulk_size -= sizeof(ioc_expr);
406 copy_exprs(expr, bulk, bulk_size);
413 lnet_udsp_marshal(struct lnet_udsp *udsp, void *bulk,
416 struct lnet_ioctl_udsp *ioc_udsp;
419 /* make sure user space allocated enough buffer to marshal the
422 if (bulk_size < lnet_get_udsp_size(udsp))
427 ioc_udsp->iou_idx = udsp->udsp_idx;
428 ioc_udsp->iou_action_type = udsp->udsp_action_type;
429 ioc_udsp->iou_action.priority = udsp->udsp_action.udsp_priority;
431 bulk += sizeof(*ioc_udsp);
432 bulk_size -= sizeof(*ioc_udsp);
434 rc = copy_nid_range(&udsp->udsp_src, "SRC", &bulk, &bulk_size);
438 rc = copy_nid_range(&udsp->udsp_dst, "DST", &bulk, &bulk_size);
442 rc = copy_nid_range(&udsp->udsp_rte, "RTE", &bulk, &bulk_size);
447 static enum lnet_udsp_action_type
448 lnet_str2udsp_action(char *type)
451 return EN_LNET_UDSP_ACTION_NONE;
453 if (!strncmp(type, "priority", strlen("priority")))
454 return EN_LNET_UDSP_ACTION_PRIORITY;
456 if (!strncmp(type, "pref", strlen("pref")))
457 return EN_LNET_UDSP_ACTION_PREFERRED_LIST;
459 return EN_LNET_UDSP_ACTION_NONE;
462 int lustre_lnet_add_udsp(char *src, char *dst, char *rte,
463 char *type, union lnet_udsp_action *action,
464 int idx, int seq_no, struct cYAML **err_rc)
466 struct lnet_udsp *udsp = NULL;
467 struct lnet_ioctl_udsp *udsp_bulk;
468 int rc = LUSTRE_CFG_RC_OUT_OF_MEM;
471 char err_str[LNET_MAX_STR_LEN];
472 enum lnet_udsp_action_type action_type;
474 snprintf(err_str, sizeof(err_str), "\"success\"");
476 action_type = lnet_str2udsp_action(type);
477 if (action_type == EN_LNET_UDSP_ACTION_NONE) {
478 snprintf(err_str, sizeof(err_str),
479 "\"bad action type specified: %s\"", type);
480 rc = LUSTRE_CFG_RC_BAD_PARAM;
484 /* sanitize parameters:
485 * src-dst can be simultaneously present
486 * dst-rte can be simultaneously present
488 if ((!src && !rte && !dst) ||
489 (src && rte && dst) ||
490 (src && rte && !dst)) {
491 snprintf(err_str, sizeof(err_str),
492 "\"The combination of src, dst and rte is not supported\"");
493 rc = LUSTRE_CFG_RC_BAD_PARAM;
497 udsp = lnet_udsp_alloc();
499 snprintf(err_str, sizeof(err_str), "\"out of memory\"");
503 udsp->udsp_idx = idx;
504 udsp->udsp_action_type = action_type;
506 /* a priority of -1 will result in the lowest possible priority */
507 if (action_type == EN_LNET_UDSP_ACTION_PRIORITY)
508 udsp->udsp_action.udsp_priority = action->udsp_priority;
510 /* override with the default
511 * if priority is expected, but not specified
513 if (!rte && ((dst && !src) || (src && !dst)) &&
514 action_type != EN_LNET_UDSP_ACTION_PRIORITY) {
515 udsp->udsp_action_type = EN_LNET_UDSP_ACTION_PRIORITY;
516 udsp->udsp_action.udsp_priority = 0;
520 rc = cfs_parse_nid_parts(src, &udsp->udsp_src.ud_addr_range,
521 &udsp->udsp_src.ud_net_id.udn_net_num_range,
522 &udsp->udsp_src.ud_net_id.udn_net_type);
526 "\failed to parse src parameter\"");
531 rc = cfs_parse_nid_parts(dst, &udsp->udsp_dst.ud_addr_range,
532 &udsp->udsp_dst.ud_net_id.udn_net_num_range,
533 &udsp->udsp_dst.ud_net_id.udn_net_type);
537 "\failed to parse dst parameter\"");
542 rc = cfs_parse_nid_parts(rte, &udsp->udsp_rte.ud_addr_range,
543 &udsp->udsp_rte.ud_net_id.udn_net_num_range,
544 &udsp->udsp_rte.ud_net_id.udn_net_type);
548 "\failed to parse rte parameter\"");
553 bulk_size = lnet_get_udsp_size(udsp);
554 bulk = calloc(1, bulk_size);
556 rc = LUSTRE_CFG_RC_OUT_OF_MEM;
557 snprintf(err_str, sizeof(err_str), "\"out of memory\"");
562 LIBCFS_IOC_INIT_V2(*udsp_bulk, iou_hdr);
563 udsp_bulk->iou_hdr.ioc_len = bulk_size;
564 udsp_bulk->iou_bulk_size = bulk_size - sizeof(*udsp_bulk);
566 rc = lnet_udsp_marshal(udsp, bulk, bulk_size);
567 if (rc != LUSTRE_CFG_RC_NO_ERR) {
568 rc = LUSTRE_CFG_RC_MARSHAL_FAIL;
571 "\"failed to marshal udsp\"");
575 udsp_bulk->iou_bulk = bulk + sizeof(*udsp_bulk);
577 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_UDSP, bulk);
580 snprintf(err_str, sizeof(err_str),
581 "\"cannot add udsp: %s\"", strerror(errno));
585 rc = LUSTRE_CFG_RC_NO_ERR;
591 lnet_udsp_free(udsp, false);
592 cYAML_build_error(rc, seq_no, ADD_CMD, "udsp", err_str, err_rc);
596 int lustre_lnet_del_udsp(unsigned int idx, int seq_no, struct cYAML **err_rc)
599 char err_str[LNET_MAX_STR_LEN];
600 struct lnet_ioctl_udsp udsp_bulk;
602 snprintf(err_str, sizeof(err_str), "\"success\"");
604 LIBCFS_IOC_INIT_V2(udsp_bulk, iou_hdr);
605 udsp_bulk.iou_idx = idx;
607 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(rc));
614 cYAML_build_error(rc, seq_no, ADD_CMD, "udsp", err_str, err_rc);