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