xref: /dpdk/app/test/test_cryptodev_security_ipsec.c (revision e2cbb384505596fa833909c60c31f669ad413ba0)
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.cipher.cipher.iv.length =
379 					param1->iv_length;
380 			td->xform.chain.auth.auth.algo = param2->alg.auth;
381 			td->xform.chain.auth.auth.key.length =
382 					param2->key_length;
383 			td->xform.chain.auth.auth.digest_length =
384 					param2->digest_length;
385 
386 		}
387 
388 		if (flags->iv_gen)
389 			td->ipsec_xform.options.iv_gen_disable = 0;
390 
391 		if (flags->sa_expiry_pkts_soft)
392 			td->ipsec_xform.life.packets_soft_limit =
393 					IPSEC_TEST_PACKETS_MAX - 1;
394 
395 		if (flags->ip_csum) {
396 			td->ipsec_xform.options.ip_csum_enable = 1;
397 			test_ipsec_csum_init(&td->input_text.data, true, false);
398 		}
399 
400 		if (flags->l4_csum) {
401 			td->ipsec_xform.options.l4_csum_enable = 1;
402 			test_ipsec_csum_init(&td->input_text.data, false, true);
403 		}
404 
405 		if (flags->transport) {
406 			td->ipsec_xform.mode =
407 					RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT;
408 		} else {
409 			td->ipsec_xform.mode =
410 					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL;
411 
412 			if (flags->tunnel_ipv6)
413 				td->ipsec_xform.tunnel.type =
414 						RTE_SECURITY_IPSEC_TUNNEL_IPV6;
415 			else
416 				td->ipsec_xform.tunnel.type =
417 						RTE_SECURITY_IPSEC_TUNNEL_IPV4;
418 		}
419 
420 		if (flags->stats_success)
421 			td->ipsec_xform.options.stats = 1;
422 
423 		if (flags->fragment) {
424 			struct rte_ipv4_hdr *ip;
425 			ip = (struct rte_ipv4_hdr *)&td->input_text.data;
426 			ip->fragment_offset = 4;
427 			ip->hdr_checksum = rte_ipv4_cksum(ip);
428 		}
429 
430 		if (flags->df == TEST_IPSEC_COPY_DF_INNER_0 ||
431 		    flags->df == TEST_IPSEC_COPY_DF_INNER_1)
432 			td->ipsec_xform.options.copy_df = 1;
433 	}
434 }
435 
436 void
437 test_ipsec_td_update(struct ipsec_test_data td_inb[],
438 		     const struct ipsec_test_data td_outb[],
439 		     int nb_td,
440 		     const struct ipsec_test_flags *flags)
441 {
442 	int i;
443 
444 	for (i = 0; i < nb_td; i++) {
445 		memcpy(td_inb[i].output_text.data, td_outb[i].input_text.data,
446 		       td_outb[i].input_text.len);
447 		td_inb[i].output_text.len = td_outb->input_text.len;
448 
449 		if (flags->icv_corrupt) {
450 			int icv_pos = td_inb[i].input_text.len - 4;
451 			td_inb[i].input_text.data[icv_pos] += 1;
452 		}
453 
454 		if (flags->sa_expiry_pkts_hard)
455 			td_inb[i].ipsec_xform.life.packets_hard_limit =
456 					IPSEC_TEST_PACKETS_MAX - 1;
457 
458 		if (flags->udp_encap)
459 			td_inb[i].ipsec_xform.options.udp_encap = 1;
460 
461 		if (flags->udp_ports_verify)
462 			td_inb[i].ipsec_xform.options.udp_ports_verify = 1;
463 
464 		td_inb[i].ipsec_xform.options.tunnel_hdr_verify =
465 			flags->tunnel_hdr_verify;
466 
467 		if (flags->ip_csum)
468 			td_inb[i].ipsec_xform.options.ip_csum_enable = 1;
469 
470 		if (flags->l4_csum)
471 			td_inb[i].ipsec_xform.options.l4_csum_enable = 1;
472 
473 		/* Clear outbound specific flags */
474 		td_inb[i].ipsec_xform.options.iv_gen_disable = 0;
475 	}
476 }
477 
478 void
479 test_ipsec_display_alg(const struct crypto_param *param1,
480 		       const struct crypto_param *param2)
481 {
482 	if (param1->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
483 		printf("\t%s [%d]",
484 		       rte_crypto_aead_algorithm_strings[param1->alg.aead],
485 		       param1->key_length * 8);
486 	} else {
487 		printf("\t%s",
488 		       rte_crypto_cipher_algorithm_strings[param1->alg.cipher]);
489 		if (param1->alg.cipher != RTE_CRYPTO_CIPHER_NULL)
490 			printf(" [%d]", param1->key_length * 8);
491 		printf(" %s",
492 		       rte_crypto_auth_algorithm_strings[param2->alg.auth]);
493 		if (param2->alg.auth != RTE_CRYPTO_AUTH_NULL)
494 			printf(" [%dB ICV]", param2->digest_length);
495 	}
496 	printf("\n");
497 }
498 
499 static int
500 test_ipsec_tunnel_hdr_len_get(const struct ipsec_test_data *td)
501 {
502 	int len = 0;
503 
504 	if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
505 		if (td->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
506 			if (td->ipsec_xform.tunnel.type ==
507 					RTE_SECURITY_IPSEC_TUNNEL_IPV4)
508 				len += sizeof(struct rte_ipv4_hdr);
509 			else
510 				len += sizeof(struct rte_ipv6_hdr);
511 		}
512 	}
513 
514 	return len;
515 }
516 
517 static int
518 test_ipsec_iv_verify_push(struct rte_mbuf *m, const struct ipsec_test_data *td)
519 {
520 	static uint8_t iv_queue[IV_LEN_MAX * IPSEC_TEST_PACKETS_MAX];
521 	uint8_t *iv_tmp, *output_text = rte_pktmbuf_mtod(m, uint8_t *);
522 	int i, iv_pos, iv_len;
523 	static int index;
524 
525 	if (td->aead)
526 		iv_len = td->xform.aead.aead.iv.length - td->salt.len;
527 	else
528 		iv_len = td->xform.chain.cipher.cipher.iv.length;
529 
530 	iv_pos = test_ipsec_tunnel_hdr_len_get(td) + sizeof(struct rte_esp_hdr);
531 	output_text += iv_pos;
532 
533 	TEST_ASSERT(iv_len <= IV_LEN_MAX, "IV length greater than supported");
534 
535 	/* Compare against previous values */
536 	for (i = 0; i < index; i++) {
537 		iv_tmp = &iv_queue[i * IV_LEN_MAX];
538 
539 		if (memcmp(output_text, iv_tmp, iv_len) == 0) {
540 			printf("IV repeated");
541 			return TEST_FAILED;
542 		}
543 	}
544 
545 	/* Save IV for future comparisons */
546 
547 	iv_tmp = &iv_queue[index * IV_LEN_MAX];
548 	memcpy(iv_tmp, output_text, iv_len);
549 	index++;
550 
551 	if (index == IPSEC_TEST_PACKETS_MAX)
552 		index = 0;
553 
554 	return TEST_SUCCESS;
555 }
556 
557 static int
558 test_ipsec_l3_csum_verify(struct rte_mbuf *m)
559 {
560 	uint16_t actual_cksum, expected_cksum;
561 	struct rte_ipv4_hdr *ip;
562 
563 	ip = rte_pktmbuf_mtod(m, struct rte_ipv4_hdr *);
564 
565 	if (!is_ipv4((void *)ip))
566 		return TEST_SKIPPED;
567 
568 	actual_cksum = ip->hdr_checksum;
569 
570 	ip->hdr_checksum = 0;
571 
572 	expected_cksum = rte_ipv4_cksum(ip);
573 
574 	if (actual_cksum != expected_cksum)
575 		return TEST_FAILED;
576 
577 	return TEST_SUCCESS;
578 }
579 
580 static int
581 test_ipsec_l4_csum_verify(struct rte_mbuf *m)
582 {
583 	uint16_t actual_cksum = 0, expected_cksum = 0;
584 	struct rte_ipv4_hdr *ipv4;
585 	struct rte_ipv6_hdr *ipv6;
586 	struct rte_tcp_hdr *tcp;
587 	struct rte_udp_hdr *udp;
588 	void *ip, *l4;
589 
590 	ip = rte_pktmbuf_mtod(m, void *);
591 
592 	if (is_ipv4(ip)) {
593 		ipv4 = ip;
594 		l4 = RTE_PTR_ADD(ipv4, sizeof(struct rte_ipv4_hdr));
595 
596 		switch (ipv4->next_proto_id) {
597 		case IPPROTO_TCP:
598 			tcp = (struct rte_tcp_hdr *)l4;
599 			actual_cksum = tcp->cksum;
600 			tcp->cksum = 0;
601 			expected_cksum = rte_ipv4_udptcp_cksum(ipv4, l4);
602 			break;
603 		case IPPROTO_UDP:
604 			udp = (struct rte_udp_hdr *)l4;
605 			actual_cksum = udp->dgram_cksum;
606 			udp->dgram_cksum = 0;
607 			expected_cksum = rte_ipv4_udptcp_cksum(ipv4, l4);
608 			break;
609 		default:
610 			break;
611 		}
612 	} else {
613 		ipv6 = ip;
614 		l4 = RTE_PTR_ADD(ipv6, sizeof(struct rte_ipv6_hdr));
615 
616 		switch (ipv6->proto) {
617 		case IPPROTO_TCP:
618 			tcp = (struct rte_tcp_hdr *)l4;
619 			actual_cksum = tcp->cksum;
620 			tcp->cksum = 0;
621 			expected_cksum = rte_ipv6_udptcp_cksum(ipv6, l4);
622 			break;
623 		case IPPROTO_UDP:
624 			udp = (struct rte_udp_hdr *)l4;
625 			actual_cksum = udp->dgram_cksum;
626 			udp->dgram_cksum = 0;
627 			expected_cksum = rte_ipv6_udptcp_cksum(ipv6, l4);
628 			break;
629 		default:
630 			break;
631 		}
632 	}
633 
634 	if (actual_cksum != expected_cksum)
635 		return TEST_FAILED;
636 
637 	return TEST_SUCCESS;
638 }
639 
640 static int
641 test_ipsec_td_verify(struct rte_mbuf *m, const struct ipsec_test_data *td,
642 		     bool silent, const struct ipsec_test_flags *flags)
643 {
644 	uint8_t *output_text = rte_pktmbuf_mtod(m, uint8_t *);
645 	uint32_t skip, len = rte_pktmbuf_pkt_len(m);
646 	uint8_t td_output_text[4096];
647 	int ret;
648 
649 	/* For tests with status as error for test success, skip verification */
650 	if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS &&
651 	    (flags->icv_corrupt ||
652 	     flags->sa_expiry_pkts_hard ||
653 	     flags->tunnel_hdr_verify))
654 		return TEST_SUCCESS;
655 
656 	if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS &&
657 	   flags->udp_encap) {
658 		const struct rte_ipv4_hdr *iph4;
659 		const struct rte_ipv6_hdr *iph6;
660 
661 		if (td->ipsec_xform.tunnel.type ==
662 				RTE_SECURITY_IPSEC_TUNNEL_IPV4) {
663 			iph4 = (const struct rte_ipv4_hdr *)output_text;
664 			if (iph4->next_proto_id != IPPROTO_UDP) {
665 				printf("UDP header is not found\n");
666 				return TEST_FAILED;
667 			}
668 		} else {
669 			iph6 = (const struct rte_ipv6_hdr *)output_text;
670 			if (iph6->proto != IPPROTO_UDP) {
671 				printf("UDP header is not found\n");
672 				return TEST_FAILED;
673 			}
674 		}
675 
676 		len -= sizeof(struct rte_udp_hdr);
677 		output_text += sizeof(struct rte_udp_hdr);
678 	}
679 
680 	if (len != td->output_text.len) {
681 		printf("Output length (%d) not matching with expected (%d)\n",
682 			len, td->output_text.len);
683 		return TEST_FAILED;
684 	}
685 
686 	if ((td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) &&
687 				flags->fragment) {
688 		const struct rte_ipv4_hdr *iph4;
689 		iph4 = (const struct rte_ipv4_hdr *)output_text;
690 		if (iph4->fragment_offset) {
691 			printf("Output packet is fragmented");
692 			return TEST_FAILED;
693 		}
694 	}
695 
696 	skip = test_ipsec_tunnel_hdr_len_get(td);
697 
698 	len -= skip;
699 	output_text += skip;
700 
701 	if ((td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
702 				flags->ip_csum) {
703 		if (m->ol_flags & RTE_MBUF_F_RX_IP_CKSUM_GOOD)
704 			ret = test_ipsec_l3_csum_verify(m);
705 		else
706 			ret = TEST_FAILED;
707 
708 		if (ret == TEST_FAILED)
709 			printf("Inner IP checksum test failed\n");
710 
711 		return ret;
712 	}
713 
714 	if ((td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
715 				flags->l4_csum) {
716 		if (m->ol_flags & RTE_MBUF_F_RX_L4_CKSUM_GOOD)
717 			ret = test_ipsec_l4_csum_verify(m);
718 		else
719 			ret = TEST_FAILED;
720 
721 		if (ret == TEST_FAILED)
722 			printf("Inner L4 checksum test failed\n");
723 
724 		return ret;
725 	}
726 
727 	memcpy(td_output_text, td->output_text.data + skip, len);
728 
729 	if (test_ipsec_pkt_update(td_output_text, flags)) {
730 		printf("Could not update expected vector");
731 		return TEST_FAILED;
732 	}
733 
734 	if (memcmp(output_text, td_output_text, len)) {
735 		if (silent)
736 			return TEST_FAILED;
737 
738 		printf("TestCase %s line %d: %s\n", __func__, __LINE__,
739 			"output text not as expected\n");
740 
741 		rte_hexdump(stdout, "expected", td_output_text, len);
742 		rte_hexdump(stdout, "actual", output_text, len);
743 		return TEST_FAILED;
744 	}
745 
746 	return TEST_SUCCESS;
747 }
748 
749 static int
750 test_ipsec_res_d_prepare(struct rte_mbuf *m, const struct ipsec_test_data *td,
751 		   struct ipsec_test_data *res_d)
752 {
753 	uint8_t *output_text = rte_pktmbuf_mtod(m, uint8_t *);
754 	uint32_t len = rte_pktmbuf_pkt_len(m);
755 
756 	memcpy(res_d, td, sizeof(*res_d));
757 	memcpy(res_d->input_text.data, output_text, len);
758 	res_d->input_text.len = len;
759 
760 	res_d->ipsec_xform.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
761 	if (res_d->aead) {
762 		res_d->xform.aead.aead.op = RTE_CRYPTO_AEAD_OP_DECRYPT;
763 	} else {
764 		res_d->xform.chain.cipher.cipher.op =
765 				RTE_CRYPTO_CIPHER_OP_DECRYPT;
766 		res_d->xform.chain.auth.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
767 	}
768 
769 	return TEST_SUCCESS;
770 }
771 
772 int
773 test_ipsec_post_process(struct rte_mbuf *m, const struct ipsec_test_data *td,
774 			struct ipsec_test_data *res_d, bool silent,
775 			const struct ipsec_test_flags *flags)
776 {
777 	uint8_t *output_text = rte_pktmbuf_mtod(m, uint8_t *);
778 	int ret;
779 
780 	if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
781 		const struct rte_ipv4_hdr *iph4;
782 		const struct rte_ipv6_hdr *iph6;
783 
784 		if (flags->iv_gen) {
785 			ret = test_ipsec_iv_verify_push(m, td);
786 			if (ret != TEST_SUCCESS)
787 				return ret;
788 		}
789 
790 		iph4 = (const struct rte_ipv4_hdr *)output_text;
791 
792 		if (td->ipsec_xform.mode ==
793 				RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT) {
794 			if (flags->ipv6) {
795 				iph6 = (const struct rte_ipv6_hdr *)output_text;
796 				if (is_valid_ipv6_pkt(iph6) == false) {
797 					printf("Transport packet is not IPv6\n");
798 					return TEST_FAILED;
799 				}
800 			} else {
801 				if (is_valid_ipv4_pkt(iph4) == false) {
802 					printf("Transport packet is not IPv4\n");
803 					return TEST_FAILED;
804 				}
805 			}
806 		} else {
807 			if (td->ipsec_xform.tunnel.type ==
808 					RTE_SECURITY_IPSEC_TUNNEL_IPV4) {
809 				uint16_t f_off;
810 
811 				if (is_valid_ipv4_pkt(iph4) == false) {
812 					printf("Tunnel outer header is not IPv4\n");
813 					return TEST_FAILED;
814 				}
815 
816 				f_off = rte_be_to_cpu_16(iph4->fragment_offset);
817 
818 				if (flags->df == TEST_IPSEC_COPY_DF_INNER_1 ||
819 				    flags->df == TEST_IPSEC_SET_DF_1_INNER_0) {
820 					if (!(f_off & RTE_IPV4_HDR_DF_FLAG)) {
821 						printf("DF bit is not set\n");
822 						return TEST_FAILED;
823 					}
824 				} else {
825 					if ((f_off & RTE_IPV4_HDR_DF_FLAG)) {
826 						printf("DF bit is set\n");
827 						return TEST_FAILED;
828 					}
829 				}
830 			} else {
831 				iph6 = (const struct rte_ipv6_hdr *)output_text;
832 				if (is_valid_ipv6_pkt(iph6) == false) {
833 					printf("Tunnel outer header is not IPv6\n");
834 					return TEST_FAILED;
835 				}
836 			}
837 		}
838 	}
839 
840 	/*
841 	 * In case of known vector tests & all inbound tests, res_d provided
842 	 * would be NULL and output data need to be validated against expected.
843 	 * For inbound, output_text would be plain packet and for outbound
844 	 * output_text would IPsec packet. Validate by comparing against
845 	 * known vectors.
846 	 *
847 	 * In case of combined mode tests, the output_text from outbound
848 	 * operation (ie, IPsec packet) would need to be inbound processed to
849 	 * obtain the plain text. Copy output_text to result data, 'res_d', so
850 	 * that inbound processing can be done.
851 	 */
852 
853 	if (res_d == NULL)
854 		return test_ipsec_td_verify(m, td, silent, flags);
855 	else
856 		return test_ipsec_res_d_prepare(m, td, res_d);
857 }
858 
859 int
860 test_ipsec_status_check(struct rte_crypto_op *op,
861 			const struct ipsec_test_flags *flags,
862 			enum rte_security_ipsec_sa_direction dir,
863 			int pkt_num)
864 {
865 	int ret = TEST_SUCCESS;
866 
867 	if (dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS &&
868 	    flags->sa_expiry_pkts_hard &&
869 	    pkt_num == IPSEC_TEST_PACKETS_MAX) {
870 		if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) {
871 			printf("SA hard expiry (pkts) test failed\n");
872 			return TEST_FAILED;
873 		} else {
874 			return TEST_SUCCESS;
875 		}
876 	}
877 
878 	if ((dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
879 	    flags->tunnel_hdr_verify) {
880 		if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) {
881 			printf("Tunnel header verify test case failed\n");
882 			return TEST_FAILED;
883 		} else {
884 			return TEST_SUCCESS;
885 		}
886 	}
887 
888 	if (dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS && flags->icv_corrupt) {
889 		if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) {
890 			printf("ICV corruption test case failed\n");
891 			ret = TEST_FAILED;
892 		}
893 	} else {
894 		if (op->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
895 			printf("Security op processing failed [pkt_num: %d]\n",
896 			       pkt_num);
897 			ret = TEST_FAILED;
898 		}
899 	}
900 
901 	if (flags->sa_expiry_pkts_soft && pkt_num == IPSEC_TEST_PACKETS_MAX) {
902 		if (!(op->aux_flags &
903 		      RTE_CRYPTO_OP_AUX_FLAGS_IPSEC_SOFT_EXPIRY)) {
904 			printf("SA soft expiry (pkts) test failed\n");
905 			ret = TEST_FAILED;
906 		}
907 	}
908 
909 	return ret;
910 }
911 
912 int
913 test_ipsec_stats_verify(struct rte_security_ctx *ctx,
914 			struct rte_security_session *sess,
915 			const struct ipsec_test_flags *flags,
916 			enum rte_security_ipsec_sa_direction dir)
917 {
918 	struct rte_security_stats stats = {0};
919 	int ret = TEST_SUCCESS;
920 
921 	if (flags->stats_success) {
922 		if (rte_security_session_stats_get(ctx, sess, &stats) < 0)
923 			return TEST_FAILED;
924 
925 		if (dir == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
926 			if (stats.ipsec.opackets != 1 ||
927 			    stats.ipsec.oerrors != 0)
928 				ret = TEST_FAILED;
929 		} else {
930 			if (stats.ipsec.ipackets != 1 ||
931 			    stats.ipsec.ierrors != 0)
932 				ret = TEST_FAILED;
933 		}
934 	}
935 
936 	return ret;
937 }
938 
939 int
940 test_ipsec_pkt_update(uint8_t *pkt, const struct ipsec_test_flags *flags)
941 {
942 	struct rte_ipv4_hdr *iph4;
943 	bool cksum_dirty = false;
944 	uint16_t frag_off;
945 
946 	iph4 = (struct rte_ipv4_hdr *)pkt;
947 
948 	if (flags->df == TEST_IPSEC_COPY_DF_INNER_1 ||
949 	    flags->df == TEST_IPSEC_SET_DF_0_INNER_1 ||
950 	    flags->df == TEST_IPSEC_COPY_DF_INNER_0 ||
951 	    flags->df == TEST_IPSEC_SET_DF_1_INNER_0) {
952 
953 		if (!is_ipv4(iph4)) {
954 			printf("Invalid packet type");
955 			return -1;
956 		}
957 
958 		frag_off = rte_be_to_cpu_16(iph4->fragment_offset);
959 
960 		if (flags->df == TEST_IPSEC_COPY_DF_INNER_1 ||
961 		    flags->df == TEST_IPSEC_SET_DF_0_INNER_1)
962 			frag_off |= RTE_IPV4_HDR_DF_FLAG;
963 		else
964 			frag_off &= ~RTE_IPV4_HDR_DF_FLAG;
965 
966 		iph4->fragment_offset = rte_cpu_to_be_16(frag_off);
967 		cksum_dirty = true;
968 	}
969 
970 	if (cksum_dirty && is_ipv4(iph4)) {
971 		iph4->hdr_checksum = 0;
972 		iph4->hdr_checksum = rte_ipv4_cksum(iph4);
973 	}
974 
975 	return 0;
976 }
977