1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /*
3 * Copyright (c) 2018, Mellanox Technologies inc. All rights reserved.
4 */
5
6 #include <rdma/ib_user_verbs.h>
7 #include <rdma/ib_verbs.h>
8 #include <rdma/uverbs_types.h>
9 #include <rdma/uverbs_ioctl.h>
10 #include <rdma/mlx5_user_ioctl_cmds.h>
11 #include <rdma/ib_umem.h>
12 #include <linux/mlx5/driver.h>
13 #include <linux/mlx5/fs.h>
14 #include "mlx5_ib.h"
15
16 #define UVERBS_MODULE_NAME mlx5_ib
17 #include <rdma/uverbs_named_ioctl.h>
18
19 static const struct uverbs_attr_spec mlx5_ib_flow_type[] = {
20 [MLX5_IB_FLOW_TYPE_NORMAL] = {
21 .type = UVERBS_ATTR_TYPE_PTR_IN,
22 .u.ptr = {
23 .len = sizeof(u16), /* data is priority */
24 .min_len = sizeof(u16),
25 }
26 },
27 [MLX5_IB_FLOW_TYPE_SNIFFER] = {
28 .type = UVERBS_ATTR_TYPE_PTR_IN,
29 UVERBS_ATTR_NO_DATA(),
30 },
31 [MLX5_IB_FLOW_TYPE_ALL_DEFAULT] = {
32 .type = UVERBS_ATTR_TYPE_PTR_IN,
33 UVERBS_ATTR_NO_DATA(),
34 },
35 [MLX5_IB_FLOW_TYPE_MC_DEFAULT] = {
36 .type = UVERBS_ATTR_TYPE_PTR_IN,
37 UVERBS_ATTR_NO_DATA(),
38 },
39 };
40
UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)41 static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)(
42 struct ib_uverbs_file *file, struct uverbs_attr_bundle *attrs)
43 {
44 struct mlx5_ib_flow_handler *flow_handler;
45 struct mlx5_ib_flow_matcher *fs_matcher;
46 void *devx_obj;
47 int dest_id, dest_type;
48 void *cmd_in;
49 int inlen;
50 bool dest_devx, dest_qp;
51 struct ib_qp *qp = NULL;
52 struct ib_uobject *uobj =
53 uverbs_attr_get_uobject(attrs, MLX5_IB_ATTR_CREATE_FLOW_HANDLE);
54 struct mlx5_ib_dev *dev = to_mdev(uobj->context->device);
55
56 if (!capable(CAP_NET_RAW))
57 return -EPERM;
58
59 dest_devx =
60 uverbs_attr_is_valid(attrs, MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX);
61 dest_qp = uverbs_attr_is_valid(attrs,
62 MLX5_IB_ATTR_CREATE_FLOW_DEST_QP);
63
64 if ((dest_devx && dest_qp) || (!dest_devx && !dest_qp))
65 return -EINVAL;
66
67 if (dest_devx) {
68 devx_obj = uverbs_attr_get_obj(
69 attrs, MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX);
70 if (IS_ERR(devx_obj))
71 return PTR_ERR(devx_obj);
72
73 /* Verify that the given DEVX object is a flow
74 * steering destination.
75 */
76 if (!mlx5_ib_devx_is_flow_dest(devx_obj, &dest_id, &dest_type))
77 return -EINVAL;
78 } else {
79 struct mlx5_ib_qp *mqp;
80
81 qp = uverbs_attr_get_obj(attrs,
82 MLX5_IB_ATTR_CREATE_FLOW_DEST_QP);
83 if (IS_ERR(qp))
84 return PTR_ERR(qp);
85
86 if (qp->qp_type != IB_QPT_RAW_PACKET)
87 return -EINVAL;
88
89 mqp = to_mqp(qp);
90 if (mqp->flags & MLX5_IB_QP_RSS)
91 dest_id = mqp->rss_qp.tirn;
92 else
93 dest_id = mqp->raw_packet_qp.rq.tirn;
94 dest_type = MLX5_FLOW_DESTINATION_TYPE_TIR;
95 }
96
97 if (dev->rep)
98 return -ENOTSUPP;
99
100 cmd_in = uverbs_attr_get_alloced_ptr(
101 attrs, MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE);
102 inlen = uverbs_attr_get_len(attrs,
103 MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE);
104 fs_matcher = uverbs_attr_get_obj(attrs,
105 MLX5_IB_ATTR_CREATE_FLOW_MATCHER);
106 flow_handler = mlx5_ib_raw_fs_rule_add(dev, fs_matcher, cmd_in, inlen,
107 dest_id, dest_type);
108 if (IS_ERR(flow_handler))
109 return PTR_ERR(flow_handler);
110
111 ib_set_flow(uobj, &flow_handler->ibflow, qp, &dev->ib_dev);
112
113 return 0;
114 }
115
flow_matcher_cleanup(struct ib_uobject * uobject,enum rdma_remove_reason why)116 static int flow_matcher_cleanup(struct ib_uobject *uobject,
117 enum rdma_remove_reason why)
118 {
119 struct mlx5_ib_flow_matcher *obj = uobject->object;
120 int ret;
121
122 ret = ib_destroy_usecnt(&obj->usecnt, why, uobject);
123 if (ret)
124 return ret;
125
126 kfree(obj);
127 return 0;
128 }
129
UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_MATCHER_CREATE)130 static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_MATCHER_CREATE)(
131 struct ib_uverbs_file *file, struct uverbs_attr_bundle *attrs)
132 {
133 struct ib_uobject *uobj = uverbs_attr_get_uobject(
134 attrs, MLX5_IB_ATTR_FLOW_MATCHER_CREATE_HANDLE);
135 struct mlx5_ib_dev *dev = to_mdev(uobj->context->device);
136 struct mlx5_ib_flow_matcher *obj;
137 int err;
138
139 obj = kzalloc(sizeof(struct mlx5_ib_flow_matcher), GFP_KERNEL);
140 if (!obj)
141 return -ENOMEM;
142
143 obj->mask_len = uverbs_attr_get_len(
144 attrs, MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK);
145 err = uverbs_copy_from(&obj->matcher_mask,
146 attrs,
147 MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK);
148 if (err)
149 goto end;
150
151 obj->flow_type = uverbs_attr_get_enum_id(
152 attrs, MLX5_IB_ATTR_FLOW_MATCHER_FLOW_TYPE);
153
154 if (obj->flow_type == MLX5_IB_FLOW_TYPE_NORMAL) {
155 err = uverbs_copy_from(&obj->priority,
156 attrs,
157 MLX5_IB_ATTR_FLOW_MATCHER_FLOW_TYPE);
158 if (err)
159 goto end;
160 }
161
162 err = uverbs_copy_from(&obj->match_criteria_enable,
163 attrs,
164 MLX5_IB_ATTR_FLOW_MATCHER_MATCH_CRITERIA);
165 if (err)
166 goto end;
167
168 uobj->object = obj;
169 obj->mdev = dev->mdev;
170 atomic_set(&obj->usecnt, 0);
171 return 0;
172
173 end:
174 kfree(obj);
175 return err;
176 }
177
178 DECLARE_UVERBS_NAMED_METHOD(
179 MLX5_IB_METHOD_CREATE_FLOW,
180 UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_HANDLE,
181 UVERBS_OBJECT_FLOW,
182 UVERBS_ACCESS_NEW,
183 UA_MANDATORY),
184 UVERBS_ATTR_PTR_IN(
185 MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE,
186 UVERBS_ATTR_SIZE(1, sizeof(struct mlx5_ib_match_params)),
187 UA_MANDATORY,
188 UA_ALLOC_AND_COPY),
189 UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_MATCHER,
190 MLX5_IB_OBJECT_FLOW_MATCHER,
191 UVERBS_ACCESS_READ,
192 UA_MANDATORY),
193 UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_DEST_QP,
194 UVERBS_OBJECT_QP,
195 UVERBS_ACCESS_READ),
196 UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX,
197 MLX5_IB_OBJECT_DEVX_OBJ,
198 UVERBS_ACCESS_READ));
199
200 DECLARE_UVERBS_NAMED_METHOD_DESTROY(
201 MLX5_IB_METHOD_DESTROY_FLOW,
202 UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_HANDLE,
203 UVERBS_OBJECT_FLOW,
204 UVERBS_ACCESS_DESTROY,
205 UA_MANDATORY));
206
207 ADD_UVERBS_METHODS(mlx5_ib_fs,
208 UVERBS_OBJECT_FLOW,
209 &UVERBS_METHOD(MLX5_IB_METHOD_CREATE_FLOW),
210 &UVERBS_METHOD(MLX5_IB_METHOD_DESTROY_FLOW));
211
212 DECLARE_UVERBS_NAMED_METHOD(
213 MLX5_IB_METHOD_FLOW_MATCHER_CREATE,
214 UVERBS_ATTR_IDR(MLX5_IB_ATTR_FLOW_MATCHER_CREATE_HANDLE,
215 MLX5_IB_OBJECT_FLOW_MATCHER,
216 UVERBS_ACCESS_NEW,
217 UA_MANDATORY),
218 UVERBS_ATTR_PTR_IN(
219 MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK,
220 UVERBS_ATTR_SIZE(1, sizeof(struct mlx5_ib_match_params)),
221 UA_MANDATORY),
222 UVERBS_ATTR_ENUM_IN(MLX5_IB_ATTR_FLOW_MATCHER_FLOW_TYPE,
223 mlx5_ib_flow_type,
224 UA_MANDATORY),
225 UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_FLOW_MATCHER_MATCH_CRITERIA,
226 UVERBS_ATTR_TYPE(u8),
227 UA_MANDATORY));
228
229 DECLARE_UVERBS_NAMED_METHOD_DESTROY(
230 MLX5_IB_METHOD_FLOW_MATCHER_DESTROY,
231 UVERBS_ATTR_IDR(MLX5_IB_ATTR_FLOW_MATCHER_DESTROY_HANDLE,
232 MLX5_IB_OBJECT_FLOW_MATCHER,
233 UVERBS_ACCESS_DESTROY,
234 UA_MANDATORY));
235
236 DECLARE_UVERBS_NAMED_OBJECT(MLX5_IB_OBJECT_FLOW_MATCHER,
237 UVERBS_TYPE_ALLOC_IDR(flow_matcher_cleanup),
238 &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_MATCHER_CREATE),
239 &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_MATCHER_DESTROY));
240
241 DECLARE_UVERBS_OBJECT_TREE(flow_objects,
242 &UVERBS_OBJECT(MLX5_IB_OBJECT_FLOW_MATCHER));
243
mlx5_ib_get_flow_trees(const struct uverbs_object_tree_def ** root)244 int mlx5_ib_get_flow_trees(const struct uverbs_object_tree_def **root)
245 {
246 int i = 0;
247
248 root[i++] = &flow_objects;
249 root[i++] = &mlx5_ib_fs;
250
251 return i;
252 }
253