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