xref: /dpdk/examples/ipsec-secgw/ipsec.c (revision 54140461b60485941da282d8da2db2f2bc19e281)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2016-2020 Intel Corporation
3  */
4 #include <sys/types.h>
5 #include <netinet/in.h>
6 #include <netinet/ip.h>
7 
8 #include <rte_branch_prediction.h>
9 #include <rte_event_crypto_adapter.h>
10 #include <rte_log.h>
11 #include <rte_crypto.h>
12 #include <rte_security.h>
13 #include <rte_cryptodev.h>
14 #include <rte_ipsec.h>
15 #include <rte_ethdev.h>
16 #include <rte_mbuf.h>
17 #include <rte_hash.h>
18 
19 #include "ipsec.h"
20 #include "esp.h"
21 
22 static inline void
23 set_ipsec_conf(struct ipsec_sa *sa, struct rte_security_ipsec_xform *ipsec)
24 {
25 	if (ipsec->mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
26 		struct rte_security_ipsec_tunnel_param *tunnel =
27 				&ipsec->tunnel;
28 		if (IS_IP4_TUNNEL(sa->flags)) {
29 			tunnel->type =
30 				RTE_SECURITY_IPSEC_TUNNEL_IPV4;
31 			tunnel->ipv4.ttl = IPDEFTTL;
32 
33 			memcpy((uint8_t *)&tunnel->ipv4.src_ip,
34 				(uint8_t *)&sa->src.ip.ip4, 4);
35 
36 			memcpy((uint8_t *)&tunnel->ipv4.dst_ip,
37 				(uint8_t *)&sa->dst.ip.ip4, 4);
38 		} else if (IS_IP6_TUNNEL(sa->flags)) {
39 			tunnel->type =
40 				RTE_SECURITY_IPSEC_TUNNEL_IPV6;
41 			tunnel->ipv6.hlimit = IPDEFTTL;
42 			tunnel->ipv6.dscp = 0;
43 			tunnel->ipv6.flabel = 0;
44 
45 			memcpy((uint8_t *)&tunnel->ipv6.src_addr,
46 				(uint8_t *)&sa->src.ip.ip6.ip6_b, 16);
47 
48 			memcpy((uint8_t *)&tunnel->ipv6.dst_addr,
49 				(uint8_t *)&sa->dst.ip.ip6.ip6_b, 16);
50 		}
51 		/* TODO support for Transport */
52 	}
53 	ipsec->replay_win_sz = app_sa_prm.window_size;
54 	ipsec->options.esn = app_sa_prm.enable_esn;
55 	ipsec->options.udp_encap = sa->udp_encap;
56 	if (IS_HW_REASSEMBLY_EN(sa->flags))
57 		ipsec->options.ip_reassembly_en = 1;
58 }
59 
60 static inline int
61 verify_crypto_xform(const struct rte_cryptodev_capabilities *capabilities,
62 		struct rte_crypto_sym_xform *crypto_xform)
63 {
64 	const struct rte_cryptodev_capabilities *crypto_cap;
65 	int j = 0;
66 
67 	while ((crypto_cap = &capabilities[j++])->op != RTE_CRYPTO_OP_TYPE_UNDEFINED) {
68 		if (crypto_cap->op == RTE_CRYPTO_OP_TYPE_SYMMETRIC &&
69 				crypto_cap->sym.xform_type == crypto_xform->type) {
70 			if (crypto_xform->type == RTE_CRYPTO_SYM_XFORM_AEAD &&
71 					crypto_cap->sym.aead.algo == crypto_xform->aead.algo) {
72 				if (rte_cryptodev_sym_capability_check_aead(&crypto_cap->sym,
73 						crypto_xform->aead.key.length,
74 						crypto_xform->aead.digest_length,
75 						crypto_xform->aead.aad_length,
76 						crypto_xform->aead.iv.length) == 0)
77 					return 0;
78 			}
79 			if (crypto_xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER &&
80 					crypto_cap->sym.cipher.algo == crypto_xform->cipher.algo) {
81 				if (rte_cryptodev_sym_capability_check_cipher(&crypto_cap->sym,
82 						crypto_xform->cipher.key.length,
83 						crypto_xform->cipher.iv.length) == 0)
84 					return 0;
85 			}
86 			if (crypto_xform->type == RTE_CRYPTO_SYM_XFORM_AUTH &&
87 					crypto_cap->sym.auth.algo == crypto_xform->auth.algo) {
88 				if (rte_cryptodev_sym_capability_check_auth(&crypto_cap->sym,
89 						crypto_xform->auth.key.length,
90 						crypto_xform->auth.digest_length,
91 						crypto_xform->auth.iv.length) == 0)
92 					return 0;
93 			}
94 		}
95 	}
96 
97 	return -ENOTSUP;
98 }
99 
100 static inline int
101 verify_crypto_capabilities(const struct rte_cryptodev_capabilities *capabilities,
102 		struct rte_crypto_sym_xform *crypto_xform)
103 {
104 	if (crypto_xform->next != NULL)
105 		return (verify_crypto_xform(capabilities, crypto_xform) ||
106 		    verify_crypto_xform(capabilities, crypto_xform->next));
107 	else
108 		return verify_crypto_xform(capabilities, crypto_xform);
109 }
110 
111 static inline int
112 verify_ipsec_capabilities(struct rte_security_ipsec_xform *ipsec_xform,
113 		const struct rte_security_capability *sec_cap)
114 {
115 	/* Verify security capabilities */
116 
117 	if (ipsec_xform->options.esn == 1 && sec_cap->ipsec.options.esn == 0) {
118 		RTE_LOG(INFO, USER1, "ESN is not supported\n");
119 		return -ENOTSUP;
120 	}
121 
122 	if (ipsec_xform->options.udp_encap == 1 &&
123 	    sec_cap->ipsec.options.udp_encap == 0) {
124 		RTE_LOG(INFO, USER1, "UDP encapsulation is not supported\n");
125 		return -ENOTSUP;
126 	}
127 
128 	if (ipsec_xform->options.udp_ports_verify == 1 &&
129 	    sec_cap->ipsec.options.udp_ports_verify == 0) {
130 		RTE_LOG(DEBUG, USER1,
131 			"UDP encapsulation ports verification is not supported\n");
132 		return -ENOTSUP;
133 	}
134 
135 	if (ipsec_xform->options.copy_dscp == 1 &&
136 	    sec_cap->ipsec.options.copy_dscp == 0) {
137 		RTE_LOG(DEBUG, USER1, "Copy DSCP is not supported\n");
138 		return -ENOTSUP;
139 	}
140 
141 	if (ipsec_xform->options.copy_flabel == 1 &&
142 	    sec_cap->ipsec.options.copy_flabel == 0) {
143 		RTE_LOG(DEBUG, USER1, "Copy Flow Label is not supported\n");
144 		return -ENOTSUP;
145 	}
146 
147 	if (ipsec_xform->options.copy_df == 1 &&
148 	    sec_cap->ipsec.options.copy_df == 0) {
149 		RTE_LOG(DEBUG, USER1, "Copy DP bit is not supported\n");
150 		return -ENOTSUP;
151 	}
152 
153 	if (ipsec_xform->options.dec_ttl == 1 &&
154 	    sec_cap->ipsec.options.dec_ttl == 0) {
155 		RTE_LOG(DEBUG, USER1, "Decrement TTL is not supported\n");
156 		return -ENOTSUP;
157 	}
158 
159 	if (ipsec_xform->options.ecn == 1 && sec_cap->ipsec.options.ecn == 0) {
160 		RTE_LOG(DEBUG, USER1, "ECN is not supported\n");
161 		return -ENOTSUP;
162 	}
163 
164 	if (ipsec_xform->options.stats == 1 &&
165 	    sec_cap->ipsec.options.stats == 0) {
166 		RTE_LOG(DEBUG, USER1, "Stats is not supported\n");
167 		return -ENOTSUP;
168 	}
169 
170 	if ((ipsec_xform->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) &&
171 	    (ipsec_xform->options.iv_gen_disable == 1) &&
172 	    (sec_cap->ipsec.options.iv_gen_disable != 1)) {
173 		RTE_LOG(DEBUG, USER1, "Application provided IV is not supported\n");
174 		return -ENOTSUP;
175 	}
176 
177 	if ((ipsec_xform->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
178 	    (ipsec_xform->options.tunnel_hdr_verify >
179 	    sec_cap->ipsec.options.tunnel_hdr_verify)) {
180 		RTE_LOG(DEBUG, USER1, "Tunnel header verify is not supported\n");
181 		return -ENOTSUP;
182 	}
183 
184 	if (ipsec_xform->options.ip_csum_enable == 1 &&
185 	    sec_cap->ipsec.options.ip_csum_enable == 0) {
186 		RTE_LOG(DEBUG, USER1, "Inner IP checksum is not supported\n");
187 		return -ENOTSUP;
188 	}
189 
190 	if (ipsec_xform->options.l4_csum_enable == 1 &&
191 	    sec_cap->ipsec.options.l4_csum_enable == 0) {
192 		RTE_LOG(DEBUG, USER1, "Inner L4 checksum is not supported\n");
193 		return -ENOTSUP;
194 	}
195 
196 	if (ipsec_xform->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) {
197 		if (ipsec_xform->replay_win_sz > sec_cap->ipsec.replay_win_sz_max) {
198 			RTE_LOG(DEBUG, USER1, "Replay window size is not supported\n");
199 			return -ENOTSUP;
200 		}
201 	}
202 
203 	return 0;
204 }
205 
206 
207 static inline int
208 verify_security_capabilities(void *ctx,
209 		struct rte_security_session_conf *sess_conf,
210 		uint32_t *ol_flags)
211 {
212 	struct rte_security_capability_idx sec_cap_idx;
213 	const struct rte_security_capability *sec_cap;
214 
215 	sec_cap_idx.action = sess_conf->action_type;
216 	sec_cap_idx.protocol = sess_conf->protocol;
217 	sec_cap_idx.ipsec.proto = sess_conf->ipsec.proto;
218 	sec_cap_idx.ipsec.mode = sess_conf->ipsec.mode;
219 	sec_cap_idx.ipsec.direction = sess_conf->ipsec.direction;
220 
221 	sec_cap = rte_security_capability_get(ctx, &sec_cap_idx);
222 	if (sec_cap == NULL)
223 		return -ENOTSUP;
224 
225 	if (verify_crypto_capabilities(sec_cap->crypto_capabilities,
226 				sess_conf->crypto_xform))
227 		return -ENOTSUP;
228 
229 	if (verify_ipsec_capabilities(&sess_conf->ipsec, sec_cap))
230 		return -ENOTSUP;
231 
232 	if (ol_flags != NULL)
233 		*ol_flags = sec_cap->ol_flags;
234 
235 	return 0;
236 }
237 
238 int
239 create_lookaside_session(struct ipsec_ctx *ipsec_ctx_lcore[],
240 	struct socket_ctx *skt_ctx, const struct eventmode_conf *em_conf,
241 	struct ipsec_sa *sa, struct rte_ipsec_session *ips)
242 {
243 	uint16_t cdev_id = RTE_CRYPTO_MAX_DEVS;
244 	enum rte_crypto_op_sess_type sess_type;
245 	struct rte_cryptodev_info cdev_info;
246 	enum rte_crypto_op_type op_type;
247 	unsigned long cdev_id_qp = 0;
248 	struct ipsec_ctx *ipsec_ctx;
249 	struct cdev_key key = { 0 };
250 	void *sess = NULL;
251 	uint32_t lcore_id;
252 	int32_t ret = 0;
253 
254 	RTE_LCORE_FOREACH(lcore_id) {
255 		ipsec_ctx = ipsec_ctx_lcore[lcore_id];
256 
257 		/* Core is not bound to any cryptodev, skip it */
258 		if (ipsec_ctx->cdev_map == NULL)
259 			continue;
260 
261 		/* Looking for cryptodev, which can handle this SA */
262 		key.lcore_id = (uint8_t)lcore_id;
263 		key.cipher_algo = (uint8_t)sa->cipher_algo;
264 		key.auth_algo = (uint8_t)sa->auth_algo;
265 		key.aead_algo = (uint8_t)sa->aead_algo;
266 
267 		ret = rte_hash_lookup_data(ipsec_ctx->cdev_map, &key,
268 				(void **)&cdev_id_qp);
269 		if (ret == -ENOENT)
270 			continue;
271 		if (ret < 0) {
272 			RTE_LOG(ERR, IPSEC,
273 					"No cryptodev: core %u, cipher_algo %u, "
274 					"auth_algo %u, aead_algo %u\n",
275 					key.lcore_id,
276 					key.cipher_algo,
277 					key.auth_algo,
278 					key.aead_algo);
279 			return ret;
280 		}
281 
282 		/* Verify that all cores are using same cryptodev for current
283 		 * algorithm combination, required by SA.
284 		 * Current cryptodev mapping process will map SA to the first
285 		 * cryptodev that matches requirements, so it's a double check,
286 		 * not an additional restriction.
287 		 */
288 		if (cdev_id == RTE_CRYPTO_MAX_DEVS)
289 			cdev_id = ipsec_ctx->tbl[cdev_id_qp].id;
290 		else if (cdev_id != ipsec_ctx->tbl[cdev_id_qp].id) {
291 			RTE_LOG(ERR, IPSEC,
292 					"SA mapping to multiple cryptodevs is "
293 					"not supported!");
294 			return -EINVAL;
295 		}
296 
297 		/* Store per core queue pair information */
298 		sa->cqp[lcore_id] = &ipsec_ctx->tbl[cdev_id_qp];
299 	}
300 	if (cdev_id == RTE_CRYPTO_MAX_DEVS) {
301 		RTE_LOG(WARNING, IPSEC, "No cores found to handle SA\n");
302 		return 0;
303 	}
304 
305 	RTE_LOG(DEBUG, IPSEC, "Create session for SA spi %u on cryptodev "
306 			"%u\n", sa->spi, cdev_id);
307 
308 	if (ips->type != RTE_SECURITY_ACTION_TYPE_NONE &&
309 		ips->type != RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO) {
310 		struct rte_security_session_conf sess_conf = {
311 			.action_type = ips->type,
312 			.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
313 			{.ipsec = {
314 				.spi = sa->spi,
315 				.salt = sa->salt,
316 				.options = { 0 },
317 				.replay_win_sz = 0,
318 				.direction = sa->direction,
319 				.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
320 				.mode = (IS_TUNNEL(sa->flags)) ?
321 					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL :
322 					RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT,
323 			} },
324 			.crypto_xform = sa->xforms,
325 			.userdata = NULL,
326 
327 		};
328 
329 		if (ips->type == RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL) {
330 			void *ctx = rte_cryptodev_get_sec_ctx(cdev_id);
331 
332 			/* Set IPsec parameters in conf */
333 			set_ipsec_conf(sa, &(sess_conf.ipsec));
334 
335 			if (verify_security_capabilities(ctx, &sess_conf, NULL)) {
336 				RTE_LOG(ERR, IPSEC,
337 					"Requested security session config not supported\n");
338 				return -1;
339 			}
340 
341 			ips->security.ses = rte_security_session_create(ctx,
342 					&sess_conf, skt_ctx->session_pool);
343 			if (ips->security.ses == NULL) {
344 				RTE_LOG(ERR, IPSEC,
345 				"SEC Session init failed: err: %d\n", ret);
346 				return -1;
347 			}
348 			ips->security.ctx = ctx;
349 
350 			sess = ips->security.ses;
351 			op_type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
352 			sess_type = RTE_CRYPTO_OP_SECURITY_SESSION;
353 		} else {
354 			RTE_LOG(ERR, IPSEC, "Inline not supported\n");
355 			return -1;
356 		}
357 	} else {
358 		struct rte_cryptodev_info info;
359 
360 		rte_cryptodev_info_get(cdev_id, &info);
361 
362 		if (ips->type == RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO) {
363 			if (!(info.feature_flags &
364 				RTE_CRYPTODEV_FF_SYM_CPU_CRYPTO))
365 				return -ENOTSUP;
366 
367 		}
368 
369 		if (verify_crypto_capabilities(info.capabilities, sa->xforms)) {
370 			RTE_LOG(ERR, IPSEC,
371 				"Requested crypto session config not supported\n");
372 			return -1;
373 		}
374 
375 		ips->crypto.dev_id = cdev_id;
376 		ips->crypto.ses = rte_cryptodev_sym_session_create(cdev_id,
377 				sa->xforms, skt_ctx->session_pool);
378 
379 		rte_cryptodev_info_get(cdev_id, &cdev_info);
380 	}
381 
382 	/* Setup meta data required by event crypto adapter */
383 	if (em_conf->enable_event_crypto_adapter && sess != NULL) {
384 		union rte_event_crypto_metadata m_data;
385 		const struct eventdev_params *eventdev_conf;
386 
387 		eventdev_conf = &(em_conf->eventdev_config[0]);
388 		memset(&m_data, 0, sizeof(m_data));
389 
390 		/* Fill in response information */
391 		m_data.response_info.sched_type = em_conf->ext_params.sched_type;
392 		m_data.response_info.op = RTE_EVENT_OP_NEW;
393 		m_data.response_info.queue_id = eventdev_conf->ev_cpt_queue_id;
394 
395 		/* Fill in request information */
396 		m_data.request_info.cdev_id = cdev_id;
397 		m_data.request_info.queue_pair_id = 0;
398 
399 		/* Attach meta info to session */
400 		rte_cryptodev_session_event_mdata_set(cdev_id, sess, op_type,
401 				sess_type, &m_data, sizeof(m_data));
402 	}
403 
404 	return 0;
405 }
406 
407 int
408 create_inline_session(struct socket_ctx *skt_ctx, struct ipsec_sa *sa,
409 		struct rte_ipsec_session *ips)
410 {
411 	int32_t ret = 0;
412 	void *sec_ctx;
413 	struct rte_security_session_conf sess_conf = {
414 		.action_type = ips->type,
415 		.protocol = RTE_SECURITY_PROTOCOL_IPSEC,
416 		{.ipsec = {
417 			.spi = sa->spi,
418 			.salt = sa->salt,
419 			.options = { 0 },
420 			.replay_win_sz = 0,
421 			.direction = sa->direction,
422 			.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP
423 		} },
424 		.crypto_xform = sa->xforms,
425 		.userdata = NULL,
426 	};
427 
428 	if (IS_TRANSPORT(sa->flags)) {
429 		sess_conf.ipsec.mode = RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT;
430 		if (IS_IP4(sa->flags)) {
431 			sess_conf.ipsec.tunnel.type =
432 				RTE_SECURITY_IPSEC_TUNNEL_IPV4;
433 
434 			sess_conf.ipsec.tunnel.ipv4.src_ip.s_addr =
435 				sa->src.ip.ip4;
436 			sess_conf.ipsec.tunnel.ipv4.dst_ip.s_addr =
437 				sa->dst.ip.ip4;
438 		} else if (IS_IP6(sa->flags)) {
439 			sess_conf.ipsec.tunnel.type =
440 				RTE_SECURITY_IPSEC_TUNNEL_IPV6;
441 
442 			memcpy(sess_conf.ipsec.tunnel.ipv6.src_addr.s6_addr,
443 				sa->src.ip.ip6.ip6_b, 16);
444 			memcpy(sess_conf.ipsec.tunnel.ipv6.dst_addr.s6_addr,
445 				sa->dst.ip.ip6.ip6_b, 16);
446 		}
447 	} else if (IS_TUNNEL(sa->flags)) {
448 		sess_conf.ipsec.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL;
449 
450 		if (IS_IP4(sa->flags)) {
451 			sess_conf.ipsec.tunnel.type =
452 				RTE_SECURITY_IPSEC_TUNNEL_IPV4;
453 
454 			sess_conf.ipsec.tunnel.ipv4.src_ip.s_addr =
455 				sa->src.ip.ip4;
456 			sess_conf.ipsec.tunnel.ipv4.dst_ip.s_addr =
457 				sa->dst.ip.ip4;
458 		} else if (IS_IP6(sa->flags)) {
459 			sess_conf.ipsec.tunnel.type =
460 				RTE_SECURITY_IPSEC_TUNNEL_IPV6;
461 
462 			memcpy(sess_conf.ipsec.tunnel.ipv6.src_addr.s6_addr,
463 				sa->src.ip.ip6.ip6_b, 16);
464 			memcpy(sess_conf.ipsec.tunnel.ipv6.dst_addr.s6_addr,
465 				sa->dst.ip.ip6.ip6_b, 16);
466 		} else {
467 			RTE_LOG(ERR, IPSEC, "invalid tunnel type\n");
468 			return -1;
469 		}
470 	}
471 
472 	if (sa->udp_encap) {
473 		sess_conf.ipsec.options.udp_encap = 1;
474 		sess_conf.ipsec.udp.sport = htons(sa->udp.sport);
475 		sess_conf.ipsec.udp.dport = htons(sa->udp.dport);
476 	}
477 
478 	if (sa->esn > 0) {
479 		sess_conf.ipsec.options.esn = 1;
480 		sess_conf.ipsec.esn.value = sa->esn;
481 	}
482 
483 
484 	RTE_LOG_DP(DEBUG, IPSEC, "Create session for SA spi %u on port %u\n",
485 		sa->spi, sa->portid);
486 
487 	if (ips->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) {
488 		struct rte_flow_error err;
489 		int ret = 0;
490 
491 		sec_ctx = rte_eth_dev_get_sec_ctx(sa->portid);
492 		if (sec_ctx == NULL) {
493 			RTE_LOG(ERR, IPSEC,
494 				" rte_eth_dev_get_sec_ctx failed\n");
495 			return -1;
496 		}
497 
498 		if (verify_security_capabilities(sec_ctx, &sess_conf,
499 					&ips->security.ol_flags)) {
500 			RTE_LOG(ERR, IPSEC,
501 				"Requested security session config not supported\n");
502 			return -1;
503 		}
504 
505 		ips->security.ses = rte_security_session_create(sec_ctx,
506 				&sess_conf, skt_ctx->session_pool);
507 		if (ips->security.ses == NULL) {
508 			RTE_LOG(ERR, IPSEC,
509 				"SEC Session init failed: err: %d\n", ret);
510 			return -1;
511 		}
512 
513 		ips->security.ctx = sec_ctx;
514 		sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
515 
516 		if (IS_IP6(sa->flags)) {
517 			sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
518 			sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
519 			sa->pattern[1].spec = &sa->ipv6_spec;
520 
521 			memcpy(sa->ipv6_spec.hdr.dst_addr,
522 				sa->dst.ip.ip6.ip6_b, 16);
523 			memcpy(sa->ipv6_spec.hdr.src_addr,
524 			       sa->src.ip.ip6.ip6_b, 16);
525 		} else if (IS_IP4(sa->flags)) {
526 			sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
527 			sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
528 			sa->pattern[1].spec = &sa->ipv4_spec;
529 
530 			sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
531 			sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
532 		}
533 
534 		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
535 
536 		if (sa->udp_encap) {
537 
538 			sa->udp_spec.hdr.dst_port =
539 					rte_cpu_to_be_16(sa->udp.dport);
540 			sa->udp_spec.hdr.src_port =
541 					rte_cpu_to_be_16(sa->udp.sport);
542 
543 			sa->pattern[2].mask = &rte_flow_item_udp_mask;
544 			sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_UDP;
545 			sa->pattern[2].spec = &sa->udp_spec;
546 
547 			sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_ESP;
548 			sa->pattern[3].spec = &sa->esp_spec;
549 			sa->pattern[3].mask = &rte_flow_item_esp_mask;
550 
551 			sa->pattern[4].type = RTE_FLOW_ITEM_TYPE_END;
552 		} else {
553 			sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
554 			sa->pattern[2].spec = &sa->esp_spec;
555 			sa->pattern[2].mask = &rte_flow_item_esp_mask;
556 
557 			sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
558 		}
559 
560 		sa->action[0].type = RTE_FLOW_ACTION_TYPE_SECURITY;
561 		sa->action[0].conf = ips->security.ses;
562 
563 		sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
564 
565 		sa->attr.egress = (sa->direction ==
566 				RTE_SECURITY_IPSEC_SA_DIR_EGRESS);
567 		sa->attr.ingress = (sa->direction ==
568 				RTE_SECURITY_IPSEC_SA_DIR_INGRESS);
569 		if (sa->attr.ingress) {
570 			uint8_t rss_key[64];
571 			struct rte_eth_rss_conf rss_conf = {
572 				.rss_key = rss_key,
573 				.rss_key_len = sizeof(rss_key),
574 			};
575 			struct rte_eth_dev_info dev_info;
576 			uint16_t queue[RTE_MAX_QUEUES_PER_PORT];
577 			struct rte_flow_action_rss action_rss;
578 			unsigned int i;
579 			unsigned int j;
580 
581 			/* Don't create flow if default flow is created */
582 			if (flow_info_tbl[sa->portid].rx_def_flow)
583 				return 0;
584 
585 			ret = rte_eth_dev_info_get(sa->portid, &dev_info);
586 			if (ret != 0) {
587 				RTE_LOG(ERR, IPSEC,
588 					"Error during getting device (port %u) info: %s\n",
589 					sa->portid, strerror(-ret));
590 				return ret;
591 			}
592 
593 			sa->action[2].type = RTE_FLOW_ACTION_TYPE_END;
594 			/* Try RSS. */
595 			sa->action[1].type = RTE_FLOW_ACTION_TYPE_RSS;
596 			sa->action[1].conf = &action_rss;
597 			ret = rte_eth_dev_rss_hash_conf_get(sa->portid,
598 					&rss_conf);
599 			if (ret != 0) {
600 				RTE_LOG(ERR, IPSEC,
601 					"rte_eth_dev_rss_hash_conf_get:ret=%d\n",
602 					ret);
603 				return -1;
604 			}
605 			for (i = 0, j = 0; i < dev_info.nb_rx_queues; ++i)
606 				queue[j++] = i;
607 
608 			action_rss = (struct rte_flow_action_rss){
609 					.types = rss_conf.rss_hf,
610 					.key_len = rss_conf.rss_key_len,
611 					.queue_num = j,
612 					.key = rss_key,
613 					.queue = queue,
614 			};
615 			ret = rte_flow_validate(sa->portid, &sa->attr,
616 						sa->pattern, sa->action,
617 						&err);
618 			if (!ret)
619 				goto flow_create;
620 			/* Try Queue. */
621 			sa->action[1].type = RTE_FLOW_ACTION_TYPE_QUEUE;
622 			sa->action[1].conf =
623 				&(struct rte_flow_action_queue){
624 				.index = 0,
625 			};
626 			ret = rte_flow_validate(sa->portid, &sa->attr,
627 						sa->pattern, sa->action,
628 						&err);
629 			/* Try End. */
630 			sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
631 			sa->action[1].conf = NULL;
632 			ret = rte_flow_validate(sa->portid, &sa->attr,
633 						sa->pattern, sa->action,
634 						&err);
635 			if (ret)
636 				goto flow_create_failure;
637 		} else if (sa->attr.egress &&
638 				(ips->security.ol_flags &
639 					RTE_SECURITY_TX_HW_TRAILER_OFFLOAD)) {
640 			sa->action[1].type =
641 					RTE_FLOW_ACTION_TYPE_PASSTHRU;
642 			sa->action[2].type =
643 					RTE_FLOW_ACTION_TYPE_END;
644 		}
645 flow_create:
646 		sa->flow = rte_flow_create(sa->portid,
647 				&sa->attr, sa->pattern, sa->action, &err);
648 		if (sa->flow == NULL) {
649 flow_create_failure:
650 			RTE_LOG(ERR, IPSEC,
651 				"Failed to create ipsec flow msg: %s\n",
652 				err.message);
653 			return -1;
654 		}
655 	} else if (ips->type ==	RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL) {
656 		sec_ctx = rte_eth_dev_get_sec_ctx(sa->portid);
657 
658 		if (sec_ctx == NULL) {
659 			RTE_LOG(ERR, IPSEC,
660 				"Ethernet device doesn't have security features registered\n");
661 			return -1;
662 		}
663 
664 		/* Set IPsec parameters in conf */
665 		set_ipsec_conf(sa, &(sess_conf.ipsec));
666 
667 		/* Save SA as userdata for the security session. When
668 		 * the packet is received, this userdata will be
669 		 * retrieved using the metadata from the packet.
670 		 *
671 		 * The PMD is expected to set similar metadata for other
672 		 * operations, like rte_eth_event, which are tied to
673 		 * security session. In such cases, the userdata could
674 		 * be obtained to uniquely identify the security
675 		 * parameters denoted.
676 		 */
677 
678 		sess_conf.userdata = (void *) sa;
679 
680 		if (verify_security_capabilities(sec_ctx, &sess_conf,
681 					&ips->security.ol_flags)) {
682 			RTE_LOG(ERR, IPSEC,
683 				"Requested security session config not supported\n");
684 			return -1;
685 		}
686 
687 		ips->security.ses = rte_security_session_create(sec_ctx,
688 					&sess_conf, skt_ctx->session_pool);
689 		if (ips->security.ses == NULL) {
690 			RTE_LOG(ERR, IPSEC,
691 				"SEC Session init failed: err: %d\n", ret);
692 			return -1;
693 		}
694 
695 		ips->security.ctx = sec_ctx;
696 	}
697 
698 	return 0;
699 }
700 
701 int
702 create_ipsec_esp_flow(struct ipsec_sa *sa)
703 {
704 	int ret = 0;
705 	struct rte_flow_error err = {};
706 	if (sa->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
707 		RTE_LOG(ERR, IPSEC,
708 			"No Flow director rule for Egress traffic\n");
709 		return -1;
710 	}
711 	if (sa->flags == TRANSPORT) {
712 		RTE_LOG(ERR, IPSEC,
713 			"No Flow director rule for transport mode\n");
714 		return -1;
715 	}
716 	sa->action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
717 	sa->pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
718 	sa->action[0].conf = &(struct rte_flow_action_queue) {
719 				.index = sa->fdir_qid,
720 	};
721 	sa->attr.egress = 0;
722 	sa->attr.ingress = 1;
723 	if (IS_IP6(sa->flags)) {
724 		sa->pattern[1].mask = &rte_flow_item_ipv6_mask;
725 		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
726 		sa->pattern[1].spec = &sa->ipv6_spec;
727 		memcpy(sa->ipv6_spec.hdr.dst_addr,
728 			sa->dst.ip.ip6.ip6_b, sizeof(sa->dst.ip.ip6.ip6_b));
729 		memcpy(sa->ipv6_spec.hdr.src_addr,
730 			sa->src.ip.ip6.ip6_b, sizeof(sa->src.ip.ip6.ip6_b));
731 		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
732 		sa->pattern[2].spec = &sa->esp_spec;
733 		sa->pattern[2].mask = &rte_flow_item_esp_mask;
734 		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
735 		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
736 	} else if (IS_IP4(sa->flags)) {
737 		sa->pattern[1].mask = &rte_flow_item_ipv4_mask;
738 		sa->pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
739 		sa->pattern[1].spec = &sa->ipv4_spec;
740 		sa->ipv4_spec.hdr.dst_addr = sa->dst.ip.ip4;
741 		sa->ipv4_spec.hdr.src_addr = sa->src.ip.ip4;
742 		sa->pattern[2].type = RTE_FLOW_ITEM_TYPE_ESP;
743 		sa->pattern[2].spec = &sa->esp_spec;
744 		sa->pattern[2].mask = &rte_flow_item_esp_mask;
745 		sa->esp_spec.hdr.spi = rte_cpu_to_be_32(sa->spi);
746 		sa->pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
747 	}
748 	sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
749 
750 	ret = rte_flow_validate(sa->portid, &sa->attr, sa->pattern, sa->action,
751 				&err);
752 	if (ret < 0) {
753 		RTE_LOG(ERR, IPSEC, "Flow validation failed %s\n", err.message);
754 		return ret;
755 	}
756 
757 	sa->flow = rte_flow_create(sa->portid, &sa->attr, sa->pattern,
758 					sa->action, &err);
759 	if (!sa->flow) {
760 		RTE_LOG(ERR, IPSEC, "Flow creation failed %s\n", err.message);
761 		return -1;
762 	}
763 
764 	return 0;
765 }
766 
767 /*
768  * queue crypto-ops into PMD queue.
769  */
770 void
771 enqueue_cop_burst(struct cdev_qp *cqp)
772 {
773 	uint32_t i, len, ret;
774 
775 	len = cqp->len;
776 	ret = rte_cryptodev_enqueue_burst(cqp->id, cqp->qp, cqp->buf, len);
777 	if (ret < len) {
778 		RTE_LOG_DP(DEBUG, IPSEC, "Cryptodev %u queue %u:"
779 			" enqueued %u crypto ops out of %u\n",
780 			cqp->id, cqp->qp, ret, len);
781 			/* drop packets that we fail to enqueue */
782 			for (i = ret; i < len; i++)
783 				free_pkts(&cqp->buf[i]->sym->m_src, 1);
784 	}
785 	cqp->in_flight += ret;
786 	cqp->len = 0;
787 }
788 
789 static inline void
790 enqueue_cop(struct cdev_qp *cqp, struct rte_crypto_op *cop)
791 {
792 	cqp->buf[cqp->len++] = cop;
793 
794 	if (cqp->len == MAX_PKT_BURST)
795 		enqueue_cop_burst(cqp);
796 }
797 
798 static inline void
799 ipsec_enqueue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
800 		struct rte_mbuf *pkts[], void *sas[],
801 		uint16_t nb_pkts)
802 {
803 	int32_t ret = 0, i;
804 	struct ipsec_mbuf_metadata *priv;
805 	struct rte_crypto_sym_op *sym_cop;
806 	struct ipsec_sa *sa;
807 	struct rte_ipsec_session *ips;
808 
809 	for (i = 0; i < nb_pkts; i++) {
810 		if (unlikely(sas[i] == NULL)) {
811 			free_pkts(&pkts[i], 1);
812 			continue;
813 		}
814 
815 		rte_prefetch0(sas[i]);
816 		rte_prefetch0(pkts[i]);
817 
818 		priv = get_priv(pkts[i]);
819 		sa = ipsec_mask_saptr(sas[i]);
820 		priv->sa = sa;
821 		ips = ipsec_get_primary_session(sa);
822 
823 		switch (ips->type) {
824 		case RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL:
825 			priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
826 			priv->cop.status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
827 
828 			rte_prefetch0(&priv->sym_cop);
829 
830 			if (unlikely(ips->security.ses == NULL)) {
831 				free_pkts(&pkts[i], 1);
832 				continue;
833 			}
834 
835 			if (unlikely((pkts[i]->packet_type &
836 					(RTE_PTYPE_TUNNEL_MASK |
837 					RTE_PTYPE_L4_MASK)) ==
838 					MBUF_PTYPE_TUNNEL_ESP_IN_UDP &&
839 					sa->udp_encap != 1)) {
840 				free_pkts(&pkts[i], 1);
841 				continue;
842 			}
843 
844 			sym_cop = get_sym_cop(&priv->cop);
845 			sym_cop->m_src = pkts[i];
846 
847 			rte_security_attach_session(&priv->cop,
848 				ips->security.ses);
849 			break;
850 
851 		case RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO:
852 			RTE_LOG(ERR, IPSEC, "CPU crypto is not supported by the"
853 					" legacy mode.");
854 			free_pkts(&pkts[i], 1);
855 			continue;
856 
857 		case RTE_SECURITY_ACTION_TYPE_NONE:
858 
859 			priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
860 			priv->cop.status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
861 
862 			rte_prefetch0(&priv->sym_cop);
863 
864 			if (unlikely(ips->crypto.ses == NULL)) {
865 				free_pkts(&pkts[i], 1);
866 				continue;
867 			}
868 
869 			rte_crypto_op_attach_sym_session(&priv->cop,
870 					ips->crypto.ses);
871 
872 			ret = xform_func(pkts[i], sa, &priv->cop);
873 			if (unlikely(ret)) {
874 				free_pkts(&pkts[i], 1);
875 				continue;
876 			}
877 			break;
878 		case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
879 			RTE_ASSERT(ips->security.ses != NULL);
880 			ipsec_ctx->ol_pkts[ipsec_ctx->ol_pkts_cnt++] = pkts[i];
881 			if (ips->security.ol_flags &
882 				RTE_SECURITY_TX_OLOAD_NEED_MDATA)
883 				rte_security_set_pkt_metadata(
884 					ips->security.ctx, ips->security.ses,
885 					pkts[i], NULL);
886 			continue;
887 		case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
888 			RTE_ASSERT(ips->security.ses != NULL);
889 			priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
890 			priv->cop.status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
891 
892 			rte_prefetch0(&priv->sym_cop);
893 			rte_security_attach_session(&priv->cop,
894 					ips->security.ses);
895 
896 			ret = xform_func(pkts[i], sa, &priv->cop);
897 			if (unlikely(ret)) {
898 				free_pkts(&pkts[i], 1);
899 				continue;
900 			}
901 
902 			ipsec_ctx->ol_pkts[ipsec_ctx->ol_pkts_cnt++] = pkts[i];
903 			if (ips->security.ol_flags &
904 				RTE_SECURITY_TX_OLOAD_NEED_MDATA)
905 				rte_security_set_pkt_metadata(
906 					ips->security.ctx, ips->security.ses,
907 					pkts[i], NULL);
908 			continue;
909 		}
910 
911 		enqueue_cop(sa->cqp[ipsec_ctx->lcore_id], &priv->cop);
912 	}
913 }
914 
915 static inline int32_t
916 ipsec_inline_dequeue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
917 	      struct rte_mbuf *pkts[], uint16_t max_pkts)
918 {
919 	int32_t nb_pkts, ret;
920 	struct ipsec_mbuf_metadata *priv;
921 	struct ipsec_sa *sa;
922 	struct rte_mbuf *pkt;
923 
924 	nb_pkts = 0;
925 	while (ipsec_ctx->ol_pkts_cnt > 0 && nb_pkts < max_pkts) {
926 		pkt = ipsec_ctx->ol_pkts[--ipsec_ctx->ol_pkts_cnt];
927 		rte_prefetch0(pkt);
928 		priv = get_priv(pkt);
929 		sa = priv->sa;
930 		ret = xform_func(pkt, sa, &priv->cop);
931 		if (unlikely(ret)) {
932 			free_pkts(&pkt, 1);
933 			continue;
934 		}
935 		pkts[nb_pkts++] = pkt;
936 	}
937 
938 	return nb_pkts;
939 }
940 
941 static inline int
942 ipsec_dequeue(ipsec_xform_fn xform_func, struct ipsec_ctx *ipsec_ctx,
943 	      struct rte_mbuf *pkts[], uint16_t max_pkts)
944 {
945 	int32_t nb_pkts = 0, ret = 0, i, j, nb_cops;
946 	struct ipsec_mbuf_metadata *priv;
947 	struct rte_crypto_op *cops[max_pkts];
948 	struct ipsec_sa *sa;
949 	struct rte_mbuf *pkt;
950 
951 	for (i = 0; i < ipsec_ctx->nb_qps && nb_pkts < max_pkts; i++) {
952 		struct cdev_qp *cqp;
953 
954 		cqp = &ipsec_ctx->tbl[ipsec_ctx->last_qp++];
955 		if (ipsec_ctx->last_qp == ipsec_ctx->nb_qps)
956 			ipsec_ctx->last_qp %= ipsec_ctx->nb_qps;
957 
958 		if (cqp->in_flight == 0)
959 			continue;
960 
961 		nb_cops = rte_cryptodev_dequeue_burst(cqp->id, cqp->qp,
962 				cops, max_pkts - nb_pkts);
963 
964 		cqp->in_flight -= nb_cops;
965 
966 		for (j = 0; j < nb_cops; j++) {
967 			pkt = cops[j]->sym->m_src;
968 			rte_prefetch0(pkt);
969 
970 			priv = get_priv(pkt);
971 			sa = priv->sa;
972 
973 			RTE_ASSERT(sa != NULL);
974 
975 			if (ipsec_get_action_type(sa) ==
976 				RTE_SECURITY_ACTION_TYPE_NONE) {
977 				ret = xform_func(pkt, sa, cops[j]);
978 				if (unlikely(ret)) {
979 					free_pkts(&pkt, 1);
980 					continue;
981 				}
982 			} else if (ipsec_get_action_type(sa) ==
983 				RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL) {
984 				if (cops[j]->status) {
985 					free_pkts(&pkt, 1);
986 					continue;
987 				}
988 			}
989 			pkts[nb_pkts++] = pkt;
990 		}
991 	}
992 
993 	/* return packets */
994 	return nb_pkts;
995 }
996 
997 uint16_t
998 ipsec_inbound(struct ipsec_ctx *ctx, struct rte_mbuf *pkts[],
999 		uint16_t nb_pkts, uint16_t len)
1000 {
1001 	void *sas[nb_pkts];
1002 
1003 	inbound_sa_lookup(ctx->sa_ctx, pkts, sas, nb_pkts);
1004 
1005 	ipsec_enqueue(esp_inbound, ctx, pkts, sas, nb_pkts);
1006 
1007 	return ipsec_inline_dequeue(esp_inbound_post, ctx, pkts, len);
1008 }
1009 
1010 uint16_t
1011 ipsec_inbound_cqp_dequeue(struct ipsec_ctx *ctx, struct rte_mbuf *pkts[],
1012 		uint16_t len)
1013 {
1014 	return ipsec_dequeue(esp_inbound_post, ctx, pkts, len);
1015 }
1016 
1017 uint16_t
1018 ipsec_outbound(struct ipsec_ctx *ctx, struct rte_mbuf *pkts[],
1019 		uint32_t sa_idx[], uint16_t nb_pkts, uint16_t len)
1020 {
1021 	void *sas[nb_pkts];
1022 
1023 	outbound_sa_lookup(ctx->sa_ctx, sa_idx, sas, nb_pkts);
1024 
1025 	ipsec_enqueue(esp_outbound, ctx, pkts, sas, nb_pkts);
1026 
1027 	return ipsec_inline_dequeue(esp_outbound_post, ctx, pkts, len);
1028 }
1029 
1030 uint16_t
1031 ipsec_outbound_cqp_dequeue(struct ipsec_ctx *ctx, struct rte_mbuf *pkts[],
1032 		uint16_t len)
1033 {
1034 	return ipsec_dequeue(esp_outbound_post, ctx, pkts, len);
1035 }
1036