xref: /dpdk/app/test/test_cryptodev_security_ipsec.c (revision 663d78bec190460a9dd5f3069a76ec76665c6b46)
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 			} else {
416 				td->xform.chain.cipher.cipher.algo =
417 						param1->alg.cipher;
418 				td->xform.chain.cipher.cipher.key.length =
419 						param1->key_length;
420 				td->xform.chain.cipher.cipher.iv.length =
421 						param1->iv_length;
422 				td->xform.chain.auth.auth.algo =
423 						param2->alg.auth;
424 				td->xform.chain.auth.auth.key.length =
425 						param2->key_length;
426 				td->xform.chain.auth.auth.digest_length =
427 						param2->digest_length;
428 			}
429 		}
430 
431 		if (flags->ah) {
432 			td->ipsec_xform.proto =
433 					RTE_SECURITY_IPSEC_SA_PROTO_AH;
434 		}
435 
436 		if (flags->iv_gen)
437 			td->ipsec_xform.options.iv_gen_disable = 0;
438 
439 		if (flags->sa_expiry_pkts_soft)
440 			td->ipsec_xform.life.packets_soft_limit =
441 					IPSEC_TEST_PACKETS_MAX - 1;
442 
443 		if (flags->ip_csum) {
444 			td->ipsec_xform.options.ip_csum_enable = 1;
445 			test_ipsec_csum_init(&td->input_text.data, true, false);
446 		}
447 
448 		if (flags->l4_csum) {
449 			td->ipsec_xform.options.l4_csum_enable = 1;
450 			test_ipsec_csum_init(&td->input_text.data, false, true);
451 		}
452 
453 		if (flags->transport) {
454 			td->ipsec_xform.mode =
455 					RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT;
456 		} else {
457 			td->ipsec_xform.mode =
458 					RTE_SECURITY_IPSEC_SA_MODE_TUNNEL;
459 
460 			if (flags->tunnel_ipv6)
461 				td->ipsec_xform.tunnel.type =
462 						RTE_SECURITY_IPSEC_TUNNEL_IPV6;
463 			else
464 				td->ipsec_xform.tunnel.type =
465 						RTE_SECURITY_IPSEC_TUNNEL_IPV4;
466 		}
467 
468 		if (flags->stats_success)
469 			td->ipsec_xform.options.stats = 1;
470 
471 		if (flags->fragment) {
472 			struct rte_ipv4_hdr *ip;
473 			ip = (struct rte_ipv4_hdr *)&td->input_text.data;
474 			ip->fragment_offset = 4;
475 			ip->hdr_checksum = rte_ipv4_cksum(ip);
476 		}
477 
478 		if (flags->df == TEST_IPSEC_COPY_DF_INNER_0 ||
479 		    flags->df == TEST_IPSEC_COPY_DF_INNER_1)
480 			td->ipsec_xform.options.copy_df = 1;
481 
482 		if (flags->dscp == TEST_IPSEC_COPY_DSCP_INNER_0 ||
483 		    flags->dscp == TEST_IPSEC_COPY_DSCP_INNER_1)
484 			td->ipsec_xform.options.copy_dscp = 1;
485 
486 		if (flags->dec_ttl_or_hop_limit)
487 			td->ipsec_xform.options.dec_ttl = 1;
488 	}
489 }
490 
491 void
492 test_ipsec_td_update(struct ipsec_test_data td_inb[],
493 		     const struct ipsec_test_data td_outb[],
494 		     int nb_td,
495 		     const struct ipsec_test_flags *flags)
496 {
497 	int i;
498 
499 	for (i = 0; i < nb_td; i++) {
500 		memcpy(td_inb[i].output_text.data, td_outb[i].input_text.data,
501 		       td_outb[i].input_text.len);
502 		td_inb[i].output_text.len = td_outb->input_text.len;
503 
504 		if (flags->icv_corrupt) {
505 			int icv_pos = td_inb[i].input_text.len - 4;
506 			td_inb[i].input_text.data[icv_pos] += 1;
507 		}
508 
509 		if (flags->sa_expiry_pkts_hard)
510 			td_inb[i].ipsec_xform.life.packets_hard_limit =
511 					IPSEC_TEST_PACKETS_MAX - 1;
512 
513 		if (flags->udp_encap)
514 			td_inb[i].ipsec_xform.options.udp_encap = 1;
515 
516 		if (flags->udp_ports_verify)
517 			td_inb[i].ipsec_xform.options.udp_ports_verify = 1;
518 
519 		td_inb[i].ipsec_xform.options.tunnel_hdr_verify =
520 			flags->tunnel_hdr_verify;
521 
522 		if (flags->ip_csum)
523 			td_inb[i].ipsec_xform.options.ip_csum_enable = 1;
524 
525 		if (flags->l4_csum)
526 			td_inb[i].ipsec_xform.options.l4_csum_enable = 1;
527 
528 		/* Clear outbound specific flags */
529 		td_inb[i].ipsec_xform.options.iv_gen_disable = 0;
530 	}
531 }
532 
533 void
534 test_ipsec_display_alg(const struct crypto_param *param1,
535 		       const struct crypto_param *param2)
536 {
537 	if (param1->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
538 		printf("\t%s [%d]",
539 		       rte_crypto_aead_algorithm_strings[param1->alg.aead],
540 		       param1->key_length * 8);
541 	} else if (param1->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
542 		printf("\t%s",
543 		       rte_crypto_auth_algorithm_strings[param1->alg.auth]);
544 		if (param1->alg.auth != RTE_CRYPTO_AUTH_NULL)
545 			printf(" [%dB ICV]", param1->digest_length);
546 	} else {
547 		printf("\t%s",
548 		       rte_crypto_cipher_algorithm_strings[param1->alg.cipher]);
549 		if (param1->alg.cipher != RTE_CRYPTO_CIPHER_NULL)
550 			printf(" [%d]", param1->key_length * 8);
551 		printf(" %s",
552 		       rte_crypto_auth_algorithm_strings[param2->alg.auth]);
553 		if (param2->alg.auth != RTE_CRYPTO_AUTH_NULL)
554 			printf(" [%dB ICV]", param2->digest_length);
555 	}
556 	printf("\n");
557 }
558 
559 static int
560 test_ipsec_tunnel_hdr_len_get(const struct ipsec_test_data *td)
561 {
562 	int len = 0;
563 
564 	if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
565 		if (td->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
566 			if (td->ipsec_xform.tunnel.type ==
567 					RTE_SECURITY_IPSEC_TUNNEL_IPV4)
568 				len += sizeof(struct rte_ipv4_hdr);
569 			else
570 				len += sizeof(struct rte_ipv6_hdr);
571 		}
572 	}
573 
574 	return len;
575 }
576 
577 static int
578 test_ipsec_iv_verify_push(struct rte_mbuf *m, const struct ipsec_test_data *td)
579 {
580 	static uint8_t iv_queue[IV_LEN_MAX * IPSEC_TEST_PACKETS_MAX];
581 	uint8_t *iv_tmp, *output_text = rte_pktmbuf_mtod(m, uint8_t *);
582 	int i, iv_pos, iv_len;
583 	static int index;
584 
585 	if (td->aead)
586 		iv_len = td->xform.aead.aead.iv.length - td->salt.len;
587 	else
588 		iv_len = td->xform.chain.cipher.cipher.iv.length;
589 
590 	iv_pos = test_ipsec_tunnel_hdr_len_get(td) + sizeof(struct rte_esp_hdr);
591 	output_text += iv_pos;
592 
593 	TEST_ASSERT(iv_len <= IV_LEN_MAX, "IV length greater than supported");
594 
595 	/* Compare against previous values */
596 	for (i = 0; i < index; i++) {
597 		iv_tmp = &iv_queue[i * IV_LEN_MAX];
598 
599 		if (memcmp(output_text, iv_tmp, iv_len) == 0) {
600 			printf("IV repeated");
601 			return TEST_FAILED;
602 		}
603 	}
604 
605 	/* Save IV for future comparisons */
606 
607 	iv_tmp = &iv_queue[index * IV_LEN_MAX];
608 	memcpy(iv_tmp, output_text, iv_len);
609 	index++;
610 
611 	if (index == IPSEC_TEST_PACKETS_MAX)
612 		index = 0;
613 
614 	return TEST_SUCCESS;
615 }
616 
617 static int
618 test_ipsec_l3_csum_verify(struct rte_mbuf *m)
619 {
620 	uint16_t actual_cksum, expected_cksum;
621 	struct rte_ipv4_hdr *ip;
622 
623 	ip = rte_pktmbuf_mtod(m, struct rte_ipv4_hdr *);
624 
625 	if (!is_ipv4((void *)ip))
626 		return TEST_SKIPPED;
627 
628 	actual_cksum = ip->hdr_checksum;
629 
630 	ip->hdr_checksum = 0;
631 
632 	expected_cksum = rte_ipv4_cksum(ip);
633 
634 	if (actual_cksum != expected_cksum)
635 		return TEST_FAILED;
636 
637 	return TEST_SUCCESS;
638 }
639 
640 static int
641 test_ipsec_l4_csum_verify(struct rte_mbuf *m)
642 {
643 	uint16_t actual_cksum = 0, expected_cksum = 0;
644 	struct rte_ipv4_hdr *ipv4;
645 	struct rte_ipv6_hdr *ipv6;
646 	struct rte_tcp_hdr *tcp;
647 	struct rte_udp_hdr *udp;
648 	void *ip, *l4;
649 
650 	ip = rte_pktmbuf_mtod(m, void *);
651 
652 	if (is_ipv4(ip)) {
653 		ipv4 = ip;
654 		l4 = RTE_PTR_ADD(ipv4, sizeof(struct rte_ipv4_hdr));
655 
656 		switch (ipv4->next_proto_id) {
657 		case IPPROTO_TCP:
658 			tcp = (struct rte_tcp_hdr *)l4;
659 			actual_cksum = tcp->cksum;
660 			tcp->cksum = 0;
661 			expected_cksum = rte_ipv4_udptcp_cksum(ipv4, l4);
662 			break;
663 		case IPPROTO_UDP:
664 			udp = (struct rte_udp_hdr *)l4;
665 			actual_cksum = udp->dgram_cksum;
666 			udp->dgram_cksum = 0;
667 			expected_cksum = rte_ipv4_udptcp_cksum(ipv4, l4);
668 			break;
669 		default:
670 			break;
671 		}
672 	} else {
673 		ipv6 = ip;
674 		l4 = RTE_PTR_ADD(ipv6, sizeof(struct rte_ipv6_hdr));
675 
676 		switch (ipv6->proto) {
677 		case IPPROTO_TCP:
678 			tcp = (struct rte_tcp_hdr *)l4;
679 			actual_cksum = tcp->cksum;
680 			tcp->cksum = 0;
681 			expected_cksum = rte_ipv6_udptcp_cksum(ipv6, l4);
682 			break;
683 		case IPPROTO_UDP:
684 			udp = (struct rte_udp_hdr *)l4;
685 			actual_cksum = udp->dgram_cksum;
686 			udp->dgram_cksum = 0;
687 			expected_cksum = rte_ipv6_udptcp_cksum(ipv6, l4);
688 			break;
689 		default:
690 			break;
691 		}
692 	}
693 
694 	if (actual_cksum != expected_cksum)
695 		return TEST_FAILED;
696 
697 	return TEST_SUCCESS;
698 }
699 
700 static int
701 test_ipsec_ttl_or_hop_decrement_verify(void *received, void *expected)
702 {
703 	struct rte_ipv4_hdr *iph4_ex, *iph4_re;
704 	struct rte_ipv6_hdr *iph6_ex, *iph6_re;
705 
706 	if (is_ipv4(received) && is_ipv4(expected)) {
707 		iph4_ex = expected;
708 		iph4_re = received;
709 		iph4_ex->time_to_live -= 1;
710 		if (iph4_re->time_to_live != iph4_ex->time_to_live)
711 			return TEST_FAILED;
712 	} else if (!is_ipv4(received) && !is_ipv4(expected)) {
713 		iph6_ex = expected;
714 		iph6_re = received;
715 		iph6_ex->hop_limits -= 1;
716 		if (iph6_re->hop_limits != iph6_ex->hop_limits)
717 			return TEST_FAILED;
718 	} else {
719 		printf("IP header version miss match\n");
720 		return TEST_FAILED;
721 	}
722 
723 	return TEST_SUCCESS;
724 }
725 
726 static int
727 test_ipsec_td_verify(struct rte_mbuf *m, const struct ipsec_test_data *td,
728 		     bool silent, const struct ipsec_test_flags *flags)
729 {
730 	uint8_t *output_text = rte_pktmbuf_mtod(m, uint8_t *);
731 	uint32_t skip, len = rte_pktmbuf_pkt_len(m);
732 	uint8_t td_output_text[4096];
733 	int ret;
734 
735 	/* For tests with status as error for test success, skip verification */
736 	if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS &&
737 	    (flags->icv_corrupt ||
738 	     flags->sa_expiry_pkts_hard ||
739 	     flags->tunnel_hdr_verify ||
740 	     td->ar_packet))
741 		return TEST_SUCCESS;
742 
743 	if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS &&
744 	   flags->udp_encap) {
745 		const struct rte_ipv4_hdr *iph4;
746 		const struct rte_ipv6_hdr *iph6;
747 
748 		if (td->ipsec_xform.tunnel.type ==
749 				RTE_SECURITY_IPSEC_TUNNEL_IPV4) {
750 			iph4 = (const struct rte_ipv4_hdr *)output_text;
751 			if (iph4->next_proto_id != IPPROTO_UDP) {
752 				printf("UDP header is not found\n");
753 				return TEST_FAILED;
754 			}
755 		} else {
756 			iph6 = (const struct rte_ipv6_hdr *)output_text;
757 			if (iph6->proto != IPPROTO_UDP) {
758 				printf("UDP header is not found\n");
759 				return TEST_FAILED;
760 			}
761 		}
762 
763 		len -= sizeof(struct rte_udp_hdr);
764 		output_text += sizeof(struct rte_udp_hdr);
765 	}
766 
767 	if (len != td->output_text.len) {
768 		printf("Output length (%d) not matching with expected (%d)\n",
769 			len, td->output_text.len);
770 		return TEST_FAILED;
771 	}
772 
773 	if ((td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) &&
774 				flags->fragment) {
775 		const struct rte_ipv4_hdr *iph4;
776 		iph4 = (const struct rte_ipv4_hdr *)output_text;
777 		if (iph4->fragment_offset) {
778 			printf("Output packet is fragmented");
779 			return TEST_FAILED;
780 		}
781 	}
782 
783 	skip = test_ipsec_tunnel_hdr_len_get(td);
784 
785 	len -= skip;
786 	output_text += skip;
787 
788 	if ((td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
789 				flags->ip_csum) {
790 		if (m->ol_flags & RTE_MBUF_F_RX_IP_CKSUM_GOOD)
791 			ret = test_ipsec_l3_csum_verify(m);
792 		else
793 			ret = TEST_FAILED;
794 
795 		if (ret == TEST_FAILED)
796 			printf("Inner IP checksum test failed\n");
797 
798 		return ret;
799 	}
800 
801 	if ((td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
802 				flags->l4_csum) {
803 		if (m->ol_flags & RTE_MBUF_F_RX_L4_CKSUM_GOOD)
804 			ret = test_ipsec_l4_csum_verify(m);
805 		else
806 			ret = TEST_FAILED;
807 
808 		if (ret == TEST_FAILED)
809 			printf("Inner L4 checksum test failed\n");
810 
811 		return ret;
812 	}
813 
814 	memcpy(td_output_text, td->output_text.data + skip, len);
815 
816 	if ((td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
817 				flags->dec_ttl_or_hop_limit) {
818 		if (test_ipsec_ttl_or_hop_decrement_verify(output_text, td_output_text)) {
819 			printf("Inner TTL/hop limit decrement test failed\n");
820 			return TEST_FAILED;
821 		}
822 	}
823 
824 	if (test_ipsec_pkt_update(td_output_text, flags)) {
825 		printf("Could not update expected vector");
826 		return TEST_FAILED;
827 	}
828 
829 	if (memcmp(output_text, td_output_text, len)) {
830 		if (silent)
831 			return TEST_FAILED;
832 
833 		printf("TestCase %s line %d: %s\n", __func__, __LINE__,
834 			"output text not as expected\n");
835 
836 		rte_hexdump(stdout, "expected", td_output_text, len);
837 		rte_hexdump(stdout, "actual", output_text, len);
838 		return TEST_FAILED;
839 	}
840 
841 	return TEST_SUCCESS;
842 }
843 
844 static int
845 test_ipsec_res_d_prepare(struct rte_mbuf *m, const struct ipsec_test_data *td,
846 		   struct ipsec_test_data *res_d)
847 {
848 	uint8_t *output_text = rte_pktmbuf_mtod(m, uint8_t *);
849 	uint32_t len = rte_pktmbuf_pkt_len(m);
850 
851 	memcpy(res_d, td, sizeof(*res_d));
852 	memcpy(res_d->input_text.data, output_text, len);
853 	res_d->input_text.len = len;
854 
855 	res_d->ipsec_xform.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
856 	if (res_d->aead) {
857 		res_d->xform.aead.aead.op = RTE_CRYPTO_AEAD_OP_DECRYPT;
858 	} else {
859 		res_d->xform.chain.cipher.cipher.op =
860 				RTE_CRYPTO_CIPHER_OP_DECRYPT;
861 		res_d->xform.chain.auth.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
862 	}
863 
864 	return TEST_SUCCESS;
865 }
866 
867 static int
868 test_ipsec_iph4_hdr_validate(const struct rte_ipv4_hdr *iph4,
869 			     const struct ipsec_test_flags *flags)
870 {
871 	uint8_t tos, dscp;
872 	uint16_t f_off;
873 
874 	if (!is_valid_ipv4_pkt(iph4)) {
875 		printf("Tunnel outer header is not IPv4\n");
876 		return -1;
877 	}
878 
879 	if (flags->ah && iph4->next_proto_id != IPPROTO_AH) {
880 		printf("Tunnel outer header proto is not AH\n");
881 		return -1;
882 	}
883 
884 	f_off = rte_be_to_cpu_16(iph4->fragment_offset);
885 	if (flags->df == TEST_IPSEC_COPY_DF_INNER_1 ||
886 	    flags->df == TEST_IPSEC_SET_DF_1_INNER_0) {
887 		if (!(f_off & RTE_IPV4_HDR_DF_FLAG)) {
888 			printf("DF bit is not set\n");
889 			return -1;
890 		}
891 	} else {
892 		if (f_off & RTE_IPV4_HDR_DF_FLAG) {
893 			printf("DF bit is set\n");
894 			return -1;
895 		}
896 	}
897 
898 	tos = iph4->type_of_service;
899 	dscp = (tos & RTE_IPV4_HDR_DSCP_MASK) >> 2;
900 
901 	if (flags->dscp == TEST_IPSEC_COPY_DSCP_INNER_1 ||
902 	    flags->dscp == TEST_IPSEC_SET_DSCP_1_INNER_0) {
903 		if (dscp != TEST_IPSEC_DSCP_VAL) {
904 			printf("DSCP value is not matching [exp: %x, actual: %x]\n",
905 			       TEST_IPSEC_DSCP_VAL, dscp);
906 			return -1;
907 		}
908 	} else {
909 		if (dscp != 0) {
910 			printf("DSCP value is set [exp: 0, actual: %x]\n",
911 			       dscp);
912 			return -1;
913 		}
914 	}
915 
916 	return 0;
917 }
918 
919 static int
920 test_ipsec_iph6_hdr_validate(const struct rte_ipv6_hdr *iph6,
921 			     const struct ipsec_test_flags *flags)
922 {
923 	uint32_t vtc_flow;
924 	uint8_t dscp;
925 
926 	if (!is_valid_ipv6_pkt(iph6)) {
927 		printf("Tunnel outer header is not IPv6\n");
928 		return -1;
929 	}
930 
931 	vtc_flow = rte_be_to_cpu_32(iph6->vtc_flow);
932 	dscp = (vtc_flow & RTE_IPV6_HDR_DSCP_MASK) >>
933 	       (RTE_IPV6_HDR_TC_SHIFT + 2);
934 
935 	if (flags->dscp == TEST_IPSEC_COPY_DSCP_INNER_1 ||
936 	    flags->dscp == TEST_IPSEC_SET_DSCP_1_INNER_0) {
937 		if (dscp != TEST_IPSEC_DSCP_VAL) {
938 			printf("DSCP value is not matching [exp: %x, actual: %x]\n",
939 			       TEST_IPSEC_DSCP_VAL, dscp);
940 			return -1;
941 		}
942 	} else {
943 		if (dscp != 0) {
944 			printf("DSCP value is set [exp: 0, actual: %x]\n",
945 			       dscp);
946 			return -1;
947 		}
948 	}
949 
950 	return 0;
951 }
952 
953 int
954 test_ipsec_post_process(struct rte_mbuf *m, const struct ipsec_test_data *td,
955 			struct ipsec_test_data *res_d, bool silent,
956 			const struct ipsec_test_flags *flags)
957 {
958 	uint8_t *output_text = rte_pktmbuf_mtod(m, uint8_t *);
959 	int ret;
960 
961 	if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
962 		const struct rte_ipv4_hdr *iph4;
963 		const struct rte_ipv6_hdr *iph6;
964 
965 		if (flags->iv_gen) {
966 			ret = test_ipsec_iv_verify_push(m, td);
967 			if (ret != TEST_SUCCESS)
968 				return ret;
969 		}
970 
971 		iph4 = (const struct rte_ipv4_hdr *)output_text;
972 
973 		if (td->ipsec_xform.mode ==
974 				RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT) {
975 			if (flags->ipv6) {
976 				iph6 = (const struct rte_ipv6_hdr *)output_text;
977 				if (is_valid_ipv6_pkt(iph6) == false) {
978 					printf("Transport packet is not IPv6\n");
979 					return TEST_FAILED;
980 				}
981 			} else {
982 				if (is_valid_ipv4_pkt(iph4) == false) {
983 					printf("Transport packet is not IPv4\n");
984 					return TEST_FAILED;
985 				}
986 
987 				if (flags->ah && iph4->next_proto_id != IPPROTO_AH) {
988 					printf("Transport IPv4 header proto is not AH\n");
989 					return -1;
990 				}
991 			}
992 		} else {
993 			if (td->ipsec_xform.tunnel.type ==
994 					RTE_SECURITY_IPSEC_TUNNEL_IPV4) {
995 				if (test_ipsec_iph4_hdr_validate(iph4, flags))
996 					return TEST_FAILED;
997 			} else {
998 				iph6 = (const struct rte_ipv6_hdr *)output_text;
999 				if (test_ipsec_iph6_hdr_validate(iph6, flags))
1000 					return TEST_FAILED;
1001 			}
1002 		}
1003 	}
1004 
1005 	/*
1006 	 * In case of known vector tests & all inbound tests, res_d provided
1007 	 * would be NULL and output data need to be validated against expected.
1008 	 * For inbound, output_text would be plain packet and for outbound
1009 	 * output_text would IPsec packet. Validate by comparing against
1010 	 * known vectors.
1011 	 *
1012 	 * In case of combined mode tests, the output_text from outbound
1013 	 * operation (ie, IPsec packet) would need to be inbound processed to
1014 	 * obtain the plain text. Copy output_text to result data, 'res_d', so
1015 	 * that inbound processing can be done.
1016 	 */
1017 
1018 	if (res_d == NULL)
1019 		return test_ipsec_td_verify(m, td, silent, flags);
1020 	else
1021 		return test_ipsec_res_d_prepare(m, td, res_d);
1022 }
1023 
1024 int
1025 test_ipsec_status_check(const struct ipsec_test_data *td,
1026 			struct rte_crypto_op *op,
1027 			const struct ipsec_test_flags *flags,
1028 			enum rte_security_ipsec_sa_direction dir,
1029 			int pkt_num)
1030 {
1031 	int ret = TEST_SUCCESS;
1032 
1033 	if ((dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
1034 	    td->ar_packet) {
1035 		if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) {
1036 			printf("Anti replay test case failed\n");
1037 			return TEST_FAILED;
1038 		} else {
1039 			return TEST_SUCCESS;
1040 		}
1041 	}
1042 
1043 	if (dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS &&
1044 	    flags->sa_expiry_pkts_hard &&
1045 	    pkt_num == IPSEC_TEST_PACKETS_MAX) {
1046 		if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) {
1047 			printf("SA hard expiry (pkts) test failed\n");
1048 			return TEST_FAILED;
1049 		} else {
1050 			return TEST_SUCCESS;
1051 		}
1052 	}
1053 
1054 	if ((dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) &&
1055 	    flags->tunnel_hdr_verify) {
1056 		if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) {
1057 			printf("Tunnel header verify test case failed\n");
1058 			return TEST_FAILED;
1059 		} else {
1060 			return TEST_SUCCESS;
1061 		}
1062 	}
1063 
1064 	if (dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS && flags->icv_corrupt) {
1065 		if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) {
1066 			printf("ICV corruption test case failed\n");
1067 			ret = TEST_FAILED;
1068 		}
1069 	} else {
1070 		if (op->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
1071 			printf("Security op processing failed [pkt_num: %d]\n",
1072 			       pkt_num);
1073 			ret = TEST_FAILED;
1074 		}
1075 	}
1076 
1077 	if (flags->sa_expiry_pkts_soft && pkt_num == IPSEC_TEST_PACKETS_MAX) {
1078 		if (!(op->aux_flags &
1079 		      RTE_CRYPTO_OP_AUX_FLAGS_IPSEC_SOFT_EXPIRY)) {
1080 			printf("SA soft expiry (pkts) test failed\n");
1081 			ret = TEST_FAILED;
1082 		}
1083 	}
1084 
1085 	return ret;
1086 }
1087 
1088 int
1089 test_ipsec_stats_verify(struct rte_security_ctx *ctx,
1090 			struct rte_security_session *sess,
1091 			const struct ipsec_test_flags *flags,
1092 			enum rte_security_ipsec_sa_direction dir)
1093 {
1094 	struct rte_security_stats stats = {0};
1095 	int ret = TEST_SUCCESS;
1096 
1097 	if (flags->stats_success) {
1098 		if (rte_security_session_stats_get(ctx, sess, &stats) < 0)
1099 			return TEST_FAILED;
1100 
1101 		if (dir == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) {
1102 			if (stats.ipsec.opackets != 1 ||
1103 			    stats.ipsec.oerrors != 0)
1104 				ret = TEST_FAILED;
1105 		} else {
1106 			if (stats.ipsec.ipackets != 1 ||
1107 			    stats.ipsec.ierrors != 0)
1108 				ret = TEST_FAILED;
1109 		}
1110 	}
1111 
1112 	return ret;
1113 }
1114 
1115 int
1116 test_ipsec_pkt_update(uint8_t *pkt, const struct ipsec_test_flags *flags)
1117 {
1118 	struct rte_ipv4_hdr *iph4;
1119 	struct rte_ipv6_hdr *iph6;
1120 	bool cksum_dirty = false;
1121 
1122 	iph4 = (struct rte_ipv4_hdr *)pkt;
1123 
1124 	if (flags->df == TEST_IPSEC_COPY_DF_INNER_1 ||
1125 	    flags->df == TEST_IPSEC_SET_DF_0_INNER_1 ||
1126 	    flags->df == TEST_IPSEC_COPY_DF_INNER_0 ||
1127 	    flags->df == TEST_IPSEC_SET_DF_1_INNER_0) {
1128 		uint16_t frag_off;
1129 
1130 		if (!is_ipv4(iph4)) {
1131 			printf("Invalid packet type\n");
1132 			return -1;
1133 		}
1134 
1135 		frag_off = rte_be_to_cpu_16(iph4->fragment_offset);
1136 
1137 		if (flags->df == TEST_IPSEC_COPY_DF_INNER_1 ||
1138 		    flags->df == TEST_IPSEC_SET_DF_0_INNER_1)
1139 			frag_off |= RTE_IPV4_HDR_DF_FLAG;
1140 		else
1141 			frag_off &= ~RTE_IPV4_HDR_DF_FLAG;
1142 
1143 		iph4->fragment_offset = rte_cpu_to_be_16(frag_off);
1144 		cksum_dirty = true;
1145 	}
1146 
1147 	if (flags->dscp == TEST_IPSEC_COPY_DSCP_INNER_1 ||
1148 	    flags->dscp == TEST_IPSEC_SET_DSCP_0_INNER_1 ||
1149 	    flags->dscp == TEST_IPSEC_COPY_DSCP_INNER_0 ||
1150 	    flags->dscp == TEST_IPSEC_SET_DSCP_1_INNER_0) {
1151 
1152 		if (is_ipv4(iph4)) {
1153 			uint8_t tos;
1154 
1155 			tos = iph4->type_of_service;
1156 			if (flags->dscp == TEST_IPSEC_COPY_DSCP_INNER_1 ||
1157 			    flags->dscp == TEST_IPSEC_SET_DSCP_0_INNER_1)
1158 				tos |= (RTE_IPV4_HDR_DSCP_MASK &
1159 					(TEST_IPSEC_DSCP_VAL << 2));
1160 			else
1161 				tos &= ~RTE_IPV4_HDR_DSCP_MASK;
1162 
1163 			iph4->type_of_service = tos;
1164 			cksum_dirty = true;
1165 		} else {
1166 			uint32_t vtc_flow;
1167 
1168 			iph6 = (struct rte_ipv6_hdr *)pkt;
1169 
1170 			vtc_flow = rte_be_to_cpu_32(iph6->vtc_flow);
1171 			if (flags->dscp == TEST_IPSEC_COPY_DSCP_INNER_1 ||
1172 			    flags->dscp == TEST_IPSEC_SET_DSCP_0_INNER_1)
1173 				vtc_flow |= (RTE_IPV6_HDR_DSCP_MASK &
1174 					     (TEST_IPSEC_DSCP_VAL << (RTE_IPV6_HDR_TC_SHIFT + 2)));
1175 			else
1176 				vtc_flow &= ~RTE_IPV6_HDR_DSCP_MASK;
1177 
1178 			iph6->vtc_flow = rte_cpu_to_be_32(vtc_flow);
1179 		}
1180 	}
1181 
1182 	if (cksum_dirty && is_ipv4(iph4)) {
1183 		iph4->hdr_checksum = 0;
1184 		iph4->hdr_checksum = rte_ipv4_cksum(iph4);
1185 	}
1186 
1187 	return 0;
1188 }
1189 
1190 #endif /* !RTE_EXEC_ENV_WINDOWS */
1191