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 "liblnetconfig.h"
48 lnet_udsp_criteria_present(struct lnet_ud_nid_descr *descr)
50 return descr->ud_net_id.udn_net_type != 0;
53 struct lnet_udsp *lnet_udsp_alloc(void)
55 struct lnet_udsp *udsp;
57 udsp = calloc(1, sizeof(*udsp));
62 INIT_LIST_HEAD(&udsp->udsp_on_list);
63 INIT_LIST_HEAD(&udsp->udsp_src.ud_addr_range);
64 INIT_LIST_HEAD(&udsp->udsp_src.ud_net_id.udn_net_num_range);
65 INIT_LIST_HEAD(&udsp->udsp_dst.ud_addr_range);
66 INIT_LIST_HEAD(&udsp->udsp_dst.ud_net_id.udn_net_num_range);
67 INIT_LIST_HEAD(&udsp->udsp_rte.ud_addr_range);
68 INIT_LIST_HEAD(&udsp->udsp_rte.ud_net_id.udn_net_num_range);
74 lnet_udsp_nid_descr_free(struct lnet_ud_nid_descr *nid_descr, bool blk)
76 struct list_head *net_range = &nid_descr->ud_net_id.udn_net_num_range;
78 if (!lnet_udsp_criteria_present(nid_descr))
81 /* memory management is a bit tricky here. When we allocate the
82 * memory to store the NID descriptor we allocate a large buffer
83 * for all the data, so we need to free the entire buffer at
84 * once. If the net is present the net_range->next points to that
85 * buffer otherwise if the ud_addr_range is present then it's the
89 if (!list_empty(net_range))
90 free(net_range->next);
91 else if (!list_empty(&nid_descr->ud_addr_range))
92 free(nid_descr->ud_addr_range.next);
94 cfs_expr_list_free_list(net_range);
95 cfs_expr_list_free_list(&nid_descr->ud_addr_range);
100 lnet_udsp_free(struct lnet_udsp *udsp, bool blk)
102 lnet_udsp_nid_descr_free(&udsp->udsp_src, blk);
103 lnet_udsp_nid_descr_free(&udsp->udsp_dst, blk);
104 lnet_udsp_nid_descr_free(&udsp->udsp_rte, blk);
110 copy_range_info(void __user **bulk, void **buf, struct list_head *list,
113 struct lnet_range_expr *range_expr;
114 struct cfs_range_expr *range;
115 struct cfs_expr_list *exprs;
116 int range_count = count;
119 if (range_count == 0)
122 if (range_count == -1) {
123 struct lnet_expressions *e;
126 range_count = e->le_count;
131 INIT_LIST_HEAD(&exprs->el_link);
132 INIT_LIST_HEAD(&exprs->el_exprs);
133 list_add_tail(&exprs->el_link, list);
134 *buf += sizeof(*exprs);
136 for (i = 0; i < range_count; i++) {
139 INIT_LIST_HEAD(&range->re_link);
140 range->re_lo = range_expr->re_lo;
141 range->re_hi = range_expr->re_hi;
142 range->re_stride = range_expr->re_stride;
143 list_add_tail(&range->re_link, &exprs->el_exprs);
144 *bulk += sizeof(*range_expr);
145 *buf += sizeof(*range);
150 copy_ioc_udsp_descr(struct lnet_ud_nid_descr *nid_descr, char *type,
151 void **bulk, __u32 *bulk_size)
153 struct lnet_ioctl_udsp_descr *ioc_nid = *bulk;
154 struct lnet_expressions *exprs;
160 int remaining_size = *bulk_size;
164 size_t range_expr_s = sizeof(struct lnet_range_expr);
165 size_t lnet_exprs_s = sizeof(struct lnet_expressions);
167 /* criteria not present, skip over the static part of the
168 * bulk, which is included for each NID descriptor
170 if (ioc_nid->iud_net.ud_net_type == 0) {
171 remaining_size -= sizeof(*ioc_nid);
172 if (remaining_size < 0)
174 *bulk += sizeof(*ioc_nid);
175 *bulk_size = remaining_size;
179 descr_type = ioc_nid->iud_src_hdr.ud_descr_type;
180 if (descr_type != *(__u32 *)type)
183 /* calculate the total size to verify we have enough buffer.
184 * Start of by finding how many ranges there are for the net
187 range_count = ioc_nid->iud_net.ud_net_num_expr.le_count;
188 size = sizeof(*ioc_nid) + (range_count * range_expr_s);
189 remaining_size -= size;
190 if (remaining_size < 0)
193 /* the number of expressions for the NID. IE 4 for IP, 1 for GNI */
194 expr_count = ioc_nid->iud_src_hdr.ud_descr_count;
195 /* point tmp to the beginning of the NID expressions */
197 for (i = 0; i < expr_count; i++) {
198 /* get the number of ranges per expression */
200 range_count += exprs->le_count;
201 size = (range_expr_s * exprs->le_count) + lnet_exprs_s;
202 remaining_size -= size;
203 if (remaining_size < 0)
208 *bulk_size = remaining_size;
210 /* copy over the net type */
211 nid_descr->ud_net_id.udn_net_type = ioc_nid->iud_net.ud_net_type;
213 /* allocate the total memory required to copy this NID descriptor */
214 alloc_size = (sizeof(struct cfs_expr_list) * (expr_count + 1)) +
215 (sizeof(struct cfs_range_expr) * (range_count));
216 buf = calloc(alloc_size, 1);
220 /* copy over the net number range */
221 range_count = ioc_nid->iud_net.ud_net_num_expr.le_count;
222 *bulk += sizeof(*ioc_nid);
223 copy_range_info(bulk, &buf, &nid_descr->ud_net_id.udn_net_num_range,
226 /* copy over the NID descriptor */
227 for (i = 0; i < expr_count; i++)
228 copy_range_info(bulk, &buf, &nid_descr->ud_addr_range, -1);
234 lnet_udsp_demarshal(void *bulk, __u32 bulk_size)
236 struct lnet_ioctl_udsp *ioc_udsp;
237 struct lnet_udsp *udsp;
240 if (bulk_size < sizeof(*ioc_udsp))
243 udsp = lnet_udsp_alloc();
249 udsp->udsp_action_type = ioc_udsp->iou_action_type;
250 udsp->udsp_action.udsp_priority = ioc_udsp->iou_action.priority;
251 udsp->udsp_idx = ioc_udsp->iou_idx;
253 bulk = ioc_udsp->iou_bulk;
254 bulk_size -= sizeof(*ioc_udsp);
256 if (bulk_size != ioc_udsp->iou_bulk_size)
259 rc = copy_ioc_udsp_descr(&udsp->udsp_src, "SRC", &bulk, &bulk_size);
263 rc = copy_ioc_udsp_descr(&udsp->udsp_dst, "DST", &bulk, &bulk_size);
267 rc = copy_ioc_udsp_descr(&udsp->udsp_rte, "RTE", &bulk, &bulk_size);
274 lnet_udsp_free(udsp, true);
279 lnet_get_list_len(struct list_head *list)
284 list_for_each(l, list)
291 lnet_size_marshaled_nid_descr(struct lnet_ud_nid_descr *descr)
293 struct cfs_expr_list *expr;
296 size_t size = sizeof(struct lnet_ioctl_udsp_descr);
298 if (!lnet_udsp_criteria_present(descr))
301 if (!list_empty(&descr->ud_net_id.udn_net_num_range)) {
302 expr = list_entry(descr->ud_net_id.udn_net_num_range.next,
303 struct cfs_expr_list, el_link);
304 range_count = lnet_get_list_len(&expr->el_exprs);
307 /* count the number of cfs_range_expr in the address expressions */
308 list_for_each_entry(expr, &descr->ud_addr_range, el_link) {
310 range_count += lnet_get_list_len(&expr->el_exprs);
313 size += (sizeof(struct lnet_expressions) * expr_count);
314 size += (sizeof(struct lnet_range_expr) * range_count);
320 lnet_get_udsp_size(struct lnet_udsp *udsp)
322 size_t size = sizeof(struct lnet_ioctl_udsp);
324 size += lnet_size_marshaled_nid_descr(&udsp->udsp_src);
325 size += lnet_size_marshaled_nid_descr(&udsp->udsp_dst);
326 size += lnet_size_marshaled_nid_descr(&udsp->udsp_rte);
332 copy_exprs(struct cfs_expr_list *expr, void __user **bulk,
335 struct cfs_range_expr *range;
336 struct lnet_range_expr range_expr;
338 /* copy over the net range expressions to the bulk */
339 list_for_each_entry(range, &expr->el_exprs, re_link) {
340 range_expr.re_lo = range->re_lo;
341 range_expr.re_hi = range->re_hi;
342 range_expr.re_stride = range->re_stride;
343 memcpy(*bulk, &range_expr, sizeof(range_expr));
344 *bulk += sizeof(range_expr);
345 *bulk_size -= sizeof(range_expr);
350 copy_nid_range(struct lnet_ud_nid_descr *nid_descr, char *type,
351 void __user **bulk, __s32 *bulk_size)
353 struct lnet_ioctl_udsp_descr ioc_udsp_descr = { { 0 } };
354 struct cfs_expr_list *expr;
355 struct lnet_expressions ioc_expr;
357 int net_expr_count = 0;
359 ioc_udsp_descr.iud_src_hdr.ud_descr_type = *(__u32 *)type;
361 /* if criteria not present, copy over the static part of the NID
364 if (!lnet_udsp_criteria_present(nid_descr)) {
365 memcpy(*bulk, &ioc_udsp_descr,
366 sizeof(ioc_udsp_descr));
367 *bulk += sizeof(ioc_udsp_descr);
368 *bulk_size -= sizeof(ioc_udsp_descr);
372 expr_count = lnet_get_list_len(&nid_descr->ud_addr_range);
374 /* copy the net information */
375 if (!list_empty(&nid_descr->ud_net_id.udn_net_num_range)) {
376 expr = list_entry(nid_descr->ud_net_id.udn_net_num_range.next,
377 struct cfs_expr_list, el_link);
378 net_expr_count = lnet_get_list_len(&expr->el_exprs);
383 /* set the total expression count */
384 ioc_udsp_descr.iud_src_hdr.ud_descr_count = expr_count;
385 ioc_udsp_descr.iud_net.ud_net_type =
386 nid_descr->ud_net_id.udn_net_type;
387 ioc_udsp_descr.iud_net.ud_net_num_expr.le_count = net_expr_count;
389 /* copy over the header info to the bulk */
390 memcpy(*bulk, &ioc_udsp_descr, sizeof(ioc_udsp_descr));
391 *bulk += sizeof(ioc_udsp_descr);
392 *bulk_size -= sizeof(ioc_udsp_descr);
394 /* copy over the net num expression if it exists */
396 copy_exprs(expr, bulk, bulk_size);
398 /* copy the address range */
399 list_for_each_entry(expr, &nid_descr->ud_addr_range, el_link) {
400 ioc_expr.le_count = lnet_get_list_len(&expr->el_exprs);
401 memcpy(*bulk, &ioc_expr, sizeof(ioc_expr));
402 *bulk += sizeof(ioc_expr);
403 *bulk_size -= sizeof(ioc_expr);
405 copy_exprs(expr, bulk, bulk_size);
412 lnet_udsp_marshal(struct lnet_udsp *udsp, void *bulk,
415 struct lnet_ioctl_udsp *ioc_udsp;
418 /* make sure user space allocated enough buffer to marshal the
421 if (bulk_size < lnet_get_udsp_size(udsp))
426 ioc_udsp->iou_idx = udsp->udsp_idx;
427 ioc_udsp->iou_action_type = udsp->udsp_action_type;
428 ioc_udsp->iou_action.priority = udsp->udsp_action.udsp_priority;
430 bulk += sizeof(*ioc_udsp);
431 bulk_size -= sizeof(*ioc_udsp);
433 rc = copy_nid_range(&udsp->udsp_src, "SRC", &bulk, &bulk_size);
437 rc = copy_nid_range(&udsp->udsp_dst, "DST", &bulk, &bulk_size);
441 rc = copy_nid_range(&udsp->udsp_rte, "RTE", &bulk, &bulk_size);