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