1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4 
5 #include <rte_common.h>
6 #include <rte_cryptodev.h>
7 #include <rte_esp.h>
8 #include <rte_ip.h>
9 #include <rte_security.h>
10 #include <rte_tcp.h>
11 #include <rte_udp.h>
12 
13 #include "test.h"
14 #include "test_cryptodev_security_ipsec.h"
15 
16 #define IV_LEN_MAX 16
17 
18 struct crypto_param_comb alg_list[RTE_DIM(aead_list) +
19 				  (RTE_DIM(cipher_list) *
20 				   RTE_DIM(auth_list))];
21 
22 static bool
23 is_valid_ipv4_pkt(const struct rte_ipv4_hdr *pkt)
24 {
25 	/* The IP version number must be 4 */
26 	if (((pkt->version_ihl) >> 4) != 4)
27 		return false;
28 	/*
29 	 * The IP header length field must be large enough to hold the
30 	 * minimum length legal IP datagram (20 bytes = 5 words).
31 	 */
32 	if ((pkt->version_ihl & 0xf) < 5)
33 		return false;
34 
35 	/*
36 	 * The IP total length field must be large enough to hold the IP
37 	 * datagram header, whose length is specified in the IP header length
38 	 * field.
39 	 */
40 	if (rte_cpu_to_be_16(pkt->total_length) < sizeof(struct rte_ipv4_hdr))
41 		return false;
42 
43 	return true;
44 }
45 
46 static bool
47 is_valid_ipv6_pkt(const struct rte_ipv6_hdr *pkt)
48 {
49 	/* The IP version number must be 6 */
50 	if ((rte_be_to_cpu_32((pkt->vtc_flow)) >> 28) != 6)
51 		return false;
52 
53 	return true;
54 }
55 
56 void
57 test_ipsec_alg_list_populate(void)
58 {
59 	unsigned long i, j, index = 0;
60 
61 	for (i = 0; i < RTE_DIM(aead_list); i++) {
62 		alg_list[index].param1 = &aead_list[i];
63 		alg_list[index].param2 = NULL;
64 		index++;
65 	}
66 
67 	for (i = 0; i < RTE_DIM(cipher_list); i++) {
68 		for (j = 0; j < RTE_DIM(auth_list); j++) {
69 			alg_list[index].param1 = &cipher_list[i];
70 			alg_list[index].param2 = &auth_list[j];
71 			index++;
72 		}
73 	}
74 }
75 
76 int
77 test_ipsec_sec_caps_verify(struct rte_security_ipsec_xform *ipsec_xform,
78 			   const struct rte_security_capability *sec_cap,
79 			   bool silent)
80 {
81 	/* Verify security capabilities */
82 
83 	if (ipsec_xform->options.esn == 1 && sec_cap->ipsec.options.esn == 0) {
84 		if (!silent)
85 			RTE_LOG(INFO, USER1, "ESN is not supported\n");
86 		return -ENOTSUP;
87 	}
88 
89 	if (ipsec_xform->options.udp_encap == 1 &&
90 	    sec_cap->ipsec.options.udp_encap == 0) {
91 		if (!silent)
92 			RTE_LOG(INFO, USER1, "UDP encapsulation is not supported\n");
93 		return -ENOTSUP;
94 	}
95 
96 	if (ipsec_xform->options.udp_ports_verify == 1 &&
97 	    sec_cap->ipsec.options.udp_ports_verify == 0) {
98 		if (!silent)
99 			RTE_LOG(INFO, USER1, "UDP encapsulation ports "
100 				"verification is not supported\n");
101 		return -ENOTSUP;
102 	}
103 
104 	if (ipsec_xform->options.copy_dscp == 1 &&
105 	    sec_cap->ipsec.options.copy_dscp == 0) {
106 		if (!silent)
107 			RTE_LOG(INFO, USER1, "Copy DSCP is not supported\n");
108 		return -ENOTSUP;
109 	}
110 
111 	if (ipsec_xform->options.copy_flabel == 1 &&
112 	    sec_cap->ipsec.options.copy_flabel == 0) {
113 		if (!silent)
114 			RTE_LOG(INFO, USER1, "Copy Flow Label is not supported\n");
115 		return -ENOTSUP;
116 	}
117 
118 	if (ipsec_xform->options.copy_df == 1 &&
119 	    sec_cap->ipsec.options.copy_df == 0) {
120 		if (!silent)
121 			RTE_LOG(INFO, USER1, "Copy DP bit is not supported\n");
122 		return -ENOTSUP;
123 	}
124 
125 	if (ipsec_xform->options.dec_ttl == 1 &&
126 	    sec_cap->ipsec.options.dec_ttl == 0) {
127 		if (!silent)
128 			RTE_LOG(INFO, USER1, "Decrement TTL is not supported\n");
129 		return -ENOTSUP;
130 	}
131 
132 	if (ipsec_xform->options.ecn == 1 && sec_cap->ipsec.options.ecn == 0) {
133 		if (!silent)
134 			RTE_LOG(INFO, USER1, "ECN is not supported\n");
135 		return -ENOTSUP;
136 	}
137 
138 	if (ipsec_xform->options.stats == 1 &&
139 	    sec_cap->ipsec.options.stats == 0) {
140 		if (!silent)
141 			RTE_LOG(INFO, USER1, "Stats is not supported\n");
142 		return -ENOTSUP;
143 	}
144 
145 	if ((ipsec_xform->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) &&
146 	    (ipsec_xform->options.iv_gen_disable == 1) &&
147 	    (sec_cap->ipsec.options.iv_gen_disable != 1)) {
148 		if (!silent)
149 			RTE_LOG(INFO, USER1,
150 				"Application provided IV is not supported\n");
151 		return -ENOTSUP;
152 	}
153 
154 	if ((ipsec_xform->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
155 	    (ipsec_xform->options.tunnel_hdr_verify >
156 	    sec_cap->ipsec.options.tunnel_hdr_verify)) {
157 		if (!silent)
158 			RTE_LOG(INFO, USER1,
159 				"Tunnel header verify is not supported\n");
160 		return -ENOTSUP;
161 	}
162 
163 	if (ipsec_xform->options.ip_csum_enable == 1 &&
164 	    sec_cap->ipsec.options.ip_csum_enable == 0) {
165 		if (!silent)
166 			RTE_LOG(INFO, USER1,
167 				"Inner IP checksum is not supported\n");
168 		return -ENOTSUP;
169 	}
170 
171 	if (ipsec_xform->options.l4_csum_enable == 1 &&
172 	    sec_cap->ipsec.options.l4_csum_enable == 0) {
173 		if (!silent)
174 			RTE_LOG(INFO, USER1,
175 				"Inner L4 checksum is not supported\n");
176 		return -ENOTSUP;
177 	}
178 
179 	return 0;
180 }
181 
182 int
183 test_ipsec_crypto_caps_aead_verify(
184 		const struct rte_security_capability *sec_cap,
185 		struct rte_crypto_sym_xform *aead)
186 {
187 	const struct rte_cryptodev_symmetric_capability *sym_cap;
188 	const struct rte_cryptodev_capabilities *crypto_cap;
189 	int j = 0;
190 
191 	while ((crypto_cap = &sec_cap->crypto_capabilities[j++])->op !=
192 			RTE_CRYPTO_OP_TYPE_UNDEFINED) {
193 		if (crypto_cap->op == RTE_CRYPTO_OP_TYPE_SYMMETRIC &&
194 				crypto_cap->sym.xform_type == aead->type &&
195 				crypto_cap->sym.aead.algo == aead->aead.algo) {
196 			sym_cap = &crypto_cap->sym;
197 			if (rte_cryptodev_sym_capability_check_aead(sym_cap,
198 					aead->aead.key.length,
199 					aead->aead.digest_length,
200 					aead->aead.aad_length,
201 					aead->aead.iv.length) == 0)
202 				return 0;
203 		}
204 	}
205 
206 	return -ENOTSUP;
207 }
208 
209 int
210 test_ipsec_crypto_caps_cipher_verify(
211 		const struct rte_security_capability *sec_cap,
212 		struct rte_crypto_sym_xform *cipher)
213 {
214 	const struct rte_cryptodev_symmetric_capability *sym_cap;
215 	const struct rte_cryptodev_capabilities *cap;
216 	int j = 0;
217 
218 	while ((cap = &sec_cap->crypto_capabilities[j++])->op !=
219 			RTE_CRYPTO_OP_TYPE_UNDEFINED) {
220 		if (cap->op == RTE_CRYPTO_OP_TYPE_SYMMETRIC &&
221 				cap->sym.xform_type == cipher->type &&
222 				cap->sym.cipher.algo == cipher->cipher.algo) {
223 			sym_cap = &cap->sym;
224 			if (rte_cryptodev_sym_capability_check_cipher(sym_cap,
225 					cipher->cipher.key.length,
226 					cipher->cipher.iv.length) == 0)
227 				return 0;
228 		}
229 	}
230 
231 	return -ENOTSUP;
232 }
233 
234 int
235 test_ipsec_crypto_caps_auth_verify(
236 		const struct rte_security_capability *sec_cap,
237 		struct rte_crypto_sym_xform *auth)
238 {
239 	const struct rte_cryptodev_symmetric_capability *sym_cap;
240 	const struct rte_cryptodev_capabilities *cap;
241 	int j = 0;
242 
243 	while ((cap = &sec_cap->crypto_capabilities[j++])->op !=
244 			RTE_CRYPTO_OP_TYPE_UNDEFINED) {
245 		if (cap->op == RTE_CRYPTO_OP_TYPE_SYMMETRIC &&
246 				cap->sym.xform_type == auth->type &&
247 				cap->sym.auth.algo == auth->auth.algo) {
248 			sym_cap = &cap->sym;
249 			if (rte_cryptodev_sym_capability_check_auth(sym_cap,
250 					auth->auth.key.length,
251 					auth->auth.digest_length,
252 					auth->auth.iv.length) == 0)
253 				return 0;
254 		}
255 	}
256 
257 	return -ENOTSUP;
258 }
259 
260 void
261 test_ipsec_td_in_from_out(const struct ipsec_test_data *td_out,
262 			  struct ipsec_test_data *td_in)
263 {
264 	memcpy(td_in, td_out, sizeof(*td_in));
265 
266 	/* Populate output text of td_in with input text of td_out */
267 	memcpy(td_in->output_text.data, td_out->input_text.data,
268 	       td_out->input_text.len);
269 	td_in->output_text.len = td_out->input_text.len;
270 
271 	/* Populate input text of td_in with output text of td_out */
272 	memcpy(td_in->input_text.data, td_out->output_text.data,
273 	       td_out->output_text.len);
274 	td_in->input_text.len = td_out->output_text.len;
275 
276 	td_in->ipsec_xform.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
277 
278 	if (td_in->aead) {
279 		td_in->xform.aead.aead.op = RTE_CRYPTO_AEAD_OP_DECRYPT;
280 	} else {
281 		td_in->xform.chain.auth.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
282 		td_in->xform.chain.cipher.cipher.op =
283 				RTE_CRYPTO_CIPHER_OP_DECRYPT;
284 	}
285 }
286 
287 static bool
288 is_ipv4(void *ip)
289 {
290 	struct rte_ipv4_hdr *ipv4 = ip;
291 	uint8_t ip_ver;
292 
293 	ip_ver = (ipv4->version_ihl & 0xf0) >> RTE_IPV4_IHL_MULTIPLIER;
294 	if (ip_ver == IPVERSION)
295 		return true;
296 	else
297 		return false;
298 }
299 
300 static void
301 test_ipsec_csum_init(void *ip, bool l3, bool l4)
302 {
303 	struct rte_ipv4_hdr *ipv4;
304 	struct rte_tcp_hdr *tcp;
305 	struct rte_udp_hdr *udp;
306 	uint8_t next_proto;
307 	uint8_t size;
308 
309 	if (is_ipv4(ip)) {
310 		ipv4 = ip;
311 		size = sizeof(struct rte_ipv4_hdr);
312 		next_proto = ipv4->next_proto_id;
313 
314 		if (l3)
315 			ipv4->hdr_checksum = 0;
316 	} else {
317 		size = sizeof(struct rte_ipv6_hdr);
318 		next_proto = ((struct rte_ipv6_hdr *)ip)->proto;
319 	}
320 
321 	if (l4) {
322 		switch (next_proto) {
323 		case IPPROTO_TCP:
324 			tcp = (struct rte_tcp_hdr *)RTE_PTR_ADD(ip, size);
325 			tcp->cksum = 0;
326 			break;
327 		case IPPROTO_UDP:
328 			udp = (struct rte_udp_hdr *)RTE_PTR_ADD(ip, size);
329 			udp->dgram_cksum = 0;
330 			break;
331 		default:
332 			return;
333 		}
334 	}
335 }
336 
337 void
338 test_ipsec_td_prepare(const struct crypto_param *param1,
339 		      const struct crypto_param *param2,
340 		      const struct ipsec_test_flags *flags,
341 		      struct ipsec_test_data *td_array,
342 		      int nb_td)
343 
344 {
345 	struct ipsec_test_data *td;
346 	int i;
347 
348 	memset(td_array, 0, nb_td * sizeof(*td));
349 
350 	for (i = 0; i < nb_td; i++) {
351 		td = &td_array[i];
352 
353 		/* Prepare fields based on param */
354 
355 		if (param1->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
356 			/* Copy template for packet & key fields */
357 			if (flags->ipv6)
358 				memcpy(td, &pkt_aes_256_gcm_v6, sizeof(*td));
359 			else
360 				memcpy(td, &pkt_aes_256_gcm, sizeof(*td));
361 
362 			td->aead = true;
363 			td->xform.aead.aead.algo = param1->alg.aead;
364 			td->xform.aead.aead.key.length = param1->key_length;
365 		} else {
366 			/* Copy template for packet & key fields */
367 			if (flags->ipv6)
368 				memcpy(td, &pkt_aes_128_cbc_hmac_sha256_v6,
369 					sizeof(*td));
370 			else
371 				memcpy(td, &pkt_aes_128_cbc_hmac_sha256,
372 					sizeof(*td));
373 
374 			td->aead = false;
375 			td->xform.chain.cipher.cipher.algo = param1->alg.cipher;
376 			td->xform.chain.cipher.cipher.key.length =
377 					param1->key_length;
378 			td->xform.chain.auth.auth.algo = param2->alg.auth;
379 			td->xform.chain.auth.auth.key.length =
380 					param2->key_length;
381 			td->xform.chain.auth.auth.digest_length =
382 					param2->digest_length;
383 
384 		}
385 
386 		if (flags->iv_gen)
387 			td->ipsec_xform.options.iv_gen_disable = 0;
388 
389 		if (flags->sa_expiry_pkts_soft)
390 			td->ipsec_xform.life.packets_soft_limit =
391 					IPSEC_TEST_PACKETS_MAX - 1;
392 
393 		if (flags->ip_csum) {
394 			td->ipsec_xform.options.ip_csum_enable = 1;
395 			test_ipsec_csum_init(&td->input_text.data, true, false);
396 		}
397 
398 		if (flags->l4_csum) {
399 			td->ipsec_xform.options.l4_csum_enable = 1;
400 			test_ipsec_csum_init(&td->input_text.data, false, true);
401 		}
402 
403 		if (flags->tunnel_ipv6)
404 			td->ipsec_xform.tunnel.type =
405 					RTE_SECURITY_IPSEC_TUNNEL_IPV6;
406 		else
407 			td->ipsec_xform.tunnel.type =
408 					RTE_SECURITY_IPSEC_TUNNEL_IPV4;
409 
410 	}
411 }
412 
413 void
414 test_ipsec_td_update(struct ipsec_test_data td_inb[],
415 		     const struct ipsec_test_data td_outb[],
416 		     int nb_td,
417 		     const struct ipsec_test_flags *flags)
418 {
419 	int i;
420 
421 	for (i = 0; i < nb_td; i++) {
422 		memcpy(td_inb[i].output_text.data, td_outb[i].input_text.data,
423 		       td_outb[i].input_text.len);
424 		td_inb[i].output_text.len = td_outb->input_text.len;
425 
426 		if (flags->icv_corrupt) {
427 			int icv_pos = td_inb[i].input_text.len - 4;
428 			td_inb[i].input_text.data[icv_pos] += 1;
429 		}
430 
431 		if (flags->sa_expiry_pkts_hard)
432 			td_inb[i].ipsec_xform.life.packets_hard_limit =
433 					IPSEC_TEST_PACKETS_MAX - 1;
434 
435 		if (flags->udp_encap)
436 			td_inb[i].ipsec_xform.options.udp_encap = 1;
437 
438 		if (flags->udp_ports_verify)
439 			td_inb[i].ipsec_xform.options.udp_ports_verify = 1;
440 
441 		td_inb[i].ipsec_xform.options.tunnel_hdr_verify =
442 			flags->tunnel_hdr_verify;
443 
444 		if (flags->ip_csum)
445 			td_inb[i].ipsec_xform.options.ip_csum_enable = 1;
446 
447 		if (flags->l4_csum)
448 			td_inb[i].ipsec_xform.options.l4_csum_enable = 1;
449 
450 		/* Clear outbound specific flags */
451 		td_inb[i].ipsec_xform.options.iv_gen_disable = 0;
452 	}
453 }
454 
455 void
456 test_ipsec_display_alg(const struct crypto_param *param1,
457 		       const struct crypto_param *param2)
458 {
459 	if (param1->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
460 		printf("\t%s [%d]",
461 		       rte_crypto_aead_algorithm_strings[param1->alg.aead],
462 		       param1->key_length * 8);
463 	} else {
464 		printf("\t%s",
465 		       rte_crypto_cipher_algorithm_strings[param1->alg.cipher]);
466 		if (param1->alg.cipher != RTE_CRYPTO_CIPHER_NULL)
467 			printf(" [%d]", param1->key_length * 8);
468 		printf(" %s",
469 		       rte_crypto_auth_algorithm_strings[param2->alg.auth]);
470 		if (param2->alg.auth != RTE_CRYPTO_AUTH_NULL)
471 			printf(" [%dB ICV]", param2->digest_length);
472 	}
473 	printf("\n");
474 }
475 
476 static int
477 test_ipsec_tunnel_hdr_len_get(const struct ipsec_test_data *td)
478 {
479 	int len = 0;
480 
481 	if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
482 		if (td->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
483 			if (td->ipsec_xform.tunnel.type ==
484 					RTE_SECURITY_IPSEC_TUNNEL_IPV4)
485 				len += sizeof(struct rte_ipv4_hdr);
486 			else
487 				len += sizeof(struct rte_ipv6_hdr);
488 		}
489 	}
490 
491 	return len;
492 }
493 
494 static int
495 test_ipsec_iv_verify_push(struct rte_mbuf *m, const struct ipsec_test_data *td)
496 {
497 	static uint8_t iv_queue[IV_LEN_MAX * IPSEC_TEST_PACKETS_MAX];
498 	uint8_t *iv_tmp, *output_text = rte_pktmbuf_mtod(m, uint8_t *);
499 	int i, iv_pos, iv_len;
500 	static int index;
501 
502 	if (td->aead)
503 		iv_len = td->xform.aead.aead.iv.length - td->salt.len;
504 	else
505 		iv_len = td->xform.chain.cipher.cipher.iv.length;
506 
507 	iv_pos = test_ipsec_tunnel_hdr_len_get(td) + sizeof(struct rte_esp_hdr);
508 	output_text += iv_pos;
509 
510 	TEST_ASSERT(iv_len <= IV_LEN_MAX, "IV length greater than supported");
511 
512 	/* Compare against previous values */
513 	for (i = 0; i < index; i++) {
514 		iv_tmp = &iv_queue[i * IV_LEN_MAX];
515 
516 		if (memcmp(output_text, iv_tmp, iv_len) == 0) {
517 			printf("IV repeated");
518 			return TEST_FAILED;
519 		}
520 	}
521 
522 	/* Save IV for future comparisons */
523 
524 	iv_tmp = &iv_queue[index * IV_LEN_MAX];
525 	memcpy(iv_tmp, output_text, iv_len);
526 	index++;
527 
528 	if (index == IPSEC_TEST_PACKETS_MAX)
529 		index = 0;
530 
531 	return TEST_SUCCESS;
532 }
533 
534 static int
535 test_ipsec_l3_csum_verify(struct rte_mbuf *m)
536 {
537 	uint16_t actual_cksum, expected_cksum;
538 	struct rte_ipv4_hdr *ip;
539 
540 	ip = rte_pktmbuf_mtod(m, struct rte_ipv4_hdr *);
541 
542 	if (!is_ipv4((void *)ip))
543 		return TEST_SKIPPED;
544 
545 	actual_cksum = ip->hdr_checksum;
546 
547 	ip->hdr_checksum = 0;
548 
549 	expected_cksum = rte_ipv4_cksum(ip);
550 
551 	if (actual_cksum != expected_cksum)
552 		return TEST_FAILED;
553 
554 	return TEST_SUCCESS;
555 }
556 
557 static int
558 test_ipsec_l4_csum_verify(struct rte_mbuf *m)
559 {
560 	uint16_t actual_cksum = 0, expected_cksum = 0;
561 	struct rte_ipv4_hdr *ipv4;
562 	struct rte_ipv6_hdr *ipv6;
563 	struct rte_tcp_hdr *tcp;
564 	struct rte_udp_hdr *udp;
565 	void *ip, *l4;
566 
567 	ip = rte_pktmbuf_mtod(m, void *);
568 
569 	if (is_ipv4(ip)) {
570 		ipv4 = ip;
571 		l4 = RTE_PTR_ADD(ipv4, sizeof(struct rte_ipv4_hdr));
572 
573 		switch (ipv4->next_proto_id) {
574 		case IPPROTO_TCP:
575 			tcp = (struct rte_tcp_hdr *)l4;
576 			actual_cksum = tcp->cksum;
577 			tcp->cksum = 0;
578 			expected_cksum = rte_ipv4_udptcp_cksum(ipv4, l4);
579 			break;
580 		case IPPROTO_UDP:
581 			udp = (struct rte_udp_hdr *)l4;
582 			actual_cksum = udp->dgram_cksum;
583 			udp->dgram_cksum = 0;
584 			expected_cksum = rte_ipv4_udptcp_cksum(ipv4, l4);
585 			break;
586 		default:
587 			break;
588 		}
589 	} else {
590 		ipv6 = ip;
591 		l4 = RTE_PTR_ADD(ipv6, sizeof(struct rte_ipv6_hdr));
592 
593 		switch (ipv6->proto) {
594 		case IPPROTO_TCP:
595 			tcp = (struct rte_tcp_hdr *)l4;
596 			actual_cksum = tcp->cksum;
597 			tcp->cksum = 0;
598 			expected_cksum = rte_ipv6_udptcp_cksum(ipv6, l4);
599 			break;
600 		case IPPROTO_UDP:
601 			udp = (struct rte_udp_hdr *)l4;
602 			actual_cksum = udp->dgram_cksum;
603 			udp->dgram_cksum = 0;
604 			expected_cksum = rte_ipv6_udptcp_cksum(ipv6, l4);
605 			break;
606 		default:
607 			break;
608 		}
609 	}
610 
611 	if (actual_cksum != expected_cksum)
612 		return TEST_FAILED;
613 
614 	return TEST_SUCCESS;
615 }
616 
617 static int
618 test_ipsec_td_verify(struct rte_mbuf *m, const struct ipsec_test_data *td,
619 		     bool silent, const struct ipsec_test_flags *flags)
620 {
621 	uint8_t *output_text = rte_pktmbuf_mtod(m, uint8_t *);
622 	uint32_t skip, len = rte_pktmbuf_pkt_len(m);
623 	int ret;
624 
625 	/* For tests with status as error for test success, skip verification */
626 	if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS &&
627 	    (flags->icv_corrupt ||
628 	     flags->sa_expiry_pkts_hard ||
629 	     flags->tunnel_hdr_verify))
630 		return TEST_SUCCESS;
631 
632 	if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS &&
633 	   flags->udp_encap) {
634 		const struct rte_ipv4_hdr *iph4;
635 		const struct rte_ipv6_hdr *iph6;
636 
637 		if (td->ipsec_xform.tunnel.type ==
638 				RTE_SECURITY_IPSEC_TUNNEL_IPV4) {
639 			iph4 = (const struct rte_ipv4_hdr *)output_text;
640 			if (iph4->next_proto_id != IPPROTO_UDP) {
641 				printf("UDP header is not found\n");
642 				return TEST_FAILED;
643 			}
644 		} else {
645 			iph6 = (const struct rte_ipv6_hdr *)output_text;
646 			if (iph6->proto != IPPROTO_UDP) {
647 				printf("UDP header is not found\n");
648 				return TEST_FAILED;
649 			}
650 		}
651 
652 		len -= sizeof(struct rte_udp_hdr);
653 		output_text += sizeof(struct rte_udp_hdr);
654 	}
655 
656 	if (len != td->output_text.len) {
657 		printf("Output length (%d) not matching with expected (%d)\n",
658 			len, td->output_text.len);
659 		return TEST_FAILED;
660 	}
661 
662 	skip = test_ipsec_tunnel_hdr_len_get(td);
663 
664 	len -= skip;
665 	output_text += skip;
666 
667 	if ((td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
668 				flags->ip_csum) {
669 		if (m->ol_flags & RTE_MBUF_F_RX_IP_CKSUM_GOOD)
670 			ret = test_ipsec_l3_csum_verify(m);
671 		else
672 			ret = TEST_FAILED;
673 
674 		if (ret == TEST_FAILED)
675 			printf("Inner IP checksum test failed\n");
676 
677 		return ret;
678 	}
679 
680 	if ((td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
681 				flags->l4_csum) {
682 		if (m->ol_flags & RTE_MBUF_F_RX_L4_CKSUM_GOOD)
683 			ret = test_ipsec_l4_csum_verify(m);
684 		else
685 			ret = TEST_FAILED;
686 
687 		if (ret == TEST_FAILED)
688 			printf("Inner L4 checksum test failed\n");
689 
690 		return ret;
691 	}
692 
693 
694 	if (memcmp(output_text, td->output_text.data + skip, len)) {
695 		if (silent)
696 			return TEST_FAILED;
697 
698 		printf("TestCase %s line %d: %s\n", __func__, __LINE__,
699 			"output text not as expected\n");
700 
701 		rte_hexdump(stdout, "expected", td->output_text.data + skip,
702 			    len);
703 		rte_hexdump(stdout, "actual", output_text, len);
704 		return TEST_FAILED;
705 	}
706 
707 	return TEST_SUCCESS;
708 }
709 
710 static int
711 test_ipsec_res_d_prepare(struct rte_mbuf *m, const struct ipsec_test_data *td,
712 		   struct ipsec_test_data *res_d)
713 {
714 	uint8_t *output_text = rte_pktmbuf_mtod(m, uint8_t *);
715 	uint32_t len = rte_pktmbuf_pkt_len(m);
716 
717 	memcpy(res_d, td, sizeof(*res_d));
718 	memcpy(res_d->input_text.data, output_text, len);
719 	res_d->input_text.len = len;
720 
721 	res_d->ipsec_xform.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
722 	if (res_d->aead) {
723 		res_d->xform.aead.aead.op = RTE_CRYPTO_AEAD_OP_DECRYPT;
724 	} else {
725 		res_d->xform.chain.cipher.cipher.op =
726 				RTE_CRYPTO_CIPHER_OP_DECRYPT;
727 		res_d->xform.chain.auth.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
728 	}
729 
730 	return TEST_SUCCESS;
731 }
732 
733 int
734 test_ipsec_post_process(struct rte_mbuf *m, const struct ipsec_test_data *td,
735 			struct ipsec_test_data *res_d, bool silent,
736 			const struct ipsec_test_flags *flags)
737 {
738 	uint8_t *output_text = rte_pktmbuf_mtod(m, uint8_t *);
739 	int ret;
740 
741 	if (flags->iv_gen &&
742 	    td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
743 		ret = test_ipsec_iv_verify_push(m, td);
744 		if (ret != TEST_SUCCESS)
745 			return ret;
746 	}
747 
748 	if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
749 		const struct rte_ipv4_hdr *iph4;
750 		const struct rte_ipv6_hdr *iph6;
751 
752 		if (td->ipsec_xform.tunnel.type ==
753 				RTE_SECURITY_IPSEC_TUNNEL_IPV4) {
754 			iph4 = (const struct rte_ipv4_hdr *)output_text;
755 			if (is_valid_ipv4_pkt(iph4) == false) {
756 				printf("Outer header is not IPv4\n");
757 				return TEST_FAILED;
758 			}
759 		} else {
760 			iph6 = (const struct rte_ipv6_hdr *)output_text;
761 			if (is_valid_ipv6_pkt(iph6) == false) {
762 				printf("Outer header is not IPv6\n");
763 				return TEST_FAILED;
764 			}
765 		}
766 	}
767 
768 	/*
769 	 * In case of known vector tests & all inbound tests, res_d provided
770 	 * would be NULL and output data need to be validated against expected.
771 	 * For inbound, output_text would be plain packet and for outbound
772 	 * output_text would IPsec packet. Validate by comparing against
773 	 * known vectors.
774 	 *
775 	 * In case of combined mode tests, the output_text from outbound
776 	 * operation (ie, IPsec packet) would need to be inbound processed to
777 	 * obtain the plain text. Copy output_text to result data, 'res_d', so
778 	 * that inbound processing can be done.
779 	 */
780 
781 	if (res_d == NULL)
782 		return test_ipsec_td_verify(m, td, silent, flags);
783 	else
784 		return test_ipsec_res_d_prepare(m, td, res_d);
785 }
786 
787 int
788 test_ipsec_status_check(struct rte_crypto_op *op,
789 			const struct ipsec_test_flags *flags,
790 			enum rte_security_ipsec_sa_direction dir,
791 			int pkt_num)
792 {
793 	int ret = TEST_SUCCESS;
794 
795 	if (dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS &&
796 	    flags->sa_expiry_pkts_hard &&
797 	    pkt_num == IPSEC_TEST_PACKETS_MAX) {
798 		if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) {
799 			printf("SA hard expiry (pkts) test failed\n");
800 			return TEST_FAILED;
801 		} else {
802 			return TEST_SUCCESS;
803 		}
804 	}
805 
806 	if ((dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
807 	    flags->tunnel_hdr_verify) {
808 		if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) {
809 			printf("Tunnel header verify test case failed\n");
810 			return TEST_FAILED;
811 		} else {
812 			return TEST_SUCCESS;
813 		}
814 	}
815 
816 	if (dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS && flags->icv_corrupt) {
817 		if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) {
818 			printf("ICV corruption test case failed\n");
819 			ret = TEST_FAILED;
820 		}
821 	} else {
822 		if (op->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
823 			printf("Security op processing failed [pkt_num: %d]\n",
824 			       pkt_num);
825 			ret = TEST_FAILED;
826 		}
827 	}
828 
829 	if (flags->sa_expiry_pkts_soft && pkt_num == IPSEC_TEST_PACKETS_MAX) {
830 		if (!(op->aux_flags &
831 		      RTE_CRYPTO_OP_AUX_FLAGS_IPSEC_SOFT_EXPIRY)) {
832 			printf("SA soft expiry (pkts) test failed\n");
833 			ret = TEST_FAILED;
834 		}
835 	}
836 
837 	return ret;
838 }
839