xref: /linux/drivers/infiniband/core/uverbs_std_types_flow_action.c (revision 164666fa66669d437bdcc8d5f1744a2aee73be41)
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 
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 
43 	if (atomic_read(&action->usecnt))
44 		return -EBUSY;
45 
46 	return action->device->ops.destroy_flow_action(action);
47 }
48 
49 static u64 esp_flags_uverbs_to_verbs(struct uverbs_attr_bundle *attrs,
50 				     u32 flags, bool is_modify)
51 {
52 	u64 verbs_flags = flags;
53 
54 	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_ESN))
55 		verbs_flags |= IB_FLOW_ACTION_ESP_FLAGS_ESN_TRIGGERED;
56 
57 	if (is_modify && uverbs_attr_is_valid(attrs,
58 					      UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS))
59 		verbs_flags |= IB_FLOW_ACTION_ESP_FLAGS_MOD_ESP_ATTRS;
60 
61 	return verbs_flags;
62 };
63 
64 static int validate_flow_action_esp_keymat_aes_gcm(struct ib_flow_action_attrs_esp_keymats *keymat)
65 {
66 	struct ib_uverbs_flow_action_esp_keymat_aes_gcm *aes_gcm =
67 		&keymat->keymat.aes_gcm;
68 
69 	if (aes_gcm->iv_algo > IB_UVERBS_FLOW_ACTION_IV_ALGO_SEQ)
70 		return -EOPNOTSUPP;
71 
72 	if (aes_gcm->key_len != 32 &&
73 	    aes_gcm->key_len != 24 &&
74 	    aes_gcm->key_len != 16)
75 		return -EINVAL;
76 
77 	if (aes_gcm->icv_len != 16 &&
78 	    aes_gcm->icv_len != 8 &&
79 	    aes_gcm->icv_len != 12)
80 		return -EINVAL;
81 
82 	return 0;
83 }
84 
85 static int (* const flow_action_esp_keymat_validate[])(struct ib_flow_action_attrs_esp_keymats *keymat) = {
86 	[IB_UVERBS_FLOW_ACTION_ESP_KEYMAT_AES_GCM] = validate_flow_action_esp_keymat_aes_gcm,
87 };
88 
89 static int flow_action_esp_replay_none(struct ib_flow_action_attrs_esp_replays *replay,
90 				       bool is_modify)
91 {
92 	/* This is used in order to modify an esp flow action with an enabled
93 	 * replay protection to a disabled one. This is only supported via
94 	 * modify, as in create verb we can simply drop the REPLAY attribute and
95 	 * achieve the same thing.
96 	 */
97 	return is_modify ? 0 : -EINVAL;
98 }
99 
100 static int flow_action_esp_replay_def_ok(struct ib_flow_action_attrs_esp_replays *replay,
101 					 bool is_modify)
102 {
103 	/* Some replay protections could always be enabled without validating
104 	 * anything.
105 	 */
106 	return 0;
107 }
108 
109 static int (* const flow_action_esp_replay_validate[])(struct ib_flow_action_attrs_esp_replays *replay,
110 						       bool is_modify) = {
111 	[IB_UVERBS_FLOW_ACTION_ESP_REPLAY_NONE] = flow_action_esp_replay_none,
112 	[IB_UVERBS_FLOW_ACTION_ESP_REPLAY_BMP] = flow_action_esp_replay_def_ok,
113 };
114 
115 static int parse_esp_ip(enum ib_flow_spec_type proto,
116 			const void __user *val_ptr,
117 			size_t len, union ib_flow_spec *out)
118 {
119 	int ret;
120 	const struct ib_uverbs_flow_ipv4_filter ipv4 = {
121 		.src_ip = cpu_to_be32(0xffffffffUL),
122 		.dst_ip = cpu_to_be32(0xffffffffUL),
123 		.proto = 0xff,
124 		.tos = 0xff,
125 		.ttl = 0xff,
126 		.flags = 0xff,
127 	};
128 	const struct ib_uverbs_flow_ipv6_filter ipv6 = {
129 		.src_ip = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
130 			   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
131 		.dst_ip = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
132 			   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
133 		.flow_label = cpu_to_be32(0xffffffffUL),
134 		.next_hdr = 0xff,
135 		.traffic_class = 0xff,
136 		.hop_limit = 0xff,
137 	};
138 	union {
139 		struct ib_uverbs_flow_ipv4_filter ipv4;
140 		struct ib_uverbs_flow_ipv6_filter ipv6;
141 	} user_val = {};
142 	const void *user_pmask;
143 	size_t val_len;
144 
145 	/* If the flow IPv4/IPv6 flow specifications are extended, the mask
146 	 * should be changed as well.
147 	 */
148 	BUILD_BUG_ON(offsetof(struct ib_uverbs_flow_ipv4_filter, flags) +
149 		     sizeof(ipv4.flags) != sizeof(ipv4));
150 	BUILD_BUG_ON(offsetof(struct ib_uverbs_flow_ipv6_filter, reserved) +
151 		     sizeof(ipv6.reserved) != sizeof(ipv6));
152 
153 	switch (proto) {
154 	case IB_FLOW_SPEC_IPV4:
155 		if (len > sizeof(user_val.ipv4) &&
156 		    !ib_is_buffer_cleared(val_ptr + sizeof(user_val.ipv4),
157 					  len - sizeof(user_val.ipv4)))
158 			return -EOPNOTSUPP;
159 
160 		val_len = min_t(size_t, len, sizeof(user_val.ipv4));
161 		ret = copy_from_user(&user_val.ipv4, val_ptr,
162 				     val_len);
163 		if (ret)
164 			return -EFAULT;
165 
166 		user_pmask = &ipv4;
167 		break;
168 	case IB_FLOW_SPEC_IPV6:
169 		if (len > sizeof(user_val.ipv6) &&
170 		    !ib_is_buffer_cleared(val_ptr + sizeof(user_val.ipv6),
171 					  len - sizeof(user_val.ipv6)))
172 			return -EOPNOTSUPP;
173 
174 		val_len = min_t(size_t, len, sizeof(user_val.ipv6));
175 		ret = copy_from_user(&user_val.ipv6, val_ptr,
176 				     val_len);
177 		if (ret)
178 			return -EFAULT;
179 
180 		user_pmask = &ipv6;
181 		break;
182 	default:
183 		return -EOPNOTSUPP;
184 	}
185 
186 	return ib_uverbs_kern_spec_to_ib_spec_filter(proto, user_pmask,
187 						     &user_val,
188 						     val_len, out);
189 }
190 
191 static int flow_action_esp_get_encap(struct ib_flow_spec_list *out,
192 				     struct uverbs_attr_bundle *attrs)
193 {
194 	struct ib_uverbs_flow_action_esp_encap uverbs_encap;
195 	int ret;
196 
197 	ret = uverbs_copy_from(&uverbs_encap, attrs,
198 			       UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP);
199 	if (ret)
200 		return ret;
201 
202 	/* We currently support only one encap */
203 	if (uverbs_encap.next_ptr)
204 		return -EOPNOTSUPP;
205 
206 	if (uverbs_encap.type != IB_FLOW_SPEC_IPV4 &&
207 	    uverbs_encap.type != IB_FLOW_SPEC_IPV6)
208 		return -EOPNOTSUPP;
209 
210 	return parse_esp_ip(uverbs_encap.type,
211 			    u64_to_user_ptr(uverbs_encap.val_ptr),
212 			    uverbs_encap.len,
213 			    &out->spec);
214 }
215 
216 struct ib_flow_action_esp_attr {
217 	struct	ib_flow_action_attrs_esp		hdr;
218 	struct	ib_flow_action_attrs_esp_keymats	keymat;
219 	struct	ib_flow_action_attrs_esp_replays	replay;
220 	/* We currently support only one spec */
221 	struct	ib_flow_spec_list			encap;
222 };
223 
224 #define ESP_LAST_SUPPORTED_FLAG		IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ESN_NEW_WINDOW
225 static int parse_flow_action_esp(struct ib_device *ib_dev,
226 				 struct uverbs_attr_bundle *attrs,
227 				 struct ib_flow_action_esp_attr *esp_attr,
228 				 bool is_modify)
229 {
230 	struct ib_uverbs_flow_action_esp uverbs_esp = {};
231 	int ret;
232 
233 	/* Optional param, if it doesn't exist, we get -ENOENT and skip it */
234 	ret = uverbs_copy_from(&esp_attr->hdr.esn, attrs,
235 			       UVERBS_ATTR_FLOW_ACTION_ESP_ESN);
236 	if (IS_UVERBS_COPY_ERR(ret))
237 		return ret;
238 
239 	/* This can be called from FLOW_ACTION_ESP_MODIFY where
240 	 * UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS is optional
241 	 */
242 	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS)) {
243 		ret = uverbs_copy_from_or_zero(&uverbs_esp, attrs,
244 					       UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS);
245 		if (ret)
246 			return ret;
247 
248 		if (uverbs_esp.flags & ~((ESP_LAST_SUPPORTED_FLAG << 1) - 1))
249 			return -EOPNOTSUPP;
250 
251 		esp_attr->hdr.spi = uverbs_esp.spi;
252 		esp_attr->hdr.seq = uverbs_esp.seq;
253 		esp_attr->hdr.tfc_pad = uverbs_esp.tfc_pad;
254 		esp_attr->hdr.hard_limit_pkts = uverbs_esp.hard_limit_pkts;
255 	}
256 	esp_attr->hdr.flags = esp_flags_uverbs_to_verbs(attrs, uverbs_esp.flags,
257 							is_modify);
258 
259 	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT)) {
260 		esp_attr->keymat.protocol =
261 			uverbs_attr_get_enum_id(attrs,
262 						UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT);
263 		ret = uverbs_copy_from_or_zero(&esp_attr->keymat.keymat,
264 					       attrs,
265 					       UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT);
266 		if (ret)
267 			return ret;
268 
269 		ret = flow_action_esp_keymat_validate[esp_attr->keymat.protocol](&esp_attr->keymat);
270 		if (ret)
271 			return ret;
272 
273 		esp_attr->hdr.keymat = &esp_attr->keymat;
274 	}
275 
276 	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY)) {
277 		esp_attr->replay.protocol =
278 			uverbs_attr_get_enum_id(attrs,
279 						UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY);
280 
281 		ret = uverbs_copy_from_or_zero(&esp_attr->replay.replay,
282 					       attrs,
283 					       UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY);
284 		if (ret)
285 			return ret;
286 
287 		ret = flow_action_esp_replay_validate[esp_attr->replay.protocol](&esp_attr->replay,
288 										 is_modify);
289 		if (ret)
290 			return ret;
291 
292 		esp_attr->hdr.replay = &esp_attr->replay;
293 	}
294 
295 	if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP)) {
296 		ret = flow_action_esp_get_encap(&esp_attr->encap, attrs);
297 		if (ret)
298 			return ret;
299 
300 		esp_attr->hdr.encap = &esp_attr->encap;
301 	}
302 
303 	return 0;
304 }
305 
306 static int UVERBS_HANDLER(UVERBS_METHOD_FLOW_ACTION_ESP_CREATE)(
307 	struct uverbs_attr_bundle *attrs)
308 {
309 	struct ib_uobject *uobj = uverbs_attr_get_uobject(
310 		attrs, UVERBS_ATTR_CREATE_FLOW_ACTION_ESP_HANDLE);
311 	struct ib_device *ib_dev = attrs->context->device;
312 	int				  ret;
313 	struct ib_flow_action		  *action;
314 	struct ib_flow_action_esp_attr	  esp_attr = {};
315 
316 	if (!ib_dev->ops.create_flow_action_esp)
317 		return -EOPNOTSUPP;
318 
319 	ret = parse_flow_action_esp(ib_dev, attrs, &esp_attr, false);
320 	if (ret)
321 		return ret;
322 
323 	/* No need to check as this attribute is marked as MANDATORY */
324 	action = ib_dev->ops.create_flow_action_esp(ib_dev, &esp_attr.hdr,
325 						    attrs);
326 	if (IS_ERR(action))
327 		return PTR_ERR(action);
328 
329 	uverbs_flow_action_fill_action(action, uobj, ib_dev,
330 				       IB_FLOW_ACTION_ESP);
331 
332 	return 0;
333 }
334 
335 static int UVERBS_HANDLER(UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY)(
336 	struct uverbs_attr_bundle *attrs)
337 {
338 	struct ib_uobject *uobj = uverbs_attr_get_uobject(
339 		attrs, UVERBS_ATTR_MODIFY_FLOW_ACTION_ESP_HANDLE);
340 	struct ib_flow_action *action = uobj->object;
341 	int				  ret;
342 	struct ib_flow_action_esp_attr	  esp_attr = {};
343 
344 	if (!action->device->ops.modify_flow_action_esp)
345 		return -EOPNOTSUPP;
346 
347 	ret = parse_flow_action_esp(action->device, attrs, &esp_attr, true);
348 	if (ret)
349 		return ret;
350 
351 	if (action->type != IB_FLOW_ACTION_ESP)
352 		return -EINVAL;
353 
354 	return action->device->ops.modify_flow_action_esp(action,
355 							  &esp_attr.hdr,
356 							  attrs);
357 }
358 
359 static const struct uverbs_attr_spec uverbs_flow_action_esp_keymat[] = {
360 	[IB_UVERBS_FLOW_ACTION_ESP_KEYMAT_AES_GCM] = {
361 		.type = UVERBS_ATTR_TYPE_PTR_IN,
362 		UVERBS_ATTR_STRUCT(
363 			struct ib_uverbs_flow_action_esp_keymat_aes_gcm,
364 			aes_key),
365 	},
366 };
367 
368 static const struct uverbs_attr_spec uverbs_flow_action_esp_replay[] = {
369 	[IB_UVERBS_FLOW_ACTION_ESP_REPLAY_NONE] = {
370 		.type = UVERBS_ATTR_TYPE_PTR_IN,
371 		UVERBS_ATTR_NO_DATA(),
372 	},
373 	[IB_UVERBS_FLOW_ACTION_ESP_REPLAY_BMP] = {
374 		.type = UVERBS_ATTR_TYPE_PTR_IN,
375 		UVERBS_ATTR_STRUCT(struct ib_uverbs_flow_action_esp_replay_bmp,
376 				   size),
377 	},
378 };
379 
380 DECLARE_UVERBS_NAMED_METHOD(
381 	UVERBS_METHOD_FLOW_ACTION_ESP_CREATE,
382 	UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_FLOW_ACTION_ESP_HANDLE,
383 			UVERBS_OBJECT_FLOW_ACTION,
384 			UVERBS_ACCESS_NEW,
385 			UA_MANDATORY),
386 	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS,
387 			   UVERBS_ATTR_STRUCT(struct ib_uverbs_flow_action_esp,
388 					      hard_limit_pkts),
389 			   UA_MANDATORY),
390 	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ESN,
391 			   UVERBS_ATTR_TYPE(__u32),
392 			   UA_OPTIONAL),
393 	UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT,
394 			    uverbs_flow_action_esp_keymat,
395 			    UA_MANDATORY),
396 	UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY,
397 			    uverbs_flow_action_esp_replay,
398 			    UA_OPTIONAL),
399 	UVERBS_ATTR_PTR_IN(
400 		UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP,
401 		UVERBS_ATTR_TYPE(struct ib_uverbs_flow_action_esp_encap),
402 		UA_OPTIONAL));
403 
404 DECLARE_UVERBS_NAMED_METHOD(
405 	UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY,
406 	UVERBS_ATTR_IDR(UVERBS_ATTR_MODIFY_FLOW_ACTION_ESP_HANDLE,
407 			UVERBS_OBJECT_FLOW_ACTION,
408 			UVERBS_ACCESS_WRITE,
409 			UA_MANDATORY),
410 	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS,
411 			   UVERBS_ATTR_STRUCT(struct ib_uverbs_flow_action_esp,
412 					      hard_limit_pkts),
413 			   UA_OPTIONAL),
414 	UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ESN,
415 			   UVERBS_ATTR_TYPE(__u32),
416 			   UA_OPTIONAL),
417 	UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT,
418 			    uverbs_flow_action_esp_keymat,
419 			    UA_OPTIONAL),
420 	UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY,
421 			    uverbs_flow_action_esp_replay,
422 			    UA_OPTIONAL),
423 	UVERBS_ATTR_PTR_IN(
424 		UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP,
425 		UVERBS_ATTR_TYPE(struct ib_uverbs_flow_action_esp_encap),
426 		UA_OPTIONAL));
427 
428 DECLARE_UVERBS_NAMED_METHOD_DESTROY(
429 	UVERBS_METHOD_FLOW_ACTION_DESTROY,
430 	UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_FLOW_ACTION_HANDLE,
431 			UVERBS_OBJECT_FLOW_ACTION,
432 			UVERBS_ACCESS_DESTROY,
433 			UA_MANDATORY));
434 
435 DECLARE_UVERBS_NAMED_OBJECT(
436 	UVERBS_OBJECT_FLOW_ACTION,
437 	UVERBS_TYPE_ALLOC_IDR(uverbs_free_flow_action),
438 	&UVERBS_METHOD(UVERBS_METHOD_FLOW_ACTION_ESP_CREATE),
439 	&UVERBS_METHOD(UVERBS_METHOD_FLOW_ACTION_DESTROY),
440 	&UVERBS_METHOD(UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY));
441 
442 const struct uapi_definition uverbs_def_obj_flow_action[] = {
443 	UAPI_DEF_CHAIN_OBJ_TREE_NAMED(
444 		UVERBS_OBJECT_FLOW_ACTION,
445 		UAPI_DEF_OBJ_NEEDS_FN(destroy_flow_action)),
446 	{}
447 };
448