xref: /dpdk/lib/security/rte_security.c (revision 7e06c0de1952d3109a5b0c4779d7e7d8059c9d78)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2017 NXP.
3  * Copyright(c) 2017 Intel Corporation.
4  * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
5  */
6 
7 #include <stdalign.h>
8 #include <ctype.h>
9 #include <stdlib.h>
10 
11 #include <rte_cryptodev.h>
12 #include <dev_driver.h>
13 #include <rte_telemetry.h>
14 #include "rte_security.h"
15 #include "rte_security_driver.h"
16 
17 /* Macro to check for invalid pointers */
18 #define RTE_PTR_OR_ERR_RET(ptr, retval) do {	\
19 	if ((ptr) == NULL)			\
20 		return retval;			\
21 } while (0)
22 
23 /* Macro to check for invalid pointers chains */
24 #define RTE_PTR_CHAIN3_OR_ERR_RET(p1, p2, p3, retval, last_retval) do {	\
25 	RTE_PTR_OR_ERR_RET(p1, retval);					\
26 	RTE_PTR_OR_ERR_RET(p1->p2, retval);				\
27 	RTE_PTR_OR_ERR_RET(p1->p2->p3, last_retval);			\
28 } while (0)
29 
30 #define RTE_SECURITY_DYNFIELD_NAME "rte_security_dynfield_metadata"
31 #define RTE_SECURITY_OOP_DYNFIELD_NAME "rte_security_oop_dynfield_metadata"
32 
33 int rte_security_dynfield_offset = -1;
34 int rte_security_oop_dynfield_offset = -1;
35 
36 int
37 rte_security_dynfield_register(void)
38 {
39 	static const struct rte_mbuf_dynfield dynfield_desc = {
40 		.name = RTE_SECURITY_DYNFIELD_NAME,
41 		.size = sizeof(rte_security_dynfield_t),
42 		.align = alignof(rte_security_dynfield_t),
43 	};
44 	rte_security_dynfield_offset =
45 		rte_mbuf_dynfield_register(&dynfield_desc);
46 	return rte_security_dynfield_offset;
47 }
48 
49 int
50 rte_security_oop_dynfield_register(void)
51 {
52 	static const struct rte_mbuf_dynfield dynfield_desc = {
53 		.name = RTE_SECURITY_OOP_DYNFIELD_NAME,
54 		.size = sizeof(rte_security_oop_dynfield_t),
55 		.align = alignof(rte_security_oop_dynfield_t),
56 	};
57 
58 	rte_security_oop_dynfield_offset =
59 		rte_mbuf_dynfield_register(&dynfield_desc);
60 	return rte_security_oop_dynfield_offset;
61 }
62 
63 void *
64 rte_security_session_create(void *ctx,
65 			    struct rte_security_session_conf *conf,
66 			    struct rte_mempool *mp)
67 {
68 	struct rte_security_session *sess = NULL;
69 	struct rte_security_ctx *instance = ctx;
70 	uint32_t sess_priv_size;
71 
72 	RTE_PTR_CHAIN3_OR_ERR_RET(instance, ops, session_create, NULL, NULL);
73 	RTE_PTR_OR_ERR_RET(conf, NULL);
74 	RTE_PTR_OR_ERR_RET(mp, NULL);
75 
76 	sess_priv_size = instance->ops->session_get_size(instance->device);
77 	if (mp->elt_size < (sizeof(struct rte_security_session) + sess_priv_size))
78 		return NULL;
79 
80 	if (rte_mempool_get(mp, (void **)&sess))
81 		return NULL;
82 
83 	/* Clear session priv data */
84 	memset(sess->driver_priv_data, 0, sess_priv_size);
85 
86 	sess->driver_priv_data_iova = rte_mempool_virt2iova(sess) +
87 			offsetof(struct rte_security_session, driver_priv_data);
88 	if (instance->ops->session_create(instance->device, conf, sess)) {
89 		rte_mempool_put(mp, (void *)sess);
90 		return NULL;
91 	}
92 	instance->sess_cnt++;
93 
94 	return (void *)sess;
95 }
96 
97 int
98 rte_security_session_update(void *ctx, void *sess, struct rte_security_session_conf *conf)
99 {
100 	struct rte_security_ctx *instance = ctx;
101 
102 	RTE_PTR_CHAIN3_OR_ERR_RET(instance, ops, session_update, -EINVAL,
103 			-ENOTSUP);
104 	RTE_PTR_OR_ERR_RET(sess, -EINVAL);
105 	RTE_PTR_OR_ERR_RET(conf, -EINVAL);
106 
107 	return instance->ops->session_update(instance->device, sess, conf);
108 }
109 
110 unsigned int
111 rte_security_session_get_size(void *ctx)
112 {
113 	struct rte_security_ctx *instance = ctx;
114 
115 	RTE_PTR_CHAIN3_OR_ERR_RET(instance, ops, session_get_size, 0, 0);
116 
117 	return (sizeof(struct rte_security_session) +
118 			instance->ops->session_get_size(instance->device));
119 }
120 
121 int
122 rte_security_session_stats_get(void *ctx, void *sess, struct rte_security_stats *stats)
123 {
124 	struct rte_security_ctx *instance = ctx;
125 
126 	RTE_PTR_CHAIN3_OR_ERR_RET(instance, ops, session_stats_get, -EINVAL,
127 			-ENOTSUP);
128 	/* Parameter sess can be NULL in case of getting global statistics. */
129 	RTE_PTR_OR_ERR_RET(stats, -EINVAL);
130 
131 	return instance->ops->session_stats_get(instance->device, sess, stats);
132 }
133 
134 int
135 rte_security_session_destroy(void *ctx, void *sess)
136 {
137 	struct rte_security_ctx *instance = ctx;
138 	int ret;
139 
140 	RTE_PTR_CHAIN3_OR_ERR_RET(instance, ops, session_destroy, -EINVAL,
141 			-ENOTSUP);
142 	RTE_PTR_OR_ERR_RET(sess, -EINVAL);
143 
144 	ret = instance->ops->session_destroy(instance->device, sess);
145 	if (ret != 0)
146 		return ret;
147 
148 	rte_mempool_put(rte_mempool_from_obj(sess), (void *)sess);
149 
150 	if (instance->sess_cnt)
151 		instance->sess_cnt--;
152 
153 	return 0;
154 }
155 
156 int
157 rte_security_macsec_sc_create(void *ctx, struct rte_security_macsec_sc *conf)
158 {
159 	struct rte_security_ctx *instance = ctx;
160 	int sc_id;
161 
162 	RTE_PTR_CHAIN3_OR_ERR_RET(instance, ops, macsec_sc_create, -EINVAL, -ENOTSUP);
163 	RTE_PTR_OR_ERR_RET(conf, -EINVAL);
164 
165 	sc_id = instance->ops->macsec_sc_create(instance->device, conf);
166 	if (sc_id >= 0)
167 		instance->macsec_sc_cnt++;
168 
169 	return sc_id;
170 }
171 
172 int
173 rte_security_macsec_sa_create(void *ctx, struct rte_security_macsec_sa *conf)
174 {
175 	struct rte_security_ctx *instance = ctx;
176 	int sa_id;
177 
178 	RTE_PTR_CHAIN3_OR_ERR_RET(instance, ops, macsec_sa_create, -EINVAL, -ENOTSUP);
179 	RTE_PTR_OR_ERR_RET(conf, -EINVAL);
180 
181 	sa_id = instance->ops->macsec_sa_create(instance->device, conf);
182 	if (sa_id >= 0)
183 		instance->macsec_sa_cnt++;
184 
185 	return sa_id;
186 }
187 
188 int
189 rte_security_macsec_sc_destroy(void *ctx, uint16_t sc_id,
190 			       enum rte_security_macsec_direction dir)
191 {
192 	struct rte_security_ctx *instance = ctx;
193 	int ret;
194 
195 	RTE_PTR_CHAIN3_OR_ERR_RET(instance, ops, macsec_sc_destroy, -EINVAL, -ENOTSUP);
196 
197 	ret = instance->ops->macsec_sc_destroy(instance->device, sc_id, dir);
198 	if (ret != 0)
199 		return ret;
200 
201 	if (instance->macsec_sc_cnt)
202 		instance->macsec_sc_cnt--;
203 
204 	return 0;
205 }
206 
207 int
208 rte_security_macsec_sa_destroy(void *ctx, uint16_t sa_id,
209 			       enum rte_security_macsec_direction dir)
210 {
211 	struct rte_security_ctx *instance = ctx;
212 	int ret;
213 
214 	RTE_PTR_CHAIN3_OR_ERR_RET(instance, ops, macsec_sa_destroy, -EINVAL, -ENOTSUP);
215 
216 	ret = instance->ops->macsec_sa_destroy(instance->device, sa_id, dir);
217 	if (ret != 0)
218 		return ret;
219 
220 	if (instance->macsec_sa_cnt)
221 		instance->macsec_sa_cnt--;
222 
223 	return 0;
224 }
225 
226 int
227 rte_security_macsec_sc_stats_get(void *ctx, uint16_t sc_id,
228 				 enum rte_security_macsec_direction dir,
229 				 struct rte_security_macsec_sc_stats *stats)
230 {
231 	struct rte_security_ctx *instance = ctx;
232 
233 	RTE_PTR_CHAIN3_OR_ERR_RET(instance, ops, macsec_sc_stats_get, -EINVAL, -ENOTSUP);
234 	RTE_PTR_OR_ERR_RET(stats, -EINVAL);
235 
236 	return instance->ops->macsec_sc_stats_get(instance->device, sc_id, dir, stats);
237 }
238 
239 int
240 rte_security_macsec_sa_stats_get(void *ctx, uint16_t sa_id,
241 				 enum rte_security_macsec_direction dir,
242 				 struct rte_security_macsec_sa_stats *stats)
243 {
244 	struct rte_security_ctx *instance = ctx;
245 
246 	RTE_PTR_CHAIN3_OR_ERR_RET(instance, ops, macsec_sa_stats_get, -EINVAL, -ENOTSUP);
247 	RTE_PTR_OR_ERR_RET(stats, -EINVAL);
248 
249 	return instance->ops->macsec_sa_stats_get(instance->device, sa_id, dir, stats);
250 }
251 
252 int
253 __rte_security_set_pkt_metadata(void *ctx, void *sess, struct rte_mbuf *m, void *params)
254 {
255 	struct rte_security_ctx *instance = ctx;
256 #ifdef RTE_DEBUG
257 	RTE_PTR_OR_ERR_RET(sess, -EINVAL);
258 	RTE_PTR_OR_ERR_RET(instance, -EINVAL);
259 	RTE_PTR_OR_ERR_RET(instance->ops, -EINVAL);
260 #endif
261 	if (*instance->ops->set_pkt_metadata == NULL)
262 		return -ENOTSUP;
263 	return instance->ops->set_pkt_metadata(instance->device,
264 					       sess, m, params);
265 }
266 
267 const struct rte_security_capability *
268 rte_security_capabilities_get(void *ctx)
269 {
270 	struct rte_security_ctx *instance = ctx;
271 
272 	RTE_PTR_CHAIN3_OR_ERR_RET(instance, ops, capabilities_get, NULL, NULL);
273 
274 	return instance->ops->capabilities_get(instance->device);
275 }
276 
277 const struct rte_security_capability *
278 rte_security_capability_get(void *ctx, struct rte_security_capability_idx *idx)
279 {
280 	const struct rte_security_capability *capabilities;
281 	const struct rte_security_capability *capability;
282 	struct rte_security_ctx *instance = ctx;
283 	uint16_t i = 0;
284 
285 	RTE_PTR_CHAIN3_OR_ERR_RET(instance, ops, capabilities_get, NULL, NULL);
286 	RTE_PTR_OR_ERR_RET(idx, NULL);
287 
288 	capabilities = instance->ops->capabilities_get(instance->device);
289 
290 	if (capabilities == NULL)
291 		return NULL;
292 
293 	while ((capability = &capabilities[i++])->action
294 			!= RTE_SECURITY_ACTION_TYPE_NONE) {
295 		if (capability->action == idx->action &&
296 				capability->protocol == idx->protocol) {
297 			if (idx->protocol == RTE_SECURITY_PROTOCOL_IPSEC) {
298 				if (capability->ipsec.proto ==
299 						idx->ipsec.proto &&
300 					capability->ipsec.mode ==
301 							idx->ipsec.mode &&
302 					capability->ipsec.direction ==
303 							idx->ipsec.direction)
304 					return capability;
305 			} else if (idx->protocol == RTE_SECURITY_PROTOCOL_PDCP) {
306 				if (capability->pdcp.domain ==
307 							idx->pdcp.domain)
308 					return capability;
309 			} else if (idx->protocol ==
310 						RTE_SECURITY_PROTOCOL_DOCSIS) {
311 				if (capability->docsis.direction ==
312 							idx->docsis.direction)
313 					return capability;
314 			} else if (idx->protocol ==
315 						RTE_SECURITY_PROTOCOL_MACSEC) {
316 				if (idx->macsec.alg == capability->macsec.alg)
317 					return capability;
318 			} else if (idx->protocol == RTE_SECURITY_PROTOCOL_TLS_RECORD) {
319 				if (capability->tls_record.ver == idx->tls_record.ver &&
320 				    capability->tls_record.type == idx->tls_record.type)
321 					return capability;
322 			}
323 		}
324 	}
325 
326 	return NULL;
327 }
328 
329 int
330 rte_security_rx_inject_configure(void *ctx, uint16_t port_id, bool enable)
331 {
332 	struct rte_security_ctx *instance = ctx;
333 
334 	RTE_PTR_OR_ERR_RET(instance, -EINVAL);
335 	RTE_PTR_OR_ERR_RET(instance->ops, -ENOTSUP);
336 	RTE_PTR_OR_ERR_RET(instance->ops->rx_inject_configure, -ENOTSUP);
337 
338 	return instance->ops->rx_inject_configure(instance->device, port_id, enable);
339 }
340 
341 uint16_t
342 rte_security_inb_pkt_rx_inject(void *ctx, struct rte_mbuf **pkts, void **sess,
343 			       uint16_t nb_pkts)
344 {
345 	struct rte_security_ctx *instance = ctx;
346 
347 	return instance->ops->inb_pkt_rx_inject(instance->device, pkts,
348 						(struct rte_security_session **)sess, nb_pkts);
349 }
350 
351 static int
352 security_handle_cryptodev_list(const char *cmd __rte_unused,
353 			       const char *params __rte_unused,
354 			       struct rte_tel_data *d)
355 {
356 	int dev_id;
357 
358 	if (rte_cryptodev_count() < 1)
359 		return -1;
360 
361 	rte_tel_data_start_array(d, RTE_TEL_INT_VAL);
362 	for (dev_id = 0; dev_id < RTE_CRYPTO_MAX_DEVS; dev_id++)
363 		if (rte_cryptodev_is_valid_dev(dev_id) &&
364 		    rte_cryptodev_get_sec_ctx(dev_id))
365 			rte_tel_data_add_array_int(d, dev_id);
366 
367 	return 0;
368 }
369 
370 #define CRYPTO_CAPS_SZ                                             \
371 	(RTE_ALIGN_CEIL(sizeof(struct rte_cryptodev_capabilities), \
372 			sizeof(uint64_t)) /	sizeof(uint64_t))
373 
374 static int
375 crypto_caps_array(struct rte_tel_data *d,
376 		  const struct rte_cryptodev_capabilities *capabilities)
377 {
378 	const struct rte_cryptodev_capabilities *dev_caps;
379 	uint64_t caps_val[CRYPTO_CAPS_SZ];
380 	unsigned int i = 0, j;
381 
382 	rte_tel_data_start_array(d, RTE_TEL_UINT_VAL);
383 
384 	while ((dev_caps = &capabilities[i++])->op !=
385 	   RTE_CRYPTO_OP_TYPE_UNDEFINED) {
386 		memset(&caps_val, 0, CRYPTO_CAPS_SZ * sizeof(caps_val[0]));
387 		rte_memcpy(caps_val, dev_caps, sizeof(capabilities[0]));
388 		for (j = 0; j < CRYPTO_CAPS_SZ; j++)
389 			rte_tel_data_add_array_uint(d, caps_val[j]);
390 	}
391 
392 	return (i - 1);
393 }
394 
395 #define SEC_CAPS_SZ						\
396 	(RTE_ALIGN_CEIL(sizeof(struct rte_security_capability), \
397 			sizeof(uint64_t)) /	sizeof(uint64_t))
398 
399 static int
400 sec_caps_array(struct rte_tel_data *d,
401 	       const struct rte_security_capability *capabilities)
402 {
403 	const struct rte_security_capability *dev_caps;
404 	uint64_t caps_val[SEC_CAPS_SZ];
405 	unsigned int i = 0, j;
406 
407 	rte_tel_data_start_array(d, RTE_TEL_UINT_VAL);
408 
409 	while ((dev_caps = &capabilities[i++])->action !=
410 	   RTE_SECURITY_ACTION_TYPE_NONE) {
411 		memset(&caps_val, 0, SEC_CAPS_SZ * sizeof(caps_val[0]));
412 		rte_memcpy(caps_val, dev_caps, sizeof(capabilities[0]));
413 		for (j = 0; j < SEC_CAPS_SZ; j++)
414 			rte_tel_data_add_array_uint(d, caps_val[j]);
415 	}
416 
417 	return i - 1;
418 }
419 
420 static const struct rte_security_capability *
421 security_capability_by_index(const struct rte_security_capability *capabilities,
422 			     int index)
423 {
424 	const struct rte_security_capability *dev_caps = NULL;
425 	int i = 0;
426 
427 	while ((dev_caps = &capabilities[i])->action !=
428 	   RTE_SECURITY_ACTION_TYPE_NONE) {
429 		if (i == index)
430 			return dev_caps;
431 
432 		++i;
433 	}
434 
435 	return NULL;
436 }
437 
438 static int
439 security_capabilities_from_dev_id(int dev_id, const void **caps)
440 {
441 	const struct rte_security_capability *capabilities;
442 	void *sec_ctx;
443 
444 	if (rte_cryptodev_is_valid_dev(dev_id) == 0)
445 		return -EINVAL;
446 
447 	sec_ctx = rte_cryptodev_get_sec_ctx(dev_id);
448 	RTE_PTR_OR_ERR_RET(sec_ctx, -EINVAL);
449 
450 	capabilities = rte_security_capabilities_get(sec_ctx);
451 	RTE_PTR_OR_ERR_RET(capabilities, -EINVAL);
452 
453 	*caps = capabilities;
454 	return 0;
455 }
456 
457 static int
458 security_handle_cryptodev_sec_caps(const char *cmd __rte_unused, const char *params,
459 				   struct rte_tel_data *d)
460 {
461 	const struct rte_security_capability *capabilities;
462 	struct rte_tel_data *sec_caps;
463 	char *end_param;
464 	int sec_caps_n;
465 	int dev_id;
466 	int rc;
467 
468 	if (!params || strlen(params) == 0 || !isdigit(*params))
469 		return -EINVAL;
470 
471 	dev_id = strtoul(params, &end_param, 0);
472 	if (*end_param != '\0')
473 		CDEV_LOG_ERR("Extra parameters passed to command, ignoring");
474 
475 	rc = security_capabilities_from_dev_id(dev_id, (void *)&capabilities);
476 	if (rc < 0)
477 		return rc;
478 
479 	sec_caps = rte_tel_data_alloc();
480 	RTE_PTR_OR_ERR_RET(sec_caps, -ENOMEM);
481 
482 	rte_tel_data_start_dict(d);
483 	sec_caps_n = sec_caps_array(sec_caps, capabilities);
484 	rte_tel_data_add_dict_container(d, "sec_caps", sec_caps, 0);
485 	rte_tel_data_add_dict_int(d, "sec_caps_n", sec_caps_n);
486 
487 	return 0;
488 }
489 
490 static int
491 security_handle_cryptodev_crypto_caps(const char *cmd __rte_unused, const char *params,
492 				      struct rte_tel_data *d)
493 {
494 	const struct rte_security_capability *capabilities;
495 	struct rte_tel_data *crypto_caps;
496 	const char *capa_param;
497 	int dev_id, capa_id;
498 	int crypto_caps_n;
499 	char *end_param;
500 	int rc;
501 
502 	if (!params || strlen(params) == 0 || !isdigit(*params))
503 		return -EINVAL;
504 
505 	dev_id = strtoul(params, &end_param, 0);
506 	capa_param = strtok(end_param, ",");
507 	if (!capa_param || strlen(capa_param) == 0 || !isdigit(*capa_param))
508 		return -EINVAL;
509 
510 	capa_id = strtoul(capa_param, &end_param, 0);
511 	if (*end_param != '\0')
512 		CDEV_LOG_ERR("Extra parameters passed to command, ignoring");
513 
514 	rc = security_capabilities_from_dev_id(dev_id, (void *)&capabilities);
515 	if (rc < 0)
516 		return rc;
517 
518 	capabilities = security_capability_by_index(capabilities, capa_id);
519 	RTE_PTR_OR_ERR_RET(capabilities, -EINVAL);
520 
521 	crypto_caps = rte_tel_data_alloc();
522 	RTE_PTR_OR_ERR_RET(crypto_caps, -ENOMEM);
523 
524 	rte_tel_data_start_dict(d);
525 	crypto_caps_n = crypto_caps_array(crypto_caps, capabilities->crypto_capabilities);
526 
527 	rte_tel_data_add_dict_container(d, "crypto_caps", crypto_caps, 0);
528 	rte_tel_data_add_dict_int(d, "crypto_caps_n", crypto_caps_n);
529 
530 	return 0;
531 }
532 
533 RTE_INIT(security_init_telemetry)
534 {
535 	rte_telemetry_register_cmd("/security/cryptodev/list",
536 		security_handle_cryptodev_list,
537 		"Returns list of available crypto devices by IDs. No parameters.");
538 
539 	rte_telemetry_register_cmd("/security/cryptodev/sec_caps",
540 		security_handle_cryptodev_sec_caps,
541 		"Returns security capabilities for a cryptodev. Parameters: int dev_id");
542 
543 	rte_telemetry_register_cmd("/security/cryptodev/crypto_caps",
544 		security_handle_cryptodev_crypto_caps,
545 		"Returns crypto capabilities for a security capability. Parameters: int dev_id, sec_cap_id");
546 }
547