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/uverbs_std_types.h>
11 #include <rdma/mlx5_user_ioctl_cmds.h>
12 #include <rdma/mlx5_user_ioctl_verbs.h>
13 #include <rdma/ib_umem.h>
14 #include <linux/mlx5/driver.h>
15 #include <linux/mlx5/fs.h>
16 #include "mlx5_ib.h"
17 
18 #define UVERBS_MODULE_NAME mlx5_ib
19 #include <rdma/uverbs_named_ioctl.h>
20 
21 static int
mlx5_ib_ft_type_to_namespace(enum mlx5_ib_uapi_flow_table_type table_type,enum mlx5_flow_namespace_type * namespace)22 mlx5_ib_ft_type_to_namespace(enum mlx5_ib_uapi_flow_table_type table_type,
23 			     enum mlx5_flow_namespace_type *namespace)
24 {
25 	switch (table_type) {
26 	case MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX:
27 		*namespace = MLX5_FLOW_NAMESPACE_BYPASS;
28 		break;
29 	case MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX:
30 		*namespace = MLX5_FLOW_NAMESPACE_EGRESS;
31 		break;
32 	case MLX5_IB_UAPI_FLOW_TABLE_TYPE_FDB:
33 		*namespace = MLX5_FLOW_NAMESPACE_FDB;
34 		break;
35 	case MLX5_IB_UAPI_FLOW_TABLE_TYPE_RDMA_RX:
36 		*namespace = MLX5_FLOW_NAMESPACE_RDMA_RX;
37 		break;
38 	default:
39 		return -EINVAL;
40 	}
41 
42 	return 0;
43 }
44 
45 static const struct uverbs_attr_spec mlx5_ib_flow_type[] = {
46 	[MLX5_IB_FLOW_TYPE_NORMAL] = {
47 		.type = UVERBS_ATTR_TYPE_PTR_IN,
48 		.u.ptr = {
49 			.len = sizeof(u16), /* data is priority */
50 			.min_len = sizeof(u16),
51 		}
52 	},
53 	[MLX5_IB_FLOW_TYPE_SNIFFER] = {
54 		.type = UVERBS_ATTR_TYPE_PTR_IN,
55 		UVERBS_ATTR_NO_DATA(),
56 	},
57 	[MLX5_IB_FLOW_TYPE_ALL_DEFAULT] = {
58 		.type = UVERBS_ATTR_TYPE_PTR_IN,
59 		UVERBS_ATTR_NO_DATA(),
60 	},
61 	[MLX5_IB_FLOW_TYPE_MC_DEFAULT] = {
62 		.type = UVERBS_ATTR_TYPE_PTR_IN,
63 		UVERBS_ATTR_NO_DATA(),
64 	},
65 };
66 
67 #define MLX5_IB_CREATE_FLOW_MAX_FLOW_ACTIONS 2
UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)68 static int UVERBS_HANDLER(MLX5_IB_METHOD_CREATE_FLOW)(
69 	struct uverbs_attr_bundle *attrs)
70 {
71 	struct mlx5_flow_context flow_context = {.flow_tag = MLX5_FS_DEFAULT_FLOW_TAG};
72 	struct mlx5_ib_flow_handler *flow_handler;
73 	struct mlx5_ib_flow_matcher *fs_matcher;
74 	struct ib_uobject **arr_flow_actions;
75 	struct ib_uflow_resources *uflow_res;
76 	struct mlx5_flow_act flow_act = {};
77 	void *devx_obj;
78 	int dest_id, dest_type;
79 	void *cmd_in;
80 	int inlen;
81 	bool dest_devx, dest_qp;
82 	struct ib_qp *qp = NULL;
83 	struct ib_uobject *uobj =
84 		uverbs_attr_get_uobject(attrs, MLX5_IB_ATTR_CREATE_FLOW_HANDLE);
85 	struct mlx5_ib_dev *dev = mlx5_udata_to_mdev(&attrs->driver_udata);
86 	int len, ret, i;
87 	u32 counter_id = 0;
88 
89 	if (!capable(CAP_NET_RAW))
90 		return -EPERM;
91 
92 	dest_devx =
93 		uverbs_attr_is_valid(attrs, MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX);
94 	dest_qp = uverbs_attr_is_valid(attrs,
95 				       MLX5_IB_ATTR_CREATE_FLOW_DEST_QP);
96 
97 	fs_matcher = uverbs_attr_get_obj(attrs,
98 					 MLX5_IB_ATTR_CREATE_FLOW_MATCHER);
99 	if (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_BYPASS &&
100 	    ((dest_devx && dest_qp) || (!dest_devx && !dest_qp)))
101 		return -EINVAL;
102 
103 	/* Allow only DEVX object as dest when inserting to FDB */
104 	if (fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_FDB && !dest_devx)
105 		return -EINVAL;
106 
107 	/* Allow only DEVX object or QP as dest when inserting to RDMA_RX */
108 	if ((fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_RDMA_RX) &&
109 	    ((!dest_devx && !dest_qp) || (dest_devx && dest_qp)))
110 		return -EINVAL;
111 
112 	if (dest_devx) {
113 		devx_obj = uverbs_attr_get_obj(
114 			attrs, MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX);
115 		if (IS_ERR(devx_obj))
116 			return PTR_ERR(devx_obj);
117 
118 		/* Verify that the given DEVX object is a flow
119 		 * steering destination.
120 		 */
121 		if (!mlx5_ib_devx_is_flow_dest(devx_obj, &dest_id, &dest_type))
122 			return -EINVAL;
123 		/* Allow only flow table as dest when inserting to FDB or RDMA_RX */
124 		if ((fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_FDB ||
125 		     fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_RDMA_RX) &&
126 		    dest_type != MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE)
127 			return -EINVAL;
128 	} else if (dest_qp) {
129 		struct mlx5_ib_qp *mqp;
130 
131 		qp = uverbs_attr_get_obj(attrs,
132 					 MLX5_IB_ATTR_CREATE_FLOW_DEST_QP);
133 		if (IS_ERR(qp))
134 			return PTR_ERR(qp);
135 
136 		if (qp->qp_type != IB_QPT_RAW_PACKET)
137 			return -EINVAL;
138 
139 		mqp = to_mqp(qp);
140 		if (mqp->flags & MLX5_IB_QP_RSS)
141 			dest_id = mqp->rss_qp.tirn;
142 		else
143 			dest_id = mqp->raw_packet_qp.rq.tirn;
144 		dest_type = MLX5_FLOW_DESTINATION_TYPE_TIR;
145 	} else {
146 		dest_type = MLX5_FLOW_DESTINATION_TYPE_PORT;
147 	}
148 
149 	len = uverbs_attr_get_uobjs_arr(attrs,
150 		MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX, &arr_flow_actions);
151 	if (len) {
152 		devx_obj = arr_flow_actions[0]->object;
153 
154 		if (!mlx5_ib_devx_is_flow_counter(devx_obj, &counter_id))
155 			return -EINVAL;
156 		flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
157 	}
158 
159 	if (dest_type == MLX5_FLOW_DESTINATION_TYPE_TIR &&
160 	    fs_matcher->ns_type == MLX5_FLOW_NAMESPACE_EGRESS)
161 		return -EINVAL;
162 
163 	cmd_in = uverbs_attr_get_alloced_ptr(
164 		attrs, MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE);
165 	inlen = uverbs_attr_get_len(attrs,
166 				    MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE);
167 
168 	uflow_res = flow_resources_alloc(MLX5_IB_CREATE_FLOW_MAX_FLOW_ACTIONS);
169 	if (!uflow_res)
170 		return -ENOMEM;
171 
172 	len = uverbs_attr_get_uobjs_arr(attrs,
173 		MLX5_IB_ATTR_CREATE_FLOW_ARR_FLOW_ACTIONS, &arr_flow_actions);
174 	for (i = 0; i < len; i++) {
175 		struct mlx5_ib_flow_action *maction =
176 			to_mflow_act(arr_flow_actions[i]->object);
177 
178 		ret = parse_flow_flow_action(maction, false, &flow_act);
179 		if (ret)
180 			goto err_out;
181 		flow_resources_add(uflow_res, IB_FLOW_SPEC_ACTION_HANDLE,
182 				   arr_flow_actions[i]->object);
183 	}
184 
185 	ret = uverbs_copy_from(&flow_context.flow_tag, attrs,
186 			       MLX5_IB_ATTR_CREATE_FLOW_TAG);
187 	if (!ret) {
188 		if (flow_context.flow_tag >= BIT(24)) {
189 			ret = -EINVAL;
190 			goto err_out;
191 		}
192 		flow_context.flags |= FLOW_CONTEXT_HAS_TAG;
193 	}
194 
195 	flow_handler = mlx5_ib_raw_fs_rule_add(dev, fs_matcher,
196 					       &flow_context,
197 					       &flow_act,
198 					       counter_id,
199 					       cmd_in, inlen,
200 					       dest_id, dest_type);
201 	if (IS_ERR(flow_handler)) {
202 		ret = PTR_ERR(flow_handler);
203 		goto err_out;
204 	}
205 
206 	ib_set_flow(uobj, &flow_handler->ibflow, qp, &dev->ib_dev, uflow_res);
207 
208 	return 0;
209 err_out:
210 	ib_uverbs_flow_resources_free(uflow_res);
211 	return ret;
212 }
213 
flow_matcher_cleanup(struct ib_uobject * uobject,enum rdma_remove_reason why,struct uverbs_attr_bundle * attrs)214 static int flow_matcher_cleanup(struct ib_uobject *uobject,
215 				enum rdma_remove_reason why,
216 				struct uverbs_attr_bundle *attrs)
217 {
218 	struct mlx5_ib_flow_matcher *obj = uobject->object;
219 	int ret;
220 
221 	ret = ib_destroy_usecnt(&obj->usecnt, why, uobject);
222 	if (ret)
223 		return ret;
224 
225 	kfree(obj);
226 	return 0;
227 }
228 
mlx5_ib_matcher_ns(struct uverbs_attr_bundle * attrs,struct mlx5_ib_flow_matcher * obj)229 static int mlx5_ib_matcher_ns(struct uverbs_attr_bundle *attrs,
230 			      struct mlx5_ib_flow_matcher *obj)
231 {
232 	enum mlx5_ib_uapi_flow_table_type ft_type =
233 		MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX;
234 	u32 flags;
235 	int err;
236 
237 	/* New users should use MLX5_IB_ATTR_FLOW_MATCHER_FT_TYPE and older
238 	 * users should switch to it. We leave this to not break userspace
239 	 */
240 	if (uverbs_attr_is_valid(attrs, MLX5_IB_ATTR_FLOW_MATCHER_FT_TYPE) &&
241 	    uverbs_attr_is_valid(attrs, MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS))
242 		return -EINVAL;
243 
244 	if (uverbs_attr_is_valid(attrs, MLX5_IB_ATTR_FLOW_MATCHER_FT_TYPE)) {
245 		err = uverbs_get_const(&ft_type, attrs,
246 				       MLX5_IB_ATTR_FLOW_MATCHER_FT_TYPE);
247 		if (err)
248 			return err;
249 
250 		err = mlx5_ib_ft_type_to_namespace(ft_type, &obj->ns_type);
251 		if (err)
252 			return err;
253 
254 		return 0;
255 	}
256 
257 	if (uverbs_attr_is_valid(attrs, MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS)) {
258 		err = uverbs_get_flags32(&flags, attrs,
259 					 MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS,
260 					 IB_FLOW_ATTR_FLAGS_EGRESS);
261 		if (err)
262 			return err;
263 
264 		if (flags) {
265 			mlx5_ib_ft_type_to_namespace(
266 				MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX,
267 				&obj->ns_type);
268 			return 0;
269 		}
270 	}
271 
272 	obj->ns_type = MLX5_FLOW_NAMESPACE_BYPASS;
273 
274 	return 0;
275 }
276 
UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_MATCHER_CREATE)277 static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_MATCHER_CREATE)(
278 	struct uverbs_attr_bundle *attrs)
279 {
280 	struct ib_uobject *uobj = uverbs_attr_get_uobject(
281 		attrs, MLX5_IB_ATTR_FLOW_MATCHER_CREATE_HANDLE);
282 	struct mlx5_ib_dev *dev = mlx5_udata_to_mdev(&attrs->driver_udata);
283 	struct mlx5_ib_flow_matcher *obj;
284 	int err;
285 
286 	obj = kzalloc(sizeof(struct mlx5_ib_flow_matcher), GFP_KERNEL);
287 	if (!obj)
288 		return -ENOMEM;
289 
290 	obj->mask_len = uverbs_attr_get_len(
291 		attrs, MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK);
292 	err = uverbs_copy_from(&obj->matcher_mask,
293 			       attrs,
294 			       MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK);
295 	if (err)
296 		goto end;
297 
298 	obj->flow_type = uverbs_attr_get_enum_id(
299 		attrs, MLX5_IB_ATTR_FLOW_MATCHER_FLOW_TYPE);
300 
301 	if (obj->flow_type == MLX5_IB_FLOW_TYPE_NORMAL) {
302 		err = uverbs_copy_from(&obj->priority,
303 				       attrs,
304 				       MLX5_IB_ATTR_FLOW_MATCHER_FLOW_TYPE);
305 		if (err)
306 			goto end;
307 	}
308 
309 	err = uverbs_copy_from(&obj->match_criteria_enable,
310 			       attrs,
311 			       MLX5_IB_ATTR_FLOW_MATCHER_MATCH_CRITERIA);
312 	if (err)
313 		goto end;
314 
315 	err = mlx5_ib_matcher_ns(attrs, obj);
316 	if (err)
317 		goto end;
318 
319 	uobj->object = obj;
320 	obj->mdev = dev->mdev;
321 	atomic_set(&obj->usecnt, 0);
322 	return 0;
323 
324 end:
325 	kfree(obj);
326 	return err;
327 }
328 
mlx5_ib_destroy_flow_action_raw(struct mlx5_ib_flow_action * maction)329 void mlx5_ib_destroy_flow_action_raw(struct mlx5_ib_flow_action *maction)
330 {
331 	switch (maction->flow_action_raw.sub_type) {
332 	case MLX5_IB_FLOW_ACTION_MODIFY_HEADER:
333 		mlx5_modify_header_dealloc(maction->flow_action_raw.dev->mdev,
334 					   maction->flow_action_raw.modify_hdr);
335 		break;
336 	case MLX5_IB_FLOW_ACTION_PACKET_REFORMAT:
337 		mlx5_packet_reformat_dealloc(maction->flow_action_raw.dev->mdev,
338 					     maction->flow_action_raw.pkt_reformat);
339 		break;
340 	case MLX5_IB_FLOW_ACTION_DECAP:
341 		break;
342 	default:
343 		break;
344 	}
345 }
346 
347 static struct ib_flow_action *
mlx5_ib_create_modify_header(struct mlx5_ib_dev * dev,enum mlx5_ib_uapi_flow_table_type ft_type,u8 num_actions,void * in)348 mlx5_ib_create_modify_header(struct mlx5_ib_dev *dev,
349 			     enum mlx5_ib_uapi_flow_table_type ft_type,
350 			     u8 num_actions, void *in)
351 {
352 	enum mlx5_flow_namespace_type namespace;
353 	struct mlx5_ib_flow_action *maction;
354 	int ret;
355 
356 	ret = mlx5_ib_ft_type_to_namespace(ft_type, &namespace);
357 	if (ret)
358 		return ERR_PTR(-EINVAL);
359 
360 	maction = kzalloc(sizeof(*maction), GFP_KERNEL);
361 	if (!maction)
362 		return ERR_PTR(-ENOMEM);
363 
364 	maction->flow_action_raw.modify_hdr =
365 		mlx5_modify_header_alloc(dev->mdev, namespace, num_actions, in);
366 
367 	if (IS_ERR(maction->flow_action_raw.modify_hdr)) {
368 		ret = PTR_ERR(maction->flow_action_raw.modify_hdr);
369 		kfree(maction);
370 		return ERR_PTR(ret);
371 	}
372 	maction->flow_action_raw.sub_type =
373 		MLX5_IB_FLOW_ACTION_MODIFY_HEADER;
374 	maction->flow_action_raw.dev = dev;
375 
376 	return &maction->ib_action;
377 }
378 
mlx5_ib_modify_header_supported(struct mlx5_ib_dev * dev)379 static bool mlx5_ib_modify_header_supported(struct mlx5_ib_dev *dev)
380 {
381 	return MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev,
382 					 max_modify_header_actions) ||
383 	       MLX5_CAP_FLOWTABLE_NIC_TX(dev->mdev, max_modify_header_actions);
384 }
385 
UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER)386 static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER)(
387 	struct uverbs_attr_bundle *attrs)
388 {
389 	struct ib_uobject *uobj = uverbs_attr_get_uobject(
390 		attrs, MLX5_IB_ATTR_CREATE_MODIFY_HEADER_HANDLE);
391 	struct mlx5_ib_dev *mdev = mlx5_udata_to_mdev(&attrs->driver_udata);
392 	enum mlx5_ib_uapi_flow_table_type ft_type;
393 	struct ib_flow_action *action;
394 	int num_actions;
395 	void *in;
396 	int ret;
397 
398 	if (!mlx5_ib_modify_header_supported(mdev))
399 		return -EOPNOTSUPP;
400 
401 	in = uverbs_attr_get_alloced_ptr(attrs,
402 		MLX5_IB_ATTR_CREATE_MODIFY_HEADER_ACTIONS_PRM);
403 
404 	num_actions = uverbs_attr_ptr_get_array_size(
405 		attrs, MLX5_IB_ATTR_CREATE_MODIFY_HEADER_ACTIONS_PRM,
406 		MLX5_UN_SZ_BYTES(set_action_in_add_action_in_auto));
407 	if (num_actions < 0)
408 		return num_actions;
409 
410 	ret = uverbs_get_const(&ft_type, attrs,
411 			       MLX5_IB_ATTR_CREATE_MODIFY_HEADER_FT_TYPE);
412 	if (ret)
413 		return ret;
414 	action = mlx5_ib_create_modify_header(mdev, ft_type, num_actions, in);
415 	if (IS_ERR(action))
416 		return PTR_ERR(action);
417 
418 	uverbs_flow_action_fill_action(action, uobj, &mdev->ib_dev,
419 				       IB_FLOW_ACTION_UNSPECIFIED);
420 
421 	return 0;
422 }
423 
mlx5_ib_flow_action_packet_reformat_valid(struct mlx5_ib_dev * ibdev,u8 packet_reformat_type,u8 ft_type)424 static bool mlx5_ib_flow_action_packet_reformat_valid(struct mlx5_ib_dev *ibdev,
425 						      u8 packet_reformat_type,
426 						      u8 ft_type)
427 {
428 	switch (packet_reformat_type) {
429 	case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL:
430 		if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX)
431 			return MLX5_CAP_FLOWTABLE(ibdev->mdev,
432 						  encap_general_header);
433 		break;
434 	case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL:
435 		if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX)
436 			return MLX5_CAP_FLOWTABLE_NIC_TX(ibdev->mdev,
437 				reformat_l2_to_l3_tunnel);
438 		break;
439 	case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2:
440 		if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX)
441 			return MLX5_CAP_FLOWTABLE_NIC_RX(ibdev->mdev,
442 				reformat_l3_tunnel_to_l2);
443 		break;
444 	case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2:
445 		if (ft_type == MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX)
446 			return MLX5_CAP_FLOWTABLE_NIC_RX(ibdev->mdev, decap);
447 		break;
448 	default:
449 		break;
450 	}
451 
452 	return false;
453 }
454 
mlx5_ib_dv_to_prm_packet_reforamt_type(u8 dv_prt,u8 * prm_prt)455 static int mlx5_ib_dv_to_prm_packet_reforamt_type(u8 dv_prt, u8 *prm_prt)
456 {
457 	switch (dv_prt) {
458 	case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL:
459 		*prm_prt = MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL;
460 		break;
461 	case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2:
462 		*prm_prt = MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2;
463 		break;
464 	case MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL:
465 		*prm_prt = MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL;
466 		break;
467 	default:
468 		return -EINVAL;
469 	}
470 
471 	return 0;
472 }
473 
mlx5_ib_flow_action_create_packet_reformat_ctx(struct mlx5_ib_dev * dev,struct mlx5_ib_flow_action * maction,u8 ft_type,u8 dv_prt,void * in,size_t len)474 static int mlx5_ib_flow_action_create_packet_reformat_ctx(
475 	struct mlx5_ib_dev *dev,
476 	struct mlx5_ib_flow_action *maction,
477 	u8 ft_type, u8 dv_prt,
478 	void *in, size_t len)
479 {
480 	enum mlx5_flow_namespace_type namespace;
481 	u8 prm_prt;
482 	int ret;
483 
484 	ret = mlx5_ib_ft_type_to_namespace(ft_type, &namespace);
485 	if (ret)
486 		return ret;
487 
488 	ret = mlx5_ib_dv_to_prm_packet_reforamt_type(dv_prt, &prm_prt);
489 	if (ret)
490 		return ret;
491 
492 	maction->flow_action_raw.pkt_reformat =
493 		mlx5_packet_reformat_alloc(dev->mdev, prm_prt, len,
494 					   in, namespace);
495 	if (IS_ERR(maction->flow_action_raw.pkt_reformat)) {
496 		ret = PTR_ERR(maction->flow_action_raw.pkt_reformat);
497 		return ret;
498 	}
499 
500 	maction->flow_action_raw.sub_type =
501 		MLX5_IB_FLOW_ACTION_PACKET_REFORMAT;
502 	maction->flow_action_raw.dev = dev;
503 
504 	return 0;
505 }
506 
UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT)507 static int UVERBS_HANDLER(MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT)(
508 	struct uverbs_attr_bundle *attrs)
509 {
510 	struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs,
511 		MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_HANDLE);
512 	struct mlx5_ib_dev *mdev = mlx5_udata_to_mdev(&attrs->driver_udata);
513 	enum mlx5_ib_uapi_flow_action_packet_reformat_type dv_prt;
514 	enum mlx5_ib_uapi_flow_table_type ft_type;
515 	struct mlx5_ib_flow_action *maction;
516 	int ret;
517 
518 	ret = uverbs_get_const(&ft_type, attrs,
519 			       MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_FT_TYPE);
520 	if (ret)
521 		return ret;
522 
523 	ret = uverbs_get_const(&dv_prt, attrs,
524 			       MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_TYPE);
525 	if (ret)
526 		return ret;
527 
528 	if (!mlx5_ib_flow_action_packet_reformat_valid(mdev, dv_prt, ft_type))
529 		return -EOPNOTSUPP;
530 
531 	maction = kzalloc(sizeof(*maction), GFP_KERNEL);
532 	if (!maction)
533 		return -ENOMEM;
534 
535 	if (dv_prt ==
536 	    MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2) {
537 		maction->flow_action_raw.sub_type =
538 			MLX5_IB_FLOW_ACTION_DECAP;
539 		maction->flow_action_raw.dev = mdev;
540 	} else {
541 		void *in;
542 		int len;
543 
544 		in = uverbs_attr_get_alloced_ptr(attrs,
545 			MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_DATA_BUF);
546 		if (IS_ERR(in)) {
547 			ret = PTR_ERR(in);
548 			goto free_maction;
549 		}
550 
551 		len = uverbs_attr_get_len(attrs,
552 			MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_DATA_BUF);
553 
554 		ret = mlx5_ib_flow_action_create_packet_reformat_ctx(mdev,
555 			maction, ft_type, dv_prt, in, len);
556 		if (ret)
557 			goto free_maction;
558 	}
559 
560 	uverbs_flow_action_fill_action(&maction->ib_action, uobj, &mdev->ib_dev,
561 				       IB_FLOW_ACTION_UNSPECIFIED);
562 	return 0;
563 
564 free_maction:
565 	kfree(maction);
566 	return ret;
567 }
568 
569 DECLARE_UVERBS_NAMED_METHOD(
570 	MLX5_IB_METHOD_CREATE_FLOW,
571 	UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_HANDLE,
572 			UVERBS_OBJECT_FLOW,
573 			UVERBS_ACCESS_NEW,
574 			UA_MANDATORY),
575 	UVERBS_ATTR_PTR_IN(
576 		MLX5_IB_ATTR_CREATE_FLOW_MATCH_VALUE,
577 		UVERBS_ATTR_SIZE(1, sizeof(struct mlx5_ib_match_params)),
578 		UA_MANDATORY,
579 		UA_ALLOC_AND_COPY),
580 	UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_MATCHER,
581 			MLX5_IB_OBJECT_FLOW_MATCHER,
582 			UVERBS_ACCESS_READ,
583 			UA_MANDATORY),
584 	UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_DEST_QP,
585 			UVERBS_OBJECT_QP,
586 			UVERBS_ACCESS_READ),
587 	UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX,
588 			MLX5_IB_OBJECT_DEVX_OBJ,
589 			UVERBS_ACCESS_READ),
590 	UVERBS_ATTR_IDRS_ARR(MLX5_IB_ATTR_CREATE_FLOW_ARR_FLOW_ACTIONS,
591 			     UVERBS_OBJECT_FLOW_ACTION,
592 			     UVERBS_ACCESS_READ, 1,
593 			     MLX5_IB_CREATE_FLOW_MAX_FLOW_ACTIONS,
594 			     UA_OPTIONAL),
595 	UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_CREATE_FLOW_TAG,
596 			   UVERBS_ATTR_TYPE(u32),
597 			   UA_OPTIONAL),
598 	UVERBS_ATTR_IDRS_ARR(MLX5_IB_ATTR_CREATE_FLOW_ARR_COUNTERS_DEVX,
599 			     MLX5_IB_OBJECT_DEVX_OBJ,
600 			     UVERBS_ACCESS_READ, 1, 1,
601 			     UA_OPTIONAL));
602 
603 DECLARE_UVERBS_NAMED_METHOD_DESTROY(
604 	MLX5_IB_METHOD_DESTROY_FLOW,
605 	UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_FLOW_HANDLE,
606 			UVERBS_OBJECT_FLOW,
607 			UVERBS_ACCESS_DESTROY,
608 			UA_MANDATORY));
609 
610 ADD_UVERBS_METHODS(mlx5_ib_fs,
611 		   UVERBS_OBJECT_FLOW,
612 		   &UVERBS_METHOD(MLX5_IB_METHOD_CREATE_FLOW),
613 		   &UVERBS_METHOD(MLX5_IB_METHOD_DESTROY_FLOW));
614 
615 DECLARE_UVERBS_NAMED_METHOD(
616 	MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER,
617 	UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_MODIFY_HEADER_HANDLE,
618 			UVERBS_OBJECT_FLOW_ACTION,
619 			UVERBS_ACCESS_NEW,
620 			UA_MANDATORY),
621 	UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_CREATE_MODIFY_HEADER_ACTIONS_PRM,
622 			   UVERBS_ATTR_MIN_SIZE(MLX5_UN_SZ_BYTES(
623 				   set_action_in_add_action_in_auto)),
624 			   UA_MANDATORY,
625 			   UA_ALLOC_AND_COPY),
626 	UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_CREATE_MODIFY_HEADER_FT_TYPE,
627 			     enum mlx5_ib_uapi_flow_table_type,
628 			     UA_MANDATORY));
629 
630 DECLARE_UVERBS_NAMED_METHOD(
631 	MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT,
632 	UVERBS_ATTR_IDR(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_HANDLE,
633 			UVERBS_OBJECT_FLOW_ACTION,
634 			UVERBS_ACCESS_NEW,
635 			UA_MANDATORY),
636 	UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_DATA_BUF,
637 			   UVERBS_ATTR_MIN_SIZE(1),
638 			   UA_ALLOC_AND_COPY,
639 			   UA_OPTIONAL),
640 	UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_TYPE,
641 			     enum mlx5_ib_uapi_flow_action_packet_reformat_type,
642 			     UA_MANDATORY),
643 	UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_FT_TYPE,
644 			     enum mlx5_ib_uapi_flow_table_type,
645 			     UA_MANDATORY));
646 
647 ADD_UVERBS_METHODS(
648 	mlx5_ib_flow_actions,
649 	UVERBS_OBJECT_FLOW_ACTION,
650 	&UVERBS_METHOD(MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER),
651 	&UVERBS_METHOD(MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT));
652 
653 DECLARE_UVERBS_NAMED_METHOD(
654 	MLX5_IB_METHOD_FLOW_MATCHER_CREATE,
655 	UVERBS_ATTR_IDR(MLX5_IB_ATTR_FLOW_MATCHER_CREATE_HANDLE,
656 			MLX5_IB_OBJECT_FLOW_MATCHER,
657 			UVERBS_ACCESS_NEW,
658 			UA_MANDATORY),
659 	UVERBS_ATTR_PTR_IN(
660 		MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK,
661 		UVERBS_ATTR_SIZE(1, sizeof(struct mlx5_ib_match_params)),
662 		UA_MANDATORY),
663 	UVERBS_ATTR_ENUM_IN(MLX5_IB_ATTR_FLOW_MATCHER_FLOW_TYPE,
664 			    mlx5_ib_flow_type,
665 			    UA_MANDATORY),
666 	UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_FLOW_MATCHER_MATCH_CRITERIA,
667 			   UVERBS_ATTR_TYPE(u8),
668 			   UA_MANDATORY),
669 	UVERBS_ATTR_FLAGS_IN(MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS,
670 			     enum ib_flow_flags,
671 			     UA_OPTIONAL),
672 	UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_FLOW_MATCHER_FT_TYPE,
673 			     enum mlx5_ib_uapi_flow_table_type,
674 			     UA_OPTIONAL));
675 
676 DECLARE_UVERBS_NAMED_METHOD_DESTROY(
677 	MLX5_IB_METHOD_FLOW_MATCHER_DESTROY,
678 	UVERBS_ATTR_IDR(MLX5_IB_ATTR_FLOW_MATCHER_DESTROY_HANDLE,
679 			MLX5_IB_OBJECT_FLOW_MATCHER,
680 			UVERBS_ACCESS_DESTROY,
681 			UA_MANDATORY));
682 
683 DECLARE_UVERBS_NAMED_OBJECT(MLX5_IB_OBJECT_FLOW_MATCHER,
684 			    UVERBS_TYPE_ALLOC_IDR(flow_matcher_cleanup),
685 			    &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_MATCHER_CREATE),
686 			    &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_MATCHER_DESTROY));
687 
688 const struct uapi_definition mlx5_ib_flow_defs[] = {
689 	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(
690 		MLX5_IB_OBJECT_FLOW_MATCHER),
691 	UAPI_DEF_CHAIN_OBJ_TREE(
692 		UVERBS_OBJECT_FLOW,
693 		&mlx5_ib_fs),
694 	UAPI_DEF_CHAIN_OBJ_TREE(UVERBS_OBJECT_FLOW_ACTION,
695 				&mlx5_ib_flow_actions),
696 	{},
697 };
698