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);