xref: /freebsd/sys/ofed/drivers/infiniband/core/ib_uverbs_std_types_flow_action.c (revision b633e08c705fe43180567eae26923d6f6f98c8d9)
1 /*
2  * Copyright (c) 2018, Mellanox Technologies inc.  All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  */
32 
33 #include "rdma_core.h"
34 #include "uverbs.h"
35 #include <rdma/uverbs_std_types.h>
36 
uverbs_free_flow_action(struct ib_uobject * uobject,enum rdma_remove_reason why,struct uverbs_attr_bundle * attrs)37 static int uverbs_free_flow_action(struct ib_uobject *uobject,
38 				   enum rdma_remove_reason why,
39 				   struct uverbs_attr_bundle *attrs)
40 {
41 	struct ib_flow_action *action = uobject->object;
42 	int ret;
43 
44 	ret = ib_destroy_usecnt(&action->usecnt, why, uobject);
45 	if (ret)
46 		return ret;
47 
48 	return action->device->destroy_flow_action(action);
49 }
50 
esp_flags_uverbs_to_verbs(struct uverbs_attr_bundle * attrs,u32 flags,bool is_modify)51 static u64 esp_flags_uverbs_to_verbs(struct uverbs_attr_bundle *attrs,
52 				     u32 flags, bool is_modify)
53 {
54 	u64 verbs_flags = flags;
55 
56 	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_ESN))
57 		verbs_flags |= IB_FLOW_ACTION_ESP_FLAGS_ESN_TRIGGERED;
58 
59 	if (is_modify && uverbs_attr_is_valid(attrs,
60 					      UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS))
61 		verbs_flags |= IB_FLOW_ACTION_ESP_FLAGS_MOD_ESP_ATTRS;
62 
63 	return verbs_flags;
64 };
65 
validate_flow_action_esp_keymat_aes_gcm(struct ib_flow_action_attrs_esp_keymats * keymat)66 static int validate_flow_action_esp_keymat_aes_gcm(struct ib_flow_action_attrs_esp_keymats *keymat)
67 {
68 	struct ib_uverbs_flow_action_esp_keymat_aes_gcm *aes_gcm =
69 		&keymat->keymat.aes_gcm;
70 
71 	if (aes_gcm->iv_algo > IB_UVERBS_FLOW_ACTION_IV_ALGO_SEQ)
72 		return -EOPNOTSUPP;
73 
74 	if (aes_gcm->key_len != 32 &&
75 	    aes_gcm->key_len != 24 &&
76 	    aes_gcm->key_len != 16)
77 		return -EINVAL;
78 
79 	if (aes_gcm->icv_len != 16 &&
80 	    aes_gcm->icv_len != 8 &&
81 	    aes_gcm->icv_len != 12)
82 		return -EINVAL;
83 
84 	return 0;
85 }
86 
87 static int (* const flow_action_esp_keymat_validate[])(struct ib_flow_action_attrs_esp_keymats *keymat) = {
88 	[IB_UVERBS_FLOW_ACTION_ESP_KEYMAT_AES_GCM] = validate_flow_action_esp_keymat_aes_gcm,
89 };
90 
flow_action_esp_replay_none(struct ib_flow_action_attrs_esp_replays * replay,bool is_modify)91 static int flow_action_esp_replay_none(struct ib_flow_action_attrs_esp_replays *replay,
92 				       bool is_modify)
93 {
94 	/* This is used in order to modify an esp flow action with an enabled
95 	 * replay protection to a disabled one. This is only supported via
96 	 * modify, as in create verb we can simply drop the REPLAY attribute and
97 	 * achieve the same thing.
98 	 */
99 	return is_modify ? 0 : -EINVAL;
100 }
101 
flow_action_esp_replay_def_ok(struct ib_flow_action_attrs_esp_replays * replay,bool is_modify)102 static int flow_action_esp_replay_def_ok(struct ib_flow_action_attrs_esp_replays *replay,
103 					 bool is_modify)
104 {
105 	/* Some replay protections could always be enabled without validating
106 	 * anything.
107 	 */
108 	return 0;
109 }
110 
111 static int (* const flow_action_esp_replay_validate[])(struct ib_flow_action_attrs_esp_replays *replay,
112 						       bool is_modify) = {
113 	[IB_UVERBS_FLOW_ACTION_ESP_REPLAY_NONE] = flow_action_esp_replay_none,
114 	[IB_UVERBS_FLOW_ACTION_ESP_REPLAY_BMP] = flow_action_esp_replay_def_ok,
115 };
116 
parse_esp_ip(enum ib_flow_spec_type proto,const void __user * val_ptr,size_t len,union ib_flow_spec * out)117 static int parse_esp_ip(enum ib_flow_spec_type proto,
118 			const void __user *val_ptr,
119 			size_t len, union ib_flow_spec *out)
120 {
121 	int ret;
122 	const struct ib_uverbs_flow_ipv4_filter ipv4 = {
123 		.src_ip = cpu_to_be32(0xffffffffUL),
124 		.dst_ip = cpu_to_be32(0xffffffffUL),
125 		.proto = 0xff,
126 		.tos = 0xff,
127 		.ttl = 0xff,
128 		.flags = 0xff,
129 	};
130 	const struct ib_uverbs_flow_ipv6_filter ipv6 = {
131 		.src_ip = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
132 			   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
133 		.dst_ip = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
134 			   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
135 		.flow_label = cpu_to_be32(0xffffffffUL),
136 		.next_hdr = 0xff,
137 		.traffic_class = 0xff,
138 		.hop_limit = 0xff,
139 	};
140 	union {
141 		struct ib_uverbs_flow_ipv4_filter ipv4;
142 		struct ib_uverbs_flow_ipv6_filter ipv6;
143 	} user_val = {};
144 	const void *user_pmask;
145 	size_t val_len;
146 
147 	/* If the flow IPv4/IPv6 flow specifications are extended, the mask
148 	 * should be changed as well.
149 	 */
150 	BUILD_BUG_ON(offsetof(struct ib_uverbs_flow_ipv4_filter, flags) +
151 		     sizeof(ipv4.flags) != sizeof(ipv4));
152 	BUILD_BUG_ON(offsetof(struct ib_uverbs_flow_ipv6_filter, reserved) +
153 		     sizeof(ipv6.reserved) != sizeof(ipv6));
154 
155 	switch (proto) {
156 	case IB_FLOW_SPEC_IPV4:
157 		if (len > sizeof(user_val.ipv4) &&
158 		    !ib_is_buffer_cleared((const u8 *)val_ptr + sizeof(user_val.ipv4),
159 					  len - sizeof(user_val.ipv4)))
160 			return -EOPNOTSUPP;
161 
162 		val_len = min_t(size_t, len, sizeof(user_val.ipv4));
163 		ret = copy_from_user(&user_val.ipv4, val_ptr,
164 				     val_len);
165 		if (ret)
166 			return -EFAULT;
167 
168 		user_pmask = &ipv4;
169 		break;
170 	case IB_FLOW_SPEC_IPV6:
171 		if (len > sizeof(user_val.ipv6) &&
172 		    !ib_is_buffer_cleared((const u8 *)val_ptr + sizeof(user_val.ipv6),
173 					  len - sizeof(user_val.ipv6)))
174 			return -EOPNOTSUPP;
175 
176 		val_len = min_t(size_t, len, sizeof(user_val.ipv6));
177 		ret = copy_from_user(&user_val.ipv6, val_ptr,
178 				     val_len);
179 		if (ret)
180 			return -EFAULT;
181 
182 		user_pmask = &ipv6;
183 		break;
184 	default:
185 		return -EOPNOTSUPP;
186 	}
187 
188 	return ib_uverbs_kern_spec_to_ib_spec_filter(proto, user_pmask,
189 						     &user_val,
190 						     val_len, out);
191 }
192 
flow_action_esp_get_encap(struct ib_flow_spec_list * out,struct uverbs_attr_bundle * attrs)193 static int flow_action_esp_get_encap(struct ib_flow_spec_list *out,
194 				     struct uverbs_attr_bundle *attrs)
195 {
196 	struct ib_uverbs_flow_action_esp_encap uverbs_encap;
197 	int ret;
198 
199 	ret = uverbs_copy_from(&uverbs_encap, attrs,
200 			       UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP);
201 	if (ret)
202 		return ret;
203 
204 	/* We currently support only one encap */
205 	if (uverbs_encap.next_ptr)
206 		return -EOPNOTSUPP;
207 
208 	if (uverbs_encap.type != IB_FLOW_SPEC_IPV4 &&
209 	    uverbs_encap.type != IB_FLOW_SPEC_IPV6)
210 		return -EOPNOTSUPP;
211 
212 	return parse_esp_ip(uverbs_encap.type,
213 			    u64_to_user_ptr(uverbs_encap.val_ptr),
214 			    uverbs_encap.len,
215 			    &out->spec);
216 }
217 
218 struct ib_flow_action_esp_attr {
219 	struct	ib_flow_action_attrs_esp		hdr;
220 	struct	ib_flow_action_attrs_esp_keymats	keymat;
221 	struct	ib_flow_action_attrs_esp_replays	replay;
222 	/* We currently support only one spec */
223 	struct	ib_flow_spec_list			encap;
224 };
225 
226 #define ESP_LAST_SUPPORTED_FLAG		IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ESN_NEW_WINDOW
parse_flow_action_esp(struct ib_device * ib_dev,struct uverbs_attr_bundle * attrs,struct ib_flow_action_esp_attr * esp_attr,bool is_modify)227 static int parse_flow_action_esp(struct ib_device *ib_dev,
228 				 struct uverbs_attr_bundle *attrs,
229 				 struct ib_flow_action_esp_attr *esp_attr,
230 				 bool is_modify)
231 {
232 	struct ib_uverbs_flow_action_esp uverbs_esp = {};
233 	int ret;
234 
235 	/* Optional param, if it doesn't exist, we get -ENOENT and skip it */
236 	ret = uverbs_copy_from(&esp_attr->hdr.esn, attrs,
237 			       UVERBS_ATTR_FLOW_ACTION_ESP_ESN);
238 	if (IS_UVERBS_COPY_ERR(ret))
239 		return ret;
240 
241 	/* This can be called from FLOW_ACTION_ESP_MODIFY where
242 	 * UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS is optional
243 	 */
244 	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS)) {
245 		ret = uverbs_copy_from_or_zero(&uverbs_esp, attrs,
246 					       UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS);
247 		if (ret)
248 			return ret;
249 
250 		if (uverbs_esp.flags & ~((ESP_LAST_SUPPORTED_FLAG << 1) - 1))
251 			return -EOPNOTSUPP;
252 
253 		esp_attr->hdr.spi = uverbs_esp.spi;
254 		esp_attr->hdr.seq = uverbs_esp.seq;
255 		esp_attr->hdr.tfc_pad = uverbs_esp.tfc_pad;
256 		esp_attr->hdr.hard_limit_pkts = uverbs_esp.hard_limit_pkts;
257 	}
258 	esp_attr->hdr.flags = esp_flags_uverbs_to_verbs(attrs, uverbs_esp.flags,
259 							is_modify);
260 
261 	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT)) {
262 		esp_attr->keymat.protocol =
263 			uverbs_attr_get_enum_id(attrs,
264 						UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT);
265 		ret = uverbs_copy_from_or_zero(&esp_attr->keymat.keymat,
266 					       attrs,
267 					       UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT);
268 		if (ret)
269 			return ret;
270 
271 		ret = flow_action_esp_keymat_validate[esp_attr->keymat.protocol](&esp_attr->keymat);
272 		if (ret)
273 			return ret;
274 
275 		esp_attr->hdr.keymat = &esp_attr->keymat;
276 	}
277 
278 	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY)) {
279 		esp_attr->replay.protocol =
280 			uverbs_attr_get_enum_id(attrs,
281 						UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY);
282 
283 		ret = uverbs_copy_from_or_zero(&esp_attr->replay.replay,
284 					       attrs,
285 					       UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY);
286 		if (ret)
287 			return ret;
288 
289 		ret = flow_action_esp_replay_validate[esp_attr->replay.protocol](&esp_attr->replay,
290 										 is_modify);
291 		if (ret)
292 			return ret;
293 
294 		esp_attr->hdr.replay = &esp_attr->replay;
295 	}
296 
297 	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP)) {
298 		ret = flow_action_esp_get_encap(&esp_attr->encap, attrs);
299 		if (ret)
300 			return ret;
301 
302 		esp_attr->hdr.encap = &esp_attr->encap;
303 	}
304 
305 	return 0;
306 }
307 
UVERBS_HANDLER(UVERBS_METHOD_FLOW_ACTION_ESP_CREATE)308 static int UVERBS_HANDLER(UVERBS_METHOD_FLOW_ACTION_ESP_CREATE)(
309 	struct uverbs_attr_bundle *attrs)
310 {
311 	struct ib_uobject *uobj = uverbs_attr_get_uobject(
312 		attrs, UVERBS_ATTR_CREATE_FLOW_ACTION_ESP_HANDLE);
313 	struct ib_device *ib_dev = attrs->context->device;
314 	int				  ret;
315 	struct ib_flow_action		  *action;
316 	struct ib_flow_action_esp_attr	  esp_attr = {};
317 
318 	if (!ib_dev->create_flow_action_esp)
319 		return -EOPNOTSUPP;
320 
321 	ret = parse_flow_action_esp(ib_dev, attrs, &esp_attr, false);
322 	if (ret)
323 		return ret;
324 
325 	/* No need to check as this attribute is marked as MANDATORY */
326 	action = ib_dev->create_flow_action_esp(ib_dev, &esp_attr.hdr,
327 						    attrs);
328 	if (IS_ERR(action))
329 		return PTR_ERR(action);
330 
331 	uverbs_flow_action_fill_action(action, uobj, ib_dev,
332 				       IB_FLOW_ACTION_ESP);
333 
334 	return 0;
335 }
336 
UVERBS_HANDLER(UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY)337 static int UVERBS_HANDLER(UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY)(
338 	struct uverbs_attr_bundle *attrs)
339 {
340 	struct ib_uobject *uobj = uverbs_attr_get_uobject(
341 		attrs, UVERBS_ATTR_MODIFY_FLOW_ACTION_ESP_HANDLE);
342 	struct ib_flow_action *action = uobj->object;
343 	int				  ret;
344 	struct ib_flow_action_esp_attr	  esp_attr = {};
345 
346 	if (!action->device->modify_flow_action_esp)
347 		return -EOPNOTSUPP;
348 
349 	ret = parse_flow_action_esp(action->device, attrs, &esp_attr, true);
350 	if (ret)
351 		return ret;
352 
353 	if (action->type != IB_FLOW_ACTION_ESP)
354 		return -EINVAL;
355 
356 	return action->device->modify_flow_action_esp(action,
357 							  &esp_attr.hdr,
358 							  attrs);
359 }
360 
361 static const struct uverbs_attr_spec uverbs_flow_action_esp_keymat[] = {
362 	[IB_UVERBS_FLOW_ACTION_ESP_KEYMAT_AES_GCM] = {
363 		.type = UVERBS_ATTR_TYPE_PTR_IN,
364 		UVERBS_ATTR_STRUCT(
365 			struct ib_uverbs_flow_action_esp_keymat_aes_gcm,
366 			aes_key),
367 	},
368 };
369 
370 static const struct uverbs_attr_spec uverbs_flow_action_esp_replay[] = {
371 	[IB_UVERBS_FLOW_ACTION_ESP_REPLAY_NONE] = {
372 		.type = UVERBS_ATTR_TYPE_PTR_IN,
373 		UVERBS_ATTR_NO_DATA(),
374 	},
375 	[IB_UVERBS_FLOW_ACTION_ESP_REPLAY_BMP] = {
376 		.type = UVERBS_ATTR_TYPE_PTR_IN,
377 		UVERBS_ATTR_STRUCT(struct ib_uverbs_flow_action_esp_replay_bmp,
378 				   size),
379 	},
380 };
381 
382 DECLARE_UVERBS_NAMED_METHOD(
383 	UVERBS_METHOD_FLOW_ACTION_ESP_CREATE,
384 	UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_FLOW_ACTION_ESP_HANDLE,
385 			UVERBS_OBJECT_FLOW_ACTION,
386 			UVERBS_ACCESS_NEW,
387 			UA_MANDATORY),
388 	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS,
389 			   UVERBS_ATTR_STRUCT(struct ib_uverbs_flow_action_esp,
390 					      hard_limit_pkts),
391 			   UA_MANDATORY),
392 	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ESN,
393 			   UVERBS_ATTR_TYPE(__u32),
394 			   UA_OPTIONAL),
395 	UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT,
396 			    uverbs_flow_action_esp_keymat,
397 			    UA_MANDATORY),
398 	UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY,
399 			    uverbs_flow_action_esp_replay,
400 			    UA_OPTIONAL),
401 	UVERBS_ATTR_PTR_IN(
402 		UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP,
403 		UVERBS_ATTR_TYPE(struct ib_uverbs_flow_action_esp_encap),
404 		UA_OPTIONAL));
405 
406 DECLARE_UVERBS_NAMED_METHOD(
407 	UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY,
408 	UVERBS_ATTR_IDR(UVERBS_ATTR_MODIFY_FLOW_ACTION_ESP_HANDLE,
409 			UVERBS_OBJECT_FLOW_ACTION,
410 			UVERBS_ACCESS_WRITE,
411 			UA_MANDATORY),
412 	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS,
413 			   UVERBS_ATTR_STRUCT(struct ib_uverbs_flow_action_esp,
414 					      hard_limit_pkts),
415 			   UA_OPTIONAL),
416 	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ESN,
417 			   UVERBS_ATTR_TYPE(__u32),
418 			   UA_OPTIONAL),
419 	UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT,
420 			    uverbs_flow_action_esp_keymat,
421 			    UA_OPTIONAL),
422 	UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY,
423 			    uverbs_flow_action_esp_replay,
424 			    UA_OPTIONAL),
425 	UVERBS_ATTR_PTR_IN(
426 		UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP,
427 		UVERBS_ATTR_TYPE(struct ib_uverbs_flow_action_esp_encap),
428 		UA_OPTIONAL));
429 
430 DECLARE_UVERBS_NAMED_METHOD_DESTROY(
431 	UVERBS_METHOD_FLOW_ACTION_DESTROY,
432 	UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_FLOW_ACTION_HANDLE,
433 			UVERBS_OBJECT_FLOW_ACTION,
434 			UVERBS_ACCESS_DESTROY,
435 			UA_MANDATORY));
436 
437 DECLARE_UVERBS_NAMED_OBJECT(
438 	UVERBS_OBJECT_FLOW_ACTION,
439 	UVERBS_TYPE_ALLOC_IDR(uverbs_free_flow_action),
440 	&UVERBS_METHOD(UVERBS_METHOD_FLOW_ACTION_ESP_CREATE),
441 	&UVERBS_METHOD(UVERBS_METHOD_FLOW_ACTION_DESTROY),
442 	&UVERBS_METHOD(UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY));
443 
444 const struct uapi_definition uverbs_def_obj_flow_action[] = {
445 	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(
446 		UVERBS_OBJECT_FLOW_ACTION,
447 		UAPI_DEF_OBJ_NEEDS_FN(destroy_flow_action)),
448 	{}
449 };
450