xref: /dpdk/app/test/test_cryptodev_security_ipsec.c (revision 97b914f4e715565d53d38ac6e04815b9be5e58a9)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4 
5 #ifndef RTE_EXEC_ENV_WINDOWS
6 
7 #include <rte_common.h>
8 #include <rte_cryptodev.h>
9 #include <rte_esp.h>
10 #include <rte_ip.h>
11 #include <rte_security.h>
12 #include <rte_tcp.h>
13 #include <rte_udp.h>
14 
15 #include "test.h"
16 #include "test_cryptodev_security_ipsec.h"
17 
18 #define IV_LEN_MAX 16
19 
20 struct crypto_param_comb alg_list[RTE_DIM(aead_list) +
21 				  (RTE_DIM(cipher_list) *
22 				   RTE_DIM(auth_list))];
23 
24 struct crypto_param_comb ah_alg_list[2 * (RTE_DIM(auth_list) - 1)];
25 
26 static bool
27 is_valid_ipv4_pkt(const struct rte_ipv4_hdr *pkt)
28 {
29 	/* The IP version number must be 4 */
30 	if (((pkt->version_ihl) >> 4) != 4)
31 		return false;
32 	/*
33 	 * The IP header length field must be large enough to hold the
34 	 * minimum length legal IP datagram (20 bytes = 5 words).
35 	 */
36 	if ((pkt->version_ihl & 0xf) < 5)
37 		return false;
38 
39 	/*
40 	 * The IP total length field must be large enough to hold the IP
41 	 * datagram header, whose length is specified in the IP header length
42 	 * field.
43 	 */
44 	if (rte_cpu_to_be_16(pkt->total_length) < sizeof(struct rte_ipv4_hdr))
45 		return false;
46 
47 	return true;
48 }
49 
50 static bool
51 is_valid_ipv6_pkt(const struct rte_ipv6_hdr *pkt)
52 {
53 	/* The IP version number must be 6 */
54 	if ((rte_be_to_cpu_32((pkt->vtc_flow)) >> 28) != 6)
55 		return false;
56 
57 	return true;
58 }
59 
60 void
61 test_ipsec_alg_list_populate(void)
62 {
63 	unsigned long i, j, index = 0;
64 
65 	for (i = 0; i < RTE_DIM(aead_list); i++) {
66 		alg_list[index].param1 = &aead_list[i];
67 		alg_list[index].param2 = NULL;
68 		index++;
69 	}
70 
71 	for (i = 0; i < RTE_DIM(cipher_list); i++) {
72 		for (j = 0; j < RTE_DIM(auth_list); j++) {
73 			alg_list[index].param1 = &cipher_list[i];
74 			alg_list[index].param2 = &auth_list[j];
75 			index++;
76 		}
77 	}
78 }
79 
80 void
81 test_ipsec_ah_alg_list_populate(void)
82 {
83 	unsigned long i, index = 0;
84 
85 	for (i = 1; i < RTE_DIM(auth_list); i++) {
86 		ah_alg_list[index].param1 = &auth_list[i];
87 		ah_alg_list[index].param2 = NULL;
88 		index++;
89 	}
90 
91 	for (i = 1; i < RTE_DIM(auth_list); i++) {
92 		/* NULL cipher */
93 		ah_alg_list[index].param1 = &cipher_list[0];
94 
95 		ah_alg_list[index].param2 = &auth_list[i];
96 		index++;
97 	}
98 }
99 
100 int
101 test_ipsec_sec_caps_verify(struct rte_security_ipsec_xform *ipsec_xform,
102 			   const struct rte_security_capability *sec_cap,
103 			   bool silent)
104 {
105 	/* Verify security capabilities */
106 
107 	if (ipsec_xform->options.esn == 1 && sec_cap->ipsec.options.esn == 0) {
108 		if (!silent)
109 			RTE_LOG(INFO, USER1, "ESN is not supported\n");
110 		return -ENOTSUP;
111 	}
112 
113 	if (ipsec_xform->options.udp_encap == 1 &&
114 	    sec_cap->ipsec.options.udp_encap == 0) {
115 		if (!silent)
116 			RTE_LOG(INFO, USER1, "UDP encapsulation is not supported\n");
117 		return -ENOTSUP;
118 	}
119 
120 	if (ipsec_xform->options.udp_ports_verify == 1 &&
121 	    sec_cap->ipsec.options.udp_ports_verify == 0) {
122 		if (!silent)
123 			RTE_LOG(INFO, USER1, "UDP encapsulation ports "
124 				"verification is not supported\n");
125 		return -ENOTSUP;
126 	}
127 
128 	if (ipsec_xform->options.copy_dscp == 1 &&
129 	    sec_cap->ipsec.options.copy_dscp == 0) {
130 		if (!silent)
131 			RTE_LOG(INFO, USER1, "Copy DSCP is not supported\n");
132 		return -ENOTSUP;
133 	}
134 
135 	if (ipsec_xform->options.copy_flabel == 1 &&
136 	    sec_cap->ipsec.options.copy_flabel == 0) {
137 		if (!silent)
138 			RTE_LOG(INFO, USER1, "Copy Flow Label is not supported\n");
139 		return -ENOTSUP;
140 	}
141 
142 	if (ipsec_xform->options.copy_df == 1 &&
143 	    sec_cap->ipsec.options.copy_df == 0) {
144 		if (!silent)
145 			RTE_LOG(INFO, USER1, "Copy DP bit is not supported\n");
146 		return -ENOTSUP;
147 	}
148 
149 	if (ipsec_xform->options.dec_ttl == 1 &&
150 	    sec_cap->ipsec.options.dec_ttl == 0) {
151 		if (!silent)
152 			RTE_LOG(INFO, USER1, "Decrement TTL is not supported\n");
153 		return -ENOTSUP;
154 	}
155 
156 	if (ipsec_xform->options.ecn == 1 && sec_cap->ipsec.options.ecn == 0) {
157 		if (!silent)
158 			RTE_LOG(INFO, USER1, "ECN is not supported\n");
159 		return -ENOTSUP;
160 	}
161 
162 	if (ipsec_xform->options.stats == 1 &&
163 	    sec_cap->ipsec.options.stats == 0) {
164 		if (!silent)
165 			RTE_LOG(INFO, USER1, "Stats is not supported\n");
166 		return -ENOTSUP;
167 	}
168 
169 	if ((ipsec_xform->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) &&
170 	    (ipsec_xform->options.iv_gen_disable == 1) &&
171 	    (sec_cap->ipsec.options.iv_gen_disable != 1)) {
172 		if (!silent)
173 			RTE_LOG(INFO, USER1,
174 				"Application provided IV is not supported\n");
175 		return -ENOTSUP;
176 	}
177 
178 	if ((ipsec_xform->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
179 	    (ipsec_xform->options.tunnel_hdr_verify >
180 	    sec_cap->ipsec.options.tunnel_hdr_verify)) {
181 		if (!silent)
182 			RTE_LOG(INFO, USER1,
183 				"Tunnel header verify is not supported\n");
184 		return -ENOTSUP;
185 	}
186 
187 	if (ipsec_xform->options.ip_csum_enable == 1 &&
188 	    sec_cap->ipsec.options.ip_csum_enable == 0) {
189 		if (!silent)
190 			RTE_LOG(INFO, USER1,
191 				"Inner IP checksum is not supported\n");
192 		return -ENOTSUP;
193 	}
194 
195 	if (ipsec_xform->options.l4_csum_enable == 1 &&
196 	    sec_cap->ipsec.options.l4_csum_enable == 0) {
197 		if (!silent)
198 			RTE_LOG(INFO, USER1,
199 				"Inner L4 checksum is not supported\n");
200 		return -ENOTSUP;
201 	}
202 
203 	if (ipsec_xform->replay_win_sz > sec_cap->ipsec.replay_win_sz_max) {
204 		if (!silent)
205 			RTE_LOG(INFO, USER1,
206 				"Replay window size is not supported\n");
207 		return -ENOTSUP;
208 	}
209 
210 	return 0;
211 }
212 
213 int
214 test_ipsec_crypto_caps_aead_verify(
215 		const struct rte_security_capability *sec_cap,
216 		struct rte_crypto_sym_xform *aead)
217 {
218 	const struct rte_cryptodev_symmetric_capability *sym_cap;
219 	const struct rte_cryptodev_capabilities *crypto_cap;
220 	int j = 0;
221 
222 	while ((crypto_cap = &sec_cap->crypto_capabilities[j++])->op !=
223 			RTE_CRYPTO_OP_TYPE_UNDEFINED) {
224 		if (crypto_cap->op == RTE_CRYPTO_OP_TYPE_SYMMETRIC &&
225 				crypto_cap->sym.xform_type == aead->type &&
226 				crypto_cap->sym.aead.algo == aead->aead.algo) {
227 			sym_cap = &crypto_cap->sym;
228 			if (rte_cryptodev_sym_capability_check_aead(sym_cap,
229 					aead->aead.key.length,
230 					aead->aead.digest_length,
231 					aead->aead.aad_length,
232 					aead->aead.iv.length) == 0)
233 				return 0;
234 		}
235 	}
236 
237 	return -ENOTSUP;
238 }
239 
240 int
241 test_ipsec_crypto_caps_cipher_verify(
242 		const struct rte_security_capability *sec_cap,
243 		struct rte_crypto_sym_xform *cipher)
244 {
245 	const struct rte_cryptodev_symmetric_capability *sym_cap;
246 	const struct rte_cryptodev_capabilities *cap;
247 	int j = 0;
248 
249 	while ((cap = &sec_cap->crypto_capabilities[j++])->op !=
250 			RTE_CRYPTO_OP_TYPE_UNDEFINED) {
251 		if (cap->op == RTE_CRYPTO_OP_TYPE_SYMMETRIC &&
252 				cap->sym.xform_type == cipher->type &&
253 				cap->sym.cipher.algo == cipher->cipher.algo) {
254 			sym_cap = &cap->sym;
255 			if (rte_cryptodev_sym_capability_check_cipher(sym_cap,
256 					cipher->cipher.key.length,
257 					cipher->cipher.iv.length) == 0)
258 				return 0;
259 		}
260 	}
261 
262 	return -ENOTSUP;
263 }
264 
265 int
266 test_ipsec_crypto_caps_auth_verify(
267 		const struct rte_security_capability *sec_cap,
268 		struct rte_crypto_sym_xform *auth)
269 {
270 	const struct rte_cryptodev_symmetric_capability *sym_cap;
271 	const struct rte_cryptodev_capabilities *cap;
272 	int j = 0;
273 
274 	while ((cap = &sec_cap->crypto_capabilities[j++])->op !=
275 			RTE_CRYPTO_OP_TYPE_UNDEFINED) {
276 		if (cap->op == RTE_CRYPTO_OP_TYPE_SYMMETRIC &&
277 				cap->sym.xform_type == auth->type &&
278 				cap->sym.auth.algo == auth->auth.algo) {
279 			sym_cap = &cap->sym;
280 			if (rte_cryptodev_sym_capability_check_auth(sym_cap,
281 					auth->auth.key.length,
282 					auth->auth.digest_length,
283 					auth->auth.iv.length) == 0)
284 				return 0;
285 		}
286 	}
287 
288 	return -ENOTSUP;
289 }
290 
291 void
292 test_ipsec_td_in_from_out(const struct ipsec_test_data *td_out,
293 			  struct ipsec_test_data *td_in)
294 {
295 	memcpy(td_in, td_out, sizeof(*td_in));
296 
297 	/* Populate output text of td_in with input text of td_out */
298 	memcpy(td_in->output_text.data, td_out->input_text.data,
299 	       td_out->input_text.len);
300 	td_in->output_text.len = td_out->input_text.len;
301 
302 	/* Populate input text of td_in with output text of td_out */
303 	memcpy(td_in->input_text.data, td_out->output_text.data,
304 	       td_out->output_text.len);
305 	td_in->input_text.len = td_out->output_text.len;
306 
307 	td_in->ipsec_xform.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
308 
309 	if (td_in->aead) {
310 		td_in->xform.aead.aead.op = RTE_CRYPTO_AEAD_OP_DECRYPT;
311 	} else {
312 		td_in->xform.chain.auth.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
313 		td_in->xform.chain.cipher.cipher.op =
314 				RTE_CRYPTO_CIPHER_OP_DECRYPT;
315 	}
316 }
317 
318 static bool
319 is_ipv4(void *ip)
320 {
321 	struct rte_ipv4_hdr *ipv4 = ip;
322 	uint8_t ip_ver;
323 
324 	ip_ver = (ipv4->version_ihl & 0xf0) >> RTE_IPV4_IHL_MULTIPLIER;
325 	if (ip_ver == IPVERSION)
326 		return true;
327 	else
328 		return false;
329 }
330 
331 static void
332 test_ipsec_csum_init(void *ip, bool l3, bool l4)
333 {
334 	struct rte_ipv4_hdr *ipv4;
335 	struct rte_tcp_hdr *tcp;
336 	struct rte_udp_hdr *udp;
337 	uint8_t next_proto;
338 	uint8_t size;
339 
340 	if (is_ipv4(ip)) {
341 		ipv4 = ip;
342 		size = sizeof(struct rte_ipv4_hdr);
343 		next_proto = ipv4->next_proto_id;
344 
345 		if (l3)
346 			ipv4->hdr_checksum = 0;
347 	} else {
348 		size = sizeof(struct rte_ipv6_hdr);
349 		next_proto = ((struct rte_ipv6_hdr *)ip)->proto;
350 	}
351 
352 	if (l4) {
353 		switch (next_proto) {
354 		case IPPROTO_TCP:
355 			tcp = (struct rte_tcp_hdr *)RTE_PTR_ADD(ip, size);
356 			tcp->cksum = 0;
357 			break;
358 		case IPPROTO_UDP:
359 			udp = (struct rte_udp_hdr *)RTE_PTR_ADD(ip, size);
360 			udp->dgram_cksum = 0;
361 			break;
362 		default:
363 			return;
364 		}
365 	}
366 }
367 
368 void
369 test_ipsec_td_prepare(const struct crypto_param *param1,
370 		      const struct crypto_param *param2,
371 		      const struct ipsec_test_flags *flags,
372 		      struct ipsec_test_data *td_array,
373 		      int nb_td)
374 
375 {
376 	struct ipsec_test_data *td;
377 	int i;
378 
379 	memset(td_array, 0, nb_td * sizeof(*td));
380 
381 	for (i = 0; i < nb_td; i++) {
382 		td = &td_array[i];
383 
384 		/* Prepare fields based on param */
385 
386 		if (param1->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
387 			/* Copy template for packet & key fields */
388 			if (flags->ipv6)
389 				memcpy(td, &pkt_aes_256_gcm_v6, sizeof(*td));
390 			else
391 				memcpy(td, &pkt_aes_256_gcm, sizeof(*td));
392 
393 			td->aead = true;
394 			td->xform.aead.aead.algo = param1->alg.aead;
395 			td->xform.aead.aead.key.length = param1->key_length;
396 		} else {
397 			/* Copy template for packet & key fields */
398 			if (flags->ipv6)
399 				memcpy(td, &pkt_aes_128_cbc_hmac_sha256_v6,
400 					sizeof(*td));
401 			else
402 				memcpy(td, &pkt_aes_128_cbc_hmac_sha256,
403 					sizeof(*td));
404 
405 			td->aead = false;
406 
407 			if (param1->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
408 				td->xform.chain.auth.auth.algo =
409 						param1->alg.auth;
410 				td->xform.chain.auth.auth.key.length =
411 						param1->key_length;
412 				td->xform.chain.auth.auth.digest_length =
413 						param1->digest_length;
414 				td->auth_only = true;
415 
416 				if (td->xform.chain.auth.auth.algo == RTE_CRYPTO_AUTH_AES_GMAC) {
417 					td->xform.chain.auth.auth.iv.length =
418 						param1->iv_length;
419 					td->aes_gmac = true;
420 				}
421 			} else {
422 				td->xform.chain.cipher.cipher.algo =
423 						param1->alg.cipher;
424 				td->xform.chain.cipher.cipher.key.length =
425 						param1->key_length;
426 				td->xform.chain.cipher.cipher.iv.length =
427 						param1->iv_length;
428 				td->xform.chain.auth.auth.algo =
429 						param2->alg.auth;
430 				td->xform.chain.auth.auth.key.length =
431 						param2->key_length;
432 				td->xform.chain.auth.auth.digest_length =
433 						param2->digest_length;
434 
435 				if (td->xform.chain.auth.auth.algo == RTE_CRYPTO_AUTH_AES_GMAC) {
436 					td->xform.chain.auth.auth.iv.length =
437 						param2->iv_length;
438 					td->aes_gmac = true;
439 				}
440 			}
441 		}
442 
443 		if (flags->ah) {
444 			td->ipsec_xform.proto =
445 					RTE_SECURITY_IPSEC_SA_PROTO_AH;
446 		}
447 
448 		if (flags->iv_gen)
449 			td->ipsec_xform.options.iv_gen_disable = 0;
450 
451 		if (flags->sa_expiry_pkts_soft)
452 			td->ipsec_xform.life.packets_soft_limit =
453 					IPSEC_TEST_PACKETS_MAX - 1;
454 
455 		if (flags->ip_csum) {
456 			td->ipsec_xform.options.ip_csum_enable = 1;
457 			test_ipsec_csum_init(&td->input_text.data, true, false);
458 		}
459 
460 		if (flags->l4_csum) {
461 			td->ipsec_xform.options.l4_csum_enable = 1;
462 			test_ipsec_csum_init(&td->input_text.data, false, true);
463 		}
464 
465 		if (flags->transport) {
466 			td->ipsec_xform.mode =
467 					RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT;
468 		} else {
469 			td->ipsec_xform.mode =
470 					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL;
471 
472 			if (flags->tunnel_ipv6)
473 				td->ipsec_xform.tunnel.type =
474 						RTE_SECURITY_IPSEC_TUNNEL_IPV6;
475 			else
476 				td->ipsec_xform.tunnel.type =
477 						RTE_SECURITY_IPSEC_TUNNEL_IPV4;
478 		}
479 
480 		if (flags->stats_success)
481 			td->ipsec_xform.options.stats = 1;
482 
483 		if (flags->fragment) {
484 			struct rte_ipv4_hdr *ip;
485 			ip = (struct rte_ipv4_hdr *)&td->input_text.data;
486 			ip->fragment_offset = 4;
487 			ip->hdr_checksum = rte_ipv4_cksum(ip);
488 		}
489 
490 		if (flags->df == TEST_IPSEC_COPY_DF_INNER_0 ||
491 		    flags->df == TEST_IPSEC_COPY_DF_INNER_1)
492 			td->ipsec_xform.options.copy_df = 1;
493 
494 		if (flags->dscp == TEST_IPSEC_COPY_DSCP_INNER_0 ||
495 		    flags->dscp == TEST_IPSEC_COPY_DSCP_INNER_1)
496 			td->ipsec_xform.options.copy_dscp = 1;
497 
498 		if (flags->dec_ttl_or_hop_limit)
499 			td->ipsec_xform.options.dec_ttl = 1;
500 	}
501 }
502 
503 void
504 test_ipsec_td_update(struct ipsec_test_data td_inb[],
505 		     const struct ipsec_test_data td_outb[],
506 		     int nb_td,
507 		     const struct ipsec_test_flags *flags)
508 {
509 	int i;
510 
511 	for (i = 0; i < nb_td; i++) {
512 		memcpy(td_inb[i].output_text.data, td_outb[i].input_text.data,
513 		       td_outb[i].input_text.len);
514 		td_inb[i].output_text.len = td_outb->input_text.len;
515 
516 		if (flags->icv_corrupt) {
517 			int icv_pos = td_inb[i].input_text.len - 4;
518 			td_inb[i].input_text.data[icv_pos] += 1;
519 		}
520 
521 		if (flags->sa_expiry_pkts_hard)
522 			td_inb[i].ipsec_xform.life.packets_hard_limit =
523 					IPSEC_TEST_PACKETS_MAX - 1;
524 
525 		if (flags->udp_encap)
526 			td_inb[i].ipsec_xform.options.udp_encap = 1;
527 
528 		if (flags->udp_ports_verify)
529 			td_inb[i].ipsec_xform.options.udp_ports_verify = 1;
530 
531 		td_inb[i].ipsec_xform.options.tunnel_hdr_verify =
532 			flags->tunnel_hdr_verify;
533 
534 		if (flags->ip_csum)
535 			td_inb[i].ipsec_xform.options.ip_csum_enable = 1;
536 
537 		if (flags->l4_csum)
538 			td_inb[i].ipsec_xform.options.l4_csum_enable = 1;
539 
540 		/* Clear outbound specific flags */
541 		td_inb[i].ipsec_xform.options.iv_gen_disable = 0;
542 	}
543 }
544 
545 void
546 test_ipsec_display_alg(const struct crypto_param *param1,
547 		       const struct crypto_param *param2)
548 {
549 	if (param1->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
550 		printf("\t%s [%d]",
551 		       rte_crypto_aead_algorithm_strings[param1->alg.aead],
552 		       param1->key_length * 8);
553 	} else if (param1->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
554 		printf("\t%s",
555 		       rte_crypto_auth_algorithm_strings[param1->alg.auth]);
556 		if (param1->alg.auth != RTE_CRYPTO_AUTH_NULL)
557 			printf(" [%dB ICV]", param1->digest_length);
558 	} else {
559 		printf("\t%s",
560 		       rte_crypto_cipher_algorithm_strings[param1->alg.cipher]);
561 		if (param1->alg.cipher != RTE_CRYPTO_CIPHER_NULL)
562 			printf(" [%d]", param1->key_length * 8);
563 		printf(" %s",
564 		       rte_crypto_auth_algorithm_strings[param2->alg.auth]);
565 		if (param2->alg.auth != RTE_CRYPTO_AUTH_NULL)
566 			printf(" [%dB ICV]", param2->digest_length);
567 	}
568 	printf("\n");
569 }
570 
571 static int
572 test_ipsec_tunnel_hdr_len_get(const struct ipsec_test_data *td)
573 {
574 	int len = 0;
575 
576 	if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
577 		if (td->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
578 			if (td->ipsec_xform.tunnel.type ==
579 					RTE_SECURITY_IPSEC_TUNNEL_IPV4)
580 				len += sizeof(struct rte_ipv4_hdr);
581 			else
582 				len += sizeof(struct rte_ipv6_hdr);
583 		}
584 	}
585 
586 	return len;
587 }
588 
589 static int
590 test_ipsec_iv_verify_push(struct rte_mbuf *m, const struct ipsec_test_data *td)
591 {
592 	static uint8_t iv_queue[IV_LEN_MAX * IPSEC_TEST_PACKETS_MAX];
593 	uint8_t *iv_tmp, *output_text = rte_pktmbuf_mtod(m, uint8_t *);
594 	int i, iv_pos, iv_len;
595 	static int index;
596 
597 	if (td->aead)
598 		iv_len = td->xform.aead.aead.iv.length - td->salt.len;
599 	else
600 		iv_len = td->xform.chain.cipher.cipher.iv.length;
601 
602 	iv_pos = test_ipsec_tunnel_hdr_len_get(td) + sizeof(struct rte_esp_hdr);
603 	output_text += iv_pos;
604 
605 	TEST_ASSERT(iv_len <= IV_LEN_MAX, "IV length greater than supported");
606 
607 	/* Compare against previous values */
608 	for (i = 0; i < index; i++) {
609 		iv_tmp = &iv_queue[i * IV_LEN_MAX];
610 
611 		if (memcmp(output_text, iv_tmp, iv_len) == 0) {
612 			printf("IV repeated");
613 			return TEST_FAILED;
614 		}
615 	}
616 
617 	/* Save IV for future comparisons */
618 
619 	iv_tmp = &iv_queue[index * IV_LEN_MAX];
620 	memcpy(iv_tmp, output_text, iv_len);
621 	index++;
622 
623 	if (index == IPSEC_TEST_PACKETS_MAX)
624 		index = 0;
625 
626 	return TEST_SUCCESS;
627 }
628 
629 static int
630 test_ipsec_l3_csum_verify(struct rte_mbuf *m)
631 {
632 	uint16_t actual_cksum, expected_cksum;
633 	struct rte_ipv4_hdr *ip;
634 
635 	ip = rte_pktmbuf_mtod(m, struct rte_ipv4_hdr *);
636 
637 	if (!is_ipv4((void *)ip))
638 		return TEST_SKIPPED;
639 
640 	actual_cksum = ip->hdr_checksum;
641 
642 	ip->hdr_checksum = 0;
643 
644 	expected_cksum = rte_ipv4_cksum(ip);
645 
646 	if (actual_cksum != expected_cksum)
647 		return TEST_FAILED;
648 
649 	return TEST_SUCCESS;
650 }
651 
652 static int
653 test_ipsec_l4_csum_verify(struct rte_mbuf *m)
654 {
655 	uint16_t actual_cksum = 0, expected_cksum = 0;
656 	struct rte_ipv4_hdr *ipv4;
657 	struct rte_ipv6_hdr *ipv6;
658 	struct rte_tcp_hdr *tcp;
659 	struct rte_udp_hdr *udp;
660 	void *ip, *l4;
661 
662 	ip = rte_pktmbuf_mtod(m, void *);
663 
664 	if (is_ipv4(ip)) {
665 		ipv4 = ip;
666 		l4 = RTE_PTR_ADD(ipv4, sizeof(struct rte_ipv4_hdr));
667 
668 		switch (ipv4->next_proto_id) {
669 		case IPPROTO_TCP:
670 			tcp = (struct rte_tcp_hdr *)l4;
671 			actual_cksum = tcp->cksum;
672 			tcp->cksum = 0;
673 			expected_cksum = rte_ipv4_udptcp_cksum(ipv4, l4);
674 			break;
675 		case IPPROTO_UDP:
676 			udp = (struct rte_udp_hdr *)l4;
677 			actual_cksum = udp->dgram_cksum;
678 			udp->dgram_cksum = 0;
679 			expected_cksum = rte_ipv4_udptcp_cksum(ipv4, l4);
680 			break;
681 		default:
682 			break;
683 		}
684 	} else {
685 		ipv6 = ip;
686 		l4 = RTE_PTR_ADD(ipv6, sizeof(struct rte_ipv6_hdr));
687 
688 		switch (ipv6->proto) {
689 		case IPPROTO_TCP:
690 			tcp = (struct rte_tcp_hdr *)l4;
691 			actual_cksum = tcp->cksum;
692 			tcp->cksum = 0;
693 			expected_cksum = rte_ipv6_udptcp_cksum(ipv6, l4);
694 			break;
695 		case IPPROTO_UDP:
696 			udp = (struct rte_udp_hdr *)l4;
697 			actual_cksum = udp->dgram_cksum;
698 			udp->dgram_cksum = 0;
699 			expected_cksum = rte_ipv6_udptcp_cksum(ipv6, l4);
700 			break;
701 		default:
702 			break;
703 		}
704 	}
705 
706 	if (actual_cksum != expected_cksum)
707 		return TEST_FAILED;
708 
709 	return TEST_SUCCESS;
710 }
711 
712 static int
713 test_ipsec_ttl_or_hop_decrement_verify(void *received, void *expected)
714 {
715 	struct rte_ipv4_hdr *iph4_ex, *iph4_re;
716 	struct rte_ipv6_hdr *iph6_ex, *iph6_re;
717 
718 	if (is_ipv4(received) && is_ipv4(expected)) {
719 		iph4_ex = expected;
720 		iph4_re = received;
721 		iph4_ex->time_to_live -= 1;
722 		if (iph4_re->time_to_live != iph4_ex->time_to_live)
723 			return TEST_FAILED;
724 	} else if (!is_ipv4(received) && !is_ipv4(expected)) {
725 		iph6_ex = expected;
726 		iph6_re = received;
727 		iph6_ex->hop_limits -= 1;
728 		if (iph6_re->hop_limits != iph6_ex->hop_limits)
729 			return TEST_FAILED;
730 	} else {
731 		printf("IP header version miss match\n");
732 		return TEST_FAILED;
733 	}
734 
735 	return TEST_SUCCESS;
736 }
737 
738 static int
739 test_ipsec_td_verify(struct rte_mbuf *m, const struct ipsec_test_data *td,
740 		     bool silent, const struct ipsec_test_flags *flags)
741 {
742 	uint8_t *output_text = rte_pktmbuf_mtod(m, uint8_t *);
743 	uint32_t skip, len = rte_pktmbuf_pkt_len(m);
744 	uint8_t td_output_text[4096];
745 	int ret;
746 
747 	/* For tests with status as error for test success, skip verification */
748 	if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS &&
749 	    (flags->icv_corrupt ||
750 	     flags->sa_expiry_pkts_hard ||
751 	     flags->tunnel_hdr_verify ||
752 	     td->ar_packet))
753 		return TEST_SUCCESS;
754 
755 	if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS &&
756 	   flags->udp_encap) {
757 		const struct rte_ipv4_hdr *iph4;
758 		const struct rte_ipv6_hdr *iph6;
759 
760 		if (td->ipsec_xform.tunnel.type ==
761 				RTE_SECURITY_IPSEC_TUNNEL_IPV4) {
762 			iph4 = (const struct rte_ipv4_hdr *)output_text;
763 			if (iph4->next_proto_id != IPPROTO_UDP) {
764 				printf("UDP header is not found\n");
765 				return TEST_FAILED;
766 			}
767 		} else {
768 			iph6 = (const struct rte_ipv6_hdr *)output_text;
769 			if (iph6->proto != IPPROTO_UDP) {
770 				printf("UDP header is not found\n");
771 				return TEST_FAILED;
772 			}
773 		}
774 
775 		len -= sizeof(struct rte_udp_hdr);
776 		output_text += sizeof(struct rte_udp_hdr);
777 	}
778 
779 	if (len != td->output_text.len) {
780 		printf("Output length (%d) not matching with expected (%d)\n",
781 			len, td->output_text.len);
782 		return TEST_FAILED;
783 	}
784 
785 	if ((td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) &&
786 				flags->fragment) {
787 		const struct rte_ipv4_hdr *iph4;
788 		iph4 = (const struct rte_ipv4_hdr *)output_text;
789 		if (iph4->fragment_offset) {
790 			printf("Output packet is fragmented");
791 			return TEST_FAILED;
792 		}
793 	}
794 
795 	skip = test_ipsec_tunnel_hdr_len_get(td);
796 
797 	len -= skip;
798 	output_text += skip;
799 
800 	if ((td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
801 				flags->ip_csum) {
802 		if (m->ol_flags & RTE_MBUF_F_RX_IP_CKSUM_GOOD)
803 			ret = test_ipsec_l3_csum_verify(m);
804 		else
805 			ret = TEST_FAILED;
806 
807 		if (ret == TEST_FAILED)
808 			printf("Inner IP checksum test failed\n");
809 
810 		return ret;
811 	}
812 
813 	if ((td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
814 				flags->l4_csum) {
815 		if (m->ol_flags & RTE_MBUF_F_RX_L4_CKSUM_GOOD)
816 			ret = test_ipsec_l4_csum_verify(m);
817 		else
818 			ret = TEST_FAILED;
819 
820 		if (ret == TEST_FAILED)
821 			printf("Inner L4 checksum test failed\n");
822 
823 		return ret;
824 	}
825 
826 	memcpy(td_output_text, td->output_text.data + skip, len);
827 
828 	if ((td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
829 				flags->dec_ttl_or_hop_limit) {
830 		if (test_ipsec_ttl_or_hop_decrement_verify(output_text, td_output_text)) {
831 			printf("Inner TTL/hop limit decrement test failed\n");
832 			return TEST_FAILED;
833 		}
834 	}
835 
836 	if (test_ipsec_pkt_update(td_output_text, flags)) {
837 		printf("Could not update expected vector");
838 		return TEST_FAILED;
839 	}
840 
841 	if (memcmp(output_text, td_output_text, len)) {
842 		if (silent)
843 			return TEST_FAILED;
844 
845 		printf("TestCase %s line %d: %s\n", __func__, __LINE__,
846 			"output text not as expected\n");
847 
848 		rte_hexdump(stdout, "expected", td_output_text, len);
849 		rte_hexdump(stdout, "actual", output_text, len);
850 		return TEST_FAILED;
851 	}
852 
853 	return TEST_SUCCESS;
854 }
855 
856 static int
857 test_ipsec_res_d_prepare(struct rte_mbuf *m, const struct ipsec_test_data *td,
858 		   struct ipsec_test_data *res_d)
859 {
860 	uint8_t *output_text = rte_pktmbuf_mtod(m, uint8_t *);
861 	uint32_t len = rte_pktmbuf_pkt_len(m);
862 
863 	memcpy(res_d, td, sizeof(*res_d));
864 	memcpy(res_d->input_text.data, output_text, len);
865 	res_d->input_text.len = len;
866 
867 	res_d->ipsec_xform.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
868 	if (res_d->aead) {
869 		res_d->xform.aead.aead.op = RTE_CRYPTO_AEAD_OP_DECRYPT;
870 	} else {
871 		res_d->xform.chain.cipher.cipher.op =
872 				RTE_CRYPTO_CIPHER_OP_DECRYPT;
873 		res_d->xform.chain.auth.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
874 	}
875 
876 	return TEST_SUCCESS;
877 }
878 
879 static int
880 test_ipsec_iph4_hdr_validate(const struct rte_ipv4_hdr *iph4,
881 			     const struct ipsec_test_flags *flags)
882 {
883 	uint8_t tos, dscp;
884 	uint16_t f_off;
885 
886 	if (!is_valid_ipv4_pkt(iph4)) {
887 		printf("Tunnel outer header is not IPv4\n");
888 		return -1;
889 	}
890 
891 	if (flags->ah && iph4->next_proto_id != IPPROTO_AH) {
892 		printf("Tunnel outer header proto is not AH\n");
893 		return -1;
894 	}
895 
896 	f_off = rte_be_to_cpu_16(iph4->fragment_offset);
897 	if (flags->df == TEST_IPSEC_COPY_DF_INNER_1 ||
898 	    flags->df == TEST_IPSEC_SET_DF_1_INNER_0) {
899 		if (!(f_off & RTE_IPV4_HDR_DF_FLAG)) {
900 			printf("DF bit is not set\n");
901 			return -1;
902 		}
903 	} else {
904 		if (f_off & RTE_IPV4_HDR_DF_FLAG) {
905 			printf("DF bit is set\n");
906 			return -1;
907 		}
908 	}
909 
910 	tos = iph4->type_of_service;
911 	dscp = (tos & RTE_IPV4_HDR_DSCP_MASK) >> 2;
912 
913 	if (flags->dscp == TEST_IPSEC_COPY_DSCP_INNER_1 ||
914 	    flags->dscp == TEST_IPSEC_SET_DSCP_1_INNER_0) {
915 		if (dscp != TEST_IPSEC_DSCP_VAL) {
916 			printf("DSCP value is not matching [exp: %x, actual: %x]\n",
917 			       TEST_IPSEC_DSCP_VAL, dscp);
918 			return -1;
919 		}
920 	} else {
921 		if (dscp != 0) {
922 			printf("DSCP value is set [exp: 0, actual: %x]\n",
923 			       dscp);
924 			return -1;
925 		}
926 	}
927 
928 	return 0;
929 }
930 
931 static int
932 test_ipsec_iph6_hdr_validate(const struct rte_ipv6_hdr *iph6,
933 			     const struct ipsec_test_flags *flags)
934 {
935 	uint32_t vtc_flow;
936 	uint8_t dscp;
937 
938 	if (!is_valid_ipv6_pkt(iph6)) {
939 		printf("Tunnel outer header is not IPv6\n");
940 		return -1;
941 	}
942 
943 	vtc_flow = rte_be_to_cpu_32(iph6->vtc_flow);
944 	dscp = (vtc_flow & RTE_IPV6_HDR_DSCP_MASK) >>
945 	       (RTE_IPV6_HDR_TC_SHIFT + 2);
946 
947 	if (flags->dscp == TEST_IPSEC_COPY_DSCP_INNER_1 ||
948 	    flags->dscp == TEST_IPSEC_SET_DSCP_1_INNER_0) {
949 		if (dscp != TEST_IPSEC_DSCP_VAL) {
950 			printf("DSCP value is not matching [exp: %x, actual: %x]\n",
951 			       TEST_IPSEC_DSCP_VAL, dscp);
952 			return -1;
953 		}
954 	} else {
955 		if (dscp != 0) {
956 			printf("DSCP value is set [exp: 0, actual: %x]\n",
957 			       dscp);
958 			return -1;
959 		}
960 	}
961 
962 	return 0;
963 }
964 
965 int
966 test_ipsec_post_process(struct rte_mbuf *m, const struct ipsec_test_data *td,
967 			struct ipsec_test_data *res_d, bool silent,
968 			const struct ipsec_test_flags *flags)
969 {
970 	uint8_t *output_text = rte_pktmbuf_mtod(m, uint8_t *);
971 	int ret;
972 
973 	if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
974 		const struct rte_ipv4_hdr *iph4;
975 		const struct rte_ipv6_hdr *iph6;
976 
977 		if (flags->iv_gen) {
978 			ret = test_ipsec_iv_verify_push(m, td);
979 			if (ret != TEST_SUCCESS)
980 				return ret;
981 		}
982 
983 		iph4 = (const struct rte_ipv4_hdr *)output_text;
984 
985 		if (td->ipsec_xform.mode ==
986 				RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT) {
987 			if (flags->ipv6) {
988 				iph6 = (const struct rte_ipv6_hdr *)output_text;
989 				if (is_valid_ipv6_pkt(iph6) == false) {
990 					printf("Transport packet is not IPv6\n");
991 					return TEST_FAILED;
992 				}
993 			} else {
994 				if (is_valid_ipv4_pkt(iph4) == false) {
995 					printf("Transport packet is not IPv4\n");
996 					return TEST_FAILED;
997 				}
998 
999 				if (flags->ah && iph4->next_proto_id != IPPROTO_AH) {
1000 					printf("Transport IPv4 header proto is not AH\n");
1001 					return -1;
1002 				}
1003 			}
1004 		} else {
1005 			if (td->ipsec_xform.tunnel.type ==
1006 					RTE_SECURITY_IPSEC_TUNNEL_IPV4) {
1007 				if (test_ipsec_iph4_hdr_validate(iph4, flags))
1008 					return TEST_FAILED;
1009 			} else {
1010 				iph6 = (const struct rte_ipv6_hdr *)output_text;
1011 				if (test_ipsec_iph6_hdr_validate(iph6, flags))
1012 					return TEST_FAILED;
1013 			}
1014 		}
1015 	}
1016 
1017 	/*
1018 	 * In case of known vector tests & all inbound tests, res_d provided
1019 	 * would be NULL and output data need to be validated against expected.
1020 	 * For inbound, output_text would be plain packet and for outbound
1021 	 * output_text would IPsec packet. Validate by comparing against
1022 	 * known vectors.
1023 	 *
1024 	 * In case of combined mode tests, the output_text from outbound
1025 	 * operation (ie, IPsec packet) would need to be inbound processed to
1026 	 * obtain the plain text. Copy output_text to result data, 'res_d', so
1027 	 * that inbound processing can be done.
1028 	 */
1029 
1030 	if (res_d == NULL)
1031 		return test_ipsec_td_verify(m, td, silent, flags);
1032 	else
1033 		return test_ipsec_res_d_prepare(m, td, res_d);
1034 }
1035 
1036 int
1037 test_ipsec_status_check(const struct ipsec_test_data *td,
1038 			struct rte_crypto_op *op,
1039 			const struct ipsec_test_flags *flags,
1040 			enum rte_security_ipsec_sa_direction dir,
1041 			int pkt_num)
1042 {
1043 	int ret = TEST_SUCCESS;
1044 
1045 	if ((dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
1046 	    td->ar_packet) {
1047 		if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) {
1048 			printf("Anti replay test case failed\n");
1049 			return TEST_FAILED;
1050 		} else {
1051 			return TEST_SUCCESS;
1052 		}
1053 	}
1054 
1055 	if (dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS &&
1056 	    flags->sa_expiry_pkts_hard &&
1057 	    pkt_num == IPSEC_TEST_PACKETS_MAX) {
1058 		if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) {
1059 			printf("SA hard expiry (pkts) test failed\n");
1060 			return TEST_FAILED;
1061 		} else {
1062 			return TEST_SUCCESS;
1063 		}
1064 	}
1065 
1066 	if ((dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
1067 	    flags->tunnel_hdr_verify) {
1068 		if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) {
1069 			printf("Tunnel header verify test case failed\n");
1070 			return TEST_FAILED;
1071 		} else {
1072 			return TEST_SUCCESS;
1073 		}
1074 	}
1075 
1076 	if (dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS && flags->icv_corrupt) {
1077 		if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) {
1078 			printf("ICV corruption test case failed\n");
1079 			ret = TEST_FAILED;
1080 		}
1081 	} else {
1082 		if (op->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
1083 			printf("Security op processing failed [pkt_num: %d]\n",
1084 			       pkt_num);
1085 			ret = TEST_FAILED;
1086 		}
1087 	}
1088 
1089 	if (flags->sa_expiry_pkts_soft && pkt_num == IPSEC_TEST_PACKETS_MAX) {
1090 		if (!(op->aux_flags &
1091 		      RTE_CRYPTO_OP_AUX_FLAGS_IPSEC_SOFT_EXPIRY)) {
1092 			printf("SA soft expiry (pkts) test failed\n");
1093 			ret = TEST_FAILED;
1094 		}
1095 	}
1096 
1097 	return ret;
1098 }
1099 
1100 int
1101 test_ipsec_stats_verify(struct rte_security_ctx *ctx,
1102 			struct rte_security_session *sess,
1103 			const struct ipsec_test_flags *flags,
1104 			enum rte_security_ipsec_sa_direction dir)
1105 {
1106 	struct rte_security_stats stats = {0};
1107 	int ret = TEST_SUCCESS;
1108 
1109 	if (flags->stats_success) {
1110 		if (rte_security_session_stats_get(ctx, sess, &stats) < 0)
1111 			return TEST_FAILED;
1112 
1113 		if (dir == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
1114 			if (stats.ipsec.opackets != 1 ||
1115 			    stats.ipsec.oerrors != 0)
1116 				ret = TEST_FAILED;
1117 		} else {
1118 			if (stats.ipsec.ipackets != 1 ||
1119 			    stats.ipsec.ierrors != 0)
1120 				ret = TEST_FAILED;
1121 		}
1122 	}
1123 
1124 	return ret;
1125 }
1126 
1127 int
1128 test_ipsec_pkt_update(uint8_t *pkt, const struct ipsec_test_flags *flags)
1129 {
1130 	struct rte_ipv4_hdr *iph4;
1131 	struct rte_ipv6_hdr *iph6;
1132 	bool cksum_dirty = false;
1133 
1134 	iph4 = (struct rte_ipv4_hdr *)pkt;
1135 
1136 	if (flags->df == TEST_IPSEC_COPY_DF_INNER_1 ||
1137 	    flags->df == TEST_IPSEC_SET_DF_0_INNER_1 ||
1138 	    flags->df == TEST_IPSEC_COPY_DF_INNER_0 ||
1139 	    flags->df == TEST_IPSEC_SET_DF_1_INNER_0) {
1140 		uint16_t frag_off;
1141 
1142 		if (!is_ipv4(iph4)) {
1143 			printf("Invalid packet type\n");
1144 			return -1;
1145 		}
1146 
1147 		frag_off = rte_be_to_cpu_16(iph4->fragment_offset);
1148 
1149 		if (flags->df == TEST_IPSEC_COPY_DF_INNER_1 ||
1150 		    flags->df == TEST_IPSEC_SET_DF_0_INNER_1)
1151 			frag_off |= RTE_IPV4_HDR_DF_FLAG;
1152 		else
1153 			frag_off &= ~RTE_IPV4_HDR_DF_FLAG;
1154 
1155 		iph4->fragment_offset = rte_cpu_to_be_16(frag_off);
1156 		cksum_dirty = true;
1157 	}
1158 
1159 	if (flags->dscp == TEST_IPSEC_COPY_DSCP_INNER_1 ||
1160 	    flags->dscp == TEST_IPSEC_SET_DSCP_0_INNER_1 ||
1161 	    flags->dscp == TEST_IPSEC_COPY_DSCP_INNER_0 ||
1162 	    flags->dscp == TEST_IPSEC_SET_DSCP_1_INNER_0) {
1163 
1164 		if (is_ipv4(iph4)) {
1165 			uint8_t tos;
1166 
1167 			tos = iph4->type_of_service;
1168 			if (flags->dscp == TEST_IPSEC_COPY_DSCP_INNER_1 ||
1169 			    flags->dscp == TEST_IPSEC_SET_DSCP_0_INNER_1)
1170 				tos |= (RTE_IPV4_HDR_DSCP_MASK &
1171 					(TEST_IPSEC_DSCP_VAL << 2));
1172 			else
1173 				tos &= ~RTE_IPV4_HDR_DSCP_MASK;
1174 
1175 			iph4->type_of_service = tos;
1176 			cksum_dirty = true;
1177 		} else {
1178 			uint32_t vtc_flow;
1179 
1180 			iph6 = (struct rte_ipv6_hdr *)pkt;
1181 
1182 			vtc_flow = rte_be_to_cpu_32(iph6->vtc_flow);
1183 			if (flags->dscp == TEST_IPSEC_COPY_DSCP_INNER_1 ||
1184 			    flags->dscp == TEST_IPSEC_SET_DSCP_0_INNER_1)
1185 				vtc_flow |= (RTE_IPV6_HDR_DSCP_MASK &
1186 					     (TEST_IPSEC_DSCP_VAL << (RTE_IPV6_HDR_TC_SHIFT + 2)));
1187 			else
1188 				vtc_flow &= ~RTE_IPV6_HDR_DSCP_MASK;
1189 
1190 			iph6->vtc_flow = rte_cpu_to_be_32(vtc_flow);
1191 		}
1192 	}
1193 
1194 	if (cksum_dirty && is_ipv4(iph4)) {
1195 		iph4->hdr_checksum = 0;
1196 		iph4->hdr_checksum = rte_ipv4_cksum(iph4);
1197 	}
1198 
1199 	return 0;
1200 }
1201 
1202 #endif /* !RTE_EXEC_ENV_WINDOWS */
1203